@maroonedsoftware/scim 0.1.10 → 0.1.12

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
@@ -1408,6 +1408,7 @@ var ScimGroupRepository = class {
1408
1408
 
1409
1409
  // src/services/scim.user.service.ts
1410
1410
  import { randomUUID } from "crypto";
1411
+ import { DateTime } from "luxon";
1411
1412
  import { Injectable } from "injectkit";
1412
1413
  import { Logger } from "@maroonedsoftware/logger";
1413
1414
  function _ts_decorate(decorators, target, key, desc) {
@@ -1470,7 +1471,7 @@ var ScimUserService = class {
1470
1471
  message: `userName "${payload.userName}" already exists`
1471
1472
  });
1472
1473
  }
1473
- const now = (/* @__PURE__ */ new Date()).toISOString();
1474
+ const now = DateTime.utc().toISO();
1474
1475
  const id = payload.id ?? randomUUID();
1475
1476
  const user = {
1476
1477
  ...payload,
@@ -1517,7 +1518,7 @@ var ScimUserService = class {
1517
1518
  });
1518
1519
  }
1519
1520
  }
1520
- const now = (/* @__PURE__ */ new Date()).toISOString();
1521
+ const now = DateTime.utc().toISO();
1521
1522
  const user = {
1522
1523
  ...payload,
1523
1524
  id,
@@ -1548,7 +1549,7 @@ var ScimUserService = class {
1548
1549
  patched.id = existing.id;
1549
1550
  patched.meta = {
1550
1551
  ...existing.meta,
1551
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
1552
+ lastModified: DateTime.utc().toISO()
1552
1553
  };
1553
1554
  return this.repository.replace(id, patched);
1554
1555
  }
@@ -1584,6 +1585,7 @@ ScimUserService = _ts_decorate([
1584
1585
 
1585
1586
  // src/services/scim.group.service.ts
1586
1587
  import { randomUUID as randomUUID2 } from "crypto";
1588
+ import { DateTime as DateTime2 } from "luxon";
1587
1589
  import { Injectable as Injectable2 } from "injectkit";
1588
1590
  import { Logger as Logger2 } from "@maroonedsoftware/logger";
1589
1591
  function _ts_decorate2(decorators, target, key, desc) {
@@ -1645,7 +1647,7 @@ var ScimGroupService = class {
1645
1647
  message: `displayName "${payload.displayName}" already exists`
1646
1648
  });
1647
1649
  }
1648
- const now = (/* @__PURE__ */ new Date()).toISOString();
1650
+ const now = DateTime2.utc().toISO();
1649
1651
  const id = payload.id ?? randomUUID2();
1650
1652
  const group = {
1651
1653
  ...payload,
@@ -1691,7 +1693,7 @@ var ScimGroupService = class {
1691
1693
  });
1692
1694
  }
1693
1695
  }
1694
- const now = (/* @__PURE__ */ new Date()).toISOString();
1696
+ const now = DateTime2.utc().toISO();
1695
1697
  const group = {
1696
1698
  ...payload,
1697
1699
  id,
@@ -1721,7 +1723,7 @@ var ScimGroupService = class {
1721
1723
  patched.id = existing.id;
1722
1724
  patched.meta = {
1723
1725
  ...existing.meta,
1724
- lastModified: (/* @__PURE__ */ new Date()).toISOString()
1726
+ lastModified: DateTime2.utc().toISO()
1725
1727
  };
1726
1728
  return this.repository.replace(id, patched);
1727
1729
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types/list.response.ts","../src/types/patch.op.ts","../src/schemas/user.schema.ts","../src/schemas/group.schema.ts","../src/schemas/enterprise.user.schema.ts","../src/schemas/resource.type.schema.ts","../src/schemas/service.provider.config.schema.ts","../src/schemas/index.ts","../src/errors/scim.error.ts","../src/filter/filter.tokenizer.ts","../src/filter/filter.parser.ts","../src/patch/patch.applier.ts","../src/repositories/scim.user.repository.ts","../src/repositories/scim.group.repository.ts","../src/services/scim.user.service.ts","../src/services/scim.group.service.ts","../src/services/scim.service.provider.service.ts","../src/middleware/scim.content.type.middleware.ts","../src/middleware/scim.error.middleware.ts","../src/middleware/require.scim.scope.middleware.ts","../src/router/scim.router.ts"],"sourcesContent":["/**\n * Schema URI for the SCIM ListResponse message (RFC 7644 §3.4.2).\n */\nexport const ListResponseSchema = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n/**\n * SCIM ListResponse envelope returned from list/search endpoints.\n */\nexport interface ScimListResponse<TResource> {\n schemas: [typeof ListResponseSchema];\n totalResults: number;\n startIndex?: number;\n itemsPerPage?: number;\n Resources?: TResource[];\n}\n","/**\n * Schema URI for the SCIM PatchOp message (RFC 7644 §3.5.2).\n */\nexport const PatchOpSchema = 'urn:ietf:params:scim:api:messages:2.0:PatchOp';\n\n/**\n * Operation kinds permitted in a SCIM PATCH request.\n * Case-insensitive on the wire; normalised internally.\n */\nexport type ScimPatchOpKind = 'add' | 'replace' | 'remove';\n\n/**\n * A single PATCH operation as it appears in a PatchOp request body.\n */\nexport interface ScimPatchOp {\n op: ScimPatchOpKind | Uppercase<ScimPatchOpKind> | Capitalize<ScimPatchOpKind>;\n path?: string;\n value?: unknown;\n}\n\n/**\n * The full PatchOp request envelope.\n */\nexport interface ScimPatchRequest {\n schemas: [typeof PatchOpSchema];\n Operations: ScimPatchOp[];\n}\n","import type { ScimAttributeDefinition, ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM core User resource. */\nexport const UserSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:User';\n\n/**\n * RFC 7643 §4.1: SCIM core User schema definition. A condensed but\n * spec-compliant subset suitable for `/Schemas` discovery.\n */\nexport const userSchema: ScimSchema = {\n id: UserSchemaId,\n name: 'User',\n description: 'User Account',\n meta: { resourceType: 'Schema', location: `/Schemas/${UserSchemaId}` },\n attributes: [\n {\n name: 'userName',\n type: 'string',\n multiValued: false,\n description: 'Unique identifier for the User, typically used by the user to directly authenticate.',\n required: true,\n caseExact: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'server',\n },\n {\n name: 'name',\n type: 'complex',\n multiValued: false,\n description: 'The components of the user\\'s real name.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'formatted', type: 'string', multiValued: false, description: 'Full name formatted for display.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'familyName', type: 'string', multiValued: false, description: 'Family name (last name).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'givenName', type: 'string', multiValued: false, description: 'Given name (first name).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'middleName', type: 'string', multiValued: false, description: 'Middle name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'honorificPrefix', type: 'string', multiValued: false, description: 'Honorific prefix (e.g., Ms., Dr.).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'honorificSuffix', type: 'string', multiValued: false, description: 'Honorific suffix (e.g., Jr., III).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n ],\n },\n { name: 'displayName', type: 'string', multiValued: false, description: 'Name displayed to end-users.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'nickName', type: 'string', multiValued: false, description: 'Casual name of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'profileUrl', type: 'reference', multiValued: false, description: 'URL of the User\\'s online profile.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none', referenceTypes: ['external'] },\n { name: 'title', type: 'string', multiValued: false, description: 'Title of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'userType', type: 'string', multiValued: false, description: 'Used to identify the relationship between the organization and the user.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'preferredLanguage', type: 'string', multiValued: false, description: 'Preferred language as per RFC 7231.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'locale', type: 'string', multiValued: false, description: 'Default location of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'timezone', type: 'string', multiValued: false, description: 'Time zone in IANA format.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'active', type: 'boolean', multiValued: false, description: 'Whether the user is active.', required: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'password', type: 'string', multiValued: false, description: 'Cleartext password (write-only).', required: false, caseExact: false, mutability: 'writeOnly', returned: 'never', uniqueness: 'none' },\n {\n name: 'emails',\n type: 'complex',\n multiValued: true,\n description: 'Email addresses for the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: multiValuedSubAttrs('email'),\n },\n {\n name: 'phoneNumbers',\n type: 'complex',\n multiValued: true,\n description: 'Phone numbers for the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: multiValuedSubAttrs('phone'),\n },\n {\n name: 'groups',\n type: 'complex',\n multiValued: true,\n description: 'Groups the user is a member of (read-only).',\n required: false,\n mutability: 'readOnly',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Identifier of the Group.', required: false, caseExact: true, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the Group resource.', required: false, caseExact: true, mutability: 'readOnly', returned: 'default', uniqueness: 'none', referenceTypes: ['Group'] },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable Group name.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: 'Membership type.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none', canonicalValues: ['direct', 'indirect'] },\n ],\n },\n ],\n};\n\nfunction multiValuedSubAttrs(kind: string): ScimAttributeDefinition[] {\n return [\n { name: 'value', type: 'string', multiValued: false, description: `${kind} value.`, required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable display value.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: `Function of the ${kind} (e.g., work, home).`, required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'primary', type: 'boolean', multiValued: false, description: 'Whether this is the primary value.', required: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n ];\n}\n","import type { ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM core Group resource. */\nexport const GroupSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n/**\n * RFC 7643 §4.2: SCIM core Group schema definition.\n */\nexport const groupSchema: ScimSchema = {\n id: GroupSchemaId,\n name: 'Group',\n description: 'Group',\n meta: { resourceType: 'Schema', location: `/Schemas/${GroupSchemaId}` },\n attributes: [\n {\n name: 'displayName',\n type: 'string',\n multiValued: false,\n description: 'Human-readable name for the Group.',\n required: true,\n caseExact: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n },\n {\n name: 'members',\n type: 'complex',\n multiValued: true,\n description: 'List of Group members.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Identifier of the member.', required: false, caseExact: true, mutability: 'immutable', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the member resource.', required: false, caseExact: true, mutability: 'immutable', returned: 'default', uniqueness: 'none', referenceTypes: ['User', 'Group'] },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable name of the member.', required: false, caseExact: false, mutability: 'immutable', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: 'Member type.', required: false, caseExact: false, mutability: 'immutable', returned: 'default', uniqueness: 'none', canonicalValues: ['User', 'Group'] },\n ],\n },\n ],\n};\n","import type { ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM EnterpriseUser extension. */\nexport const EnterpriseUserSchemaId = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n\n/**\n * RFC 7643 §4.3: EnterpriseUser extension schema definition.\n */\nexport const enterpriseUserSchema: ScimSchema = {\n id: EnterpriseUserSchemaId,\n name: 'EnterpriseUser',\n description: 'Enterprise User extension',\n meta: { resourceType: 'Schema', location: `/Schemas/${EnterpriseUserSchemaId}` },\n attributes: [\n { name: 'employeeNumber', type: 'string', multiValued: false, description: 'Employee number.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'costCenter', type: 'string', multiValued: false, description: 'Cost center.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'organization', type: 'string', multiValued: false, description: 'Organization name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'division', type: 'string', multiValued: false, description: 'Division name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'department', type: 'string', multiValued: false, description: 'Department name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n {\n name: 'manager',\n type: 'complex',\n multiValued: false,\n description: 'The manager of the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Manager user id.', required: false, caseExact: true, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the manager User resource.', required: false, caseExact: true, mutability: 'readWrite', returned: 'default', uniqueness: 'none', referenceTypes: ['User'] },\n { name: 'displayName', type: 'string', multiValued: false, description: 'Manager display name.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n ],\n },\n ],\n};\n","import { UserSchemaId } from './user.schema.js';\nimport { GroupSchemaId } from './group.schema.js';\nimport { EnterpriseUserSchemaId } from './enterprise.user.schema.js';\n\n/** Schema URI for the SCIM ResourceType resource. */\nexport const ResourceTypeSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:ResourceType';\n\nexport interface ScimResourceType {\n schemas: [typeof ResourceTypeSchemaId];\n id: string;\n name: string;\n endpoint: string;\n description: string;\n schema: string;\n schemaExtensions?: Array<{ schema: string; required: boolean }>;\n meta: {\n resourceType: 'ResourceType';\n location?: string;\n };\n}\n\nexport const userResourceType: ScimResourceType = {\n schemas: [ResourceTypeSchemaId],\n id: 'User',\n name: 'User',\n endpoint: '/Users',\n description: 'User Account',\n schema: UserSchemaId,\n schemaExtensions: [{ schema: EnterpriseUserSchemaId, required: false }],\n meta: { resourceType: 'ResourceType', location: '/ResourceTypes/User' },\n};\n\nexport const groupResourceType: ScimResourceType = {\n schemas: [ResourceTypeSchemaId],\n id: 'Group',\n name: 'Group',\n endpoint: '/Groups',\n description: 'Group',\n schema: GroupSchemaId,\n meta: { resourceType: 'ResourceType', location: '/ResourceTypes/Group' },\n};\n","/** Schema URI for the SCIM ServiceProviderConfig resource. */\nexport const ServiceProviderConfigSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig';\n\n/** Authentication scheme advertised by `/ServiceProviderConfig`. */\nexport interface ScimAuthenticationScheme {\n type: 'oauth' | 'oauth2' | 'oauthbearertoken' | 'httpbasic' | 'httpdigest';\n name: string;\n description: string;\n specUri?: string;\n documentationUri?: string;\n primary?: boolean;\n}\n\n/** Optional features the service provider supports (RFC 7643 §5). */\nexport interface ScimServiceProviderConfigOptions {\n documentationUri?: string;\n patch?: { supported: boolean };\n bulk?: { supported: boolean; maxOperations: number; maxPayloadSize: number };\n filter?: { supported: boolean; maxResults: number };\n changePassword?: { supported: boolean };\n sort?: { supported: boolean };\n etag?: { supported: boolean };\n authenticationSchemes?: ScimAuthenticationScheme[];\n}\n\n/** Materialised ServiceProviderConfig response. */\nexport interface ScimServiceProviderConfig extends Required<Omit<ScimServiceProviderConfigOptions, 'documentationUri' | 'authenticationSchemes'>> {\n schemas: [typeof ServiceProviderConfigSchemaId];\n documentationUri?: string;\n authenticationSchemes: ScimAuthenticationScheme[];\n meta: {\n resourceType: 'ServiceProviderConfig';\n location?: string;\n };\n}\n\nconst defaultBearer: ScimAuthenticationScheme = {\n type: 'oauthbearertoken',\n name: 'OAuth Bearer Token',\n description: 'Authentication scheme using the OAuth Bearer Token Standard.',\n specUri: 'https://www.rfc-editor.org/info/rfc6750',\n primary: true,\n};\n\n/**\n * Build a SCIM ServiceProviderConfig response object, layering caller options\n * over the toolkit's defaults (PATCH on, filter on, sort on; bulk/changePassword/etag off).\n */\nexport const buildServiceProviderConfig = (options: ScimServiceProviderConfigOptions = {}): ScimServiceProviderConfig => ({\n schemas: [ServiceProviderConfigSchemaId],\n documentationUri: options.documentationUri,\n patch: options.patch ?? { supported: true },\n bulk: options.bulk ?? { supported: false, maxOperations: 0, maxPayloadSize: 0 },\n filter: options.filter ?? { supported: true, maxResults: 200 },\n changePassword: options.changePassword ?? { supported: false },\n sort: options.sort ?? { supported: true },\n etag: options.etag ?? { supported: false },\n authenticationSchemes: options.authenticationSchemes ?? [defaultBearer],\n meta: { resourceType: 'ServiceProviderConfig', location: '/ServiceProviderConfig' },\n});\n","export * from './schema.types.js';\nexport * from './user.schema.js';\nexport * from './group.schema.js';\nexport * from './enterprise.user.schema.js';\nexport * from './resource.type.schema.js';\nexport * from './service.provider.config.schema.js';\n\nimport { userSchema } from './user.schema.js';\nimport { groupSchema } from './group.schema.js';\nimport { enterpriseUserSchema } from './enterprise.user.schema.js';\n\n/** All SCIM core + extension schemas this package ships. */\nexport const coreSchemas = [userSchema, groupSchema, enterpriseUserSchema];\n","import { HttpError, HttpStatusCodes, type HttpStatusMessage } from '@maroonedsoftware/errors';\n\n/** Schema URI for the SCIM Error message. */\nexport const ScimErrorSchema = 'urn:ietf:params:scim:api:messages:2.0:Error';\n\n/**\n * `scimType` values defined by RFC 7644 §3.12 plus the few extensions clients\n * commonly emit. Keep this open as `string` to allow vendor-specific values.\n */\nexport type ScimErrorType =\n | 'invalidFilter'\n | 'tooMany'\n | 'uniqueness'\n | 'mutability'\n | 'invalidSyntax'\n | 'invalidPath'\n | 'noTarget'\n | 'invalidValue'\n | 'invalidVers'\n | 'sensitive'\n | 'insufficientScope'\n | (string & {});\n\n/**\n * SCIM error envelope (RFC 7644 §3.12). The HTTP status comes from\n * the underlying {@link HttpError}; the JSON body matches:\n *\n * ```json\n * { \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:Error\"], \"status\": \"404\", \"scimType\": \"invalidPath\", \"detail\": \"...\" }\n * ```\n */\nexport class ScimError extends HttpError {\n /** SCIM-specific error subtype, see RFC 7644 §3.12. */\n readonly scimType?: ScimErrorType;\n\n constructor(statusCode: HttpStatusCodes, scimType?: ScimErrorType, message?: HttpStatusMessage<HttpStatusCodes>) {\n super(statusCode, message);\n this.scimType = scimType;\n Object.setPrototypeOf(this, ScimError.prototype);\n }\n\n /** Build the SCIM error JSON body for this error. */\n toScimBody(): { schemas: [typeof ScimErrorSchema]; status: string; scimType?: ScimErrorType; detail?: string } {\n return {\n schemas: [ScimErrorSchema],\n status: String(this.statusCode),\n ...(this.scimType ? { scimType: this.scimType } : {}),\n detail: this.message,\n };\n }\n}\n\n/** Type guard for {@link ScimError}. */\nexport const IsScimError = (error: unknown): error is ScimError => error instanceof ScimError;\n\n/**\n * Factory for building a SCIM-shaped HTTP error. The returned object behaves like\n * an {@link HttpError}, so chained `.withDetails()` / `.withCause()` /\n * `.withInternalDetails()` work as usual.\n *\n * @example\n * ```ts\n * throw scimError(400, 'invalidFilter', 'Bad Request');\n * ```\n */\nexport const scimError = <Status extends HttpStatusCodes>(\n statusCode: Status,\n scimType?: ScimErrorType,\n message?: HttpStatusMessage<Status>,\n): ScimError => new ScimError(statusCode, scimType, message);\n","import { scimError } from '../errors/scim.error.js';\n\nexport type ScimTokenKind =\n | 'identifier' // attribute path, including dots, colons, dashes, and URN segments\n | 'string'\n | 'number'\n | 'true'\n | 'false'\n | 'null'\n | 'and'\n | 'or'\n | 'not'\n | 'lparen'\n | 'rparen'\n | 'lbracket'\n | 'rbracket'\n | 'op'; // eq, ne, co, sw, ew, gt, ge, lt, le, pr\n\nexport interface ScimToken {\n kind: ScimTokenKind;\n /** For `identifier`/`string`/`op`: the textual value. For `number`: numeric. */\n value: string | number | boolean | null;\n /** Source position where the token starts. */\n start: number;\n}\n\nconst COMPARISON_OPS = new Set(['eq', 'ne', 'co', 'sw', 'ew', 'gt', 'ge', 'lt', 'le', 'pr']);\n\n/**\n * Tokenize a SCIM filter expression into a stream of {@link ScimToken}s.\n * Throws a `400 invalidFilter` SCIM error on malformed input.\n */\nexport const tokenizeScimFilter = (input: string): ScimToken[] => {\n const tokens: ScimToken[] = [];\n let i = 0;\n\n while (i < input.length) {\n const ch = input[i]!;\n\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n i += 1;\n continue;\n }\n\n if (ch === '(') {\n tokens.push({ kind: 'lparen', value: '(', start: i });\n i += 1;\n continue;\n }\n if (ch === ')') {\n tokens.push({ kind: 'rparen', value: ')', start: i });\n i += 1;\n continue;\n }\n if (ch === '[') {\n tokens.push({ kind: 'lbracket', value: '[', start: i });\n i += 1;\n continue;\n }\n if (ch === ']') {\n tokens.push({ kind: 'rbracket', value: ']', start: i });\n i += 1;\n continue;\n }\n\n if (ch === '\"') {\n const start = i;\n i += 1;\n let value = '';\n while (i < input.length && input[i] !== '\"') {\n if (input[i] === '\\\\' && i + 1 < input.length) {\n const next = input[i + 1]!;\n if (next === '\"' || next === '\\\\' || next === '/') {\n value += next;\n i += 2;\n continue;\n }\n if (next === 'n') { value += '\\n'; i += 2; continue; }\n if (next === 't') { value += '\\t'; i += 2; continue; }\n if (next === 'r') { value += '\\r'; i += 2; continue; }\n if (next === 'b') { value += '\\b'; i += 2; continue; }\n if (next === 'f') { value += '\\f'; i += 2; continue; }\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: i, message: `Unsupported escape sequence \\\\${next}` });\n }\n value += input[i];\n i += 1;\n }\n if (i >= input.length) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: start, message: 'Unterminated string literal' });\n }\n i += 1; // consume closing quote\n tokens.push({ kind: 'string', value, start });\n continue;\n }\n\n if (ch === '-' || (ch >= '0' && ch <= '9')) {\n const start = i;\n let raw = '';\n if (ch === '-') {\n raw += ch;\n i += 1;\n }\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n if (input[i] === '.') {\n raw += '.';\n i += 1;\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n }\n if (input[i] === 'e' || input[i] === 'E') {\n raw += input[i];\n i += 1;\n if (input[i] === '+' || input[i] === '-') {\n raw += input[i];\n i += 1;\n }\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n }\n const num = Number(raw);\n if (Number.isNaN(num)) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: start, message: `Invalid numeric literal \"${raw}\"` });\n }\n tokens.push({ kind: 'number', value: num, start });\n continue;\n }\n\n if (isIdentifierStart(ch)) {\n const start = i;\n let raw = '';\n while (i < input.length && isIdentifierPart(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n const lower = raw.toLowerCase();\n switch (lower) {\n case 'true':\n tokens.push({ kind: 'true', value: true, start });\n continue;\n case 'false':\n tokens.push({ kind: 'false', value: false, start });\n continue;\n case 'null':\n tokens.push({ kind: 'null', value: null, start });\n continue;\n case 'and':\n case 'or':\n case 'not':\n tokens.push({ kind: lower, value: lower, start });\n continue;\n }\n if (COMPARISON_OPS.has(lower)) {\n tokens.push({ kind: 'op', value: lower, start });\n continue;\n }\n tokens.push({ kind: 'identifier', value: raw, start });\n continue;\n }\n\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: i, message: `Unexpected character \"${ch}\"` });\n }\n\n return tokens;\n};\n\nconst isIdentifierStart = (ch: string): boolean => /[A-Za-z_$]/.test(ch);\n\nconst isIdentifierPart = (ch: string): boolean => /[A-Za-z0-9_.\\-:$]/.test(ch);\n","import { scimError } from '../errors/scim.error.js';\nimport type { ScimFilterNode, ScimComparisonOperator } from './filter.ast.js';\nimport { tokenizeScimFilter, type ScimToken } from './filter.tokenizer.js';\n\n/**\n * Parse a SCIM filter expression (RFC 7644 §3.4.2.2) into a typed AST.\n * Throws a `400 invalidFilter` SCIM error on malformed input.\n *\n * Operator precedence (highest first):\n * 1. parentheses, value-path brackets, `not(...)`\n * 2. comparison\n * 3. `and`\n * 4. `or`\n */\nexport const parseScimFilter = (input: string): ScimFilterNode => {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ message: 'Filter is empty' });\n }\n const tokens = tokenizeScimFilter(trimmed);\n const parser = new Parser(tokens);\n const node = parser.parseOr();\n parser.expectEnd();\n return node;\n};\n\nclass Parser {\n private pos = 0;\n\n constructor(private readonly tokens: ScimToken[]) {}\n\n parseOr(): ScimFilterNode {\n let left = this.parseAnd();\n while (this.peek()?.kind === 'or') {\n this.consume();\n const right = this.parseAnd();\n left = { kind: 'logical', operator: 'or', left, right };\n }\n return left;\n }\n\n parseAnd(): ScimFilterNode {\n let left = this.parseUnary();\n while (this.peek()?.kind === 'and') {\n this.consume();\n const right = this.parseUnary();\n left = { kind: 'logical', operator: 'and', left, right };\n }\n return left;\n }\n\n parseUnary(): ScimFilterNode {\n const token = this.peek();\n if (token?.kind === 'not') {\n this.consume();\n this.expect('lparen', 'Expected \"(\" after \"not\"');\n const inner = this.parseOr();\n this.expect('rparen', 'Expected \")\" to close \"not(...)\"');\n return { kind: 'not', filter: inner };\n }\n if (token?.kind === 'lparen') {\n this.consume();\n const inner = this.parseOr();\n this.expect('rparen', 'Expected \")\"');\n return inner;\n }\n return this.parseComparisonOrValuePath();\n }\n\n parseComparisonOrValuePath(): ScimFilterNode {\n const token = this.peek();\n if (!token || token.kind !== 'identifier') {\n throw this.error(token, 'Expected attribute path');\n }\n this.consume();\n const attribute = String(token.value);\n\n const next = this.peek();\n if (next?.kind === 'lbracket') {\n this.consume();\n const inner = this.parseOr();\n this.expect('rbracket', 'Expected \"]\" to close value-path filter');\n return { kind: 'valuePath', attribute, filter: inner };\n }\n\n if (!next || next.kind !== 'op') {\n throw this.error(next, 'Expected comparison operator');\n }\n this.consume();\n const operator = String(next.value) as ScimComparisonOperator;\n\n if (operator === 'pr') {\n return { kind: 'comparison', attribute, operator };\n }\n\n const valueToken = this.peek();\n if (!valueToken) {\n throw this.error(valueToken, `Expected value after operator \"${operator}\"`);\n }\n this.consume();\n\n if (valueToken.kind === 'string' || valueToken.kind === 'number' || valueToken.kind === 'true' || valueToken.kind === 'false' || valueToken.kind === 'null') {\n return { kind: 'comparison', attribute, operator, value: valueToken.value as string | number | boolean | null };\n }\n throw this.error(valueToken, `Expected literal value after operator \"${operator}\"`);\n }\n\n expectEnd(): void {\n const remaining = this.peek();\n if (remaining) {\n throw this.error(remaining, 'Unexpected trailing tokens');\n }\n }\n\n private peek(): ScimToken | undefined {\n return this.tokens[this.pos];\n }\n\n private consume(): ScimToken | undefined {\n const token = this.tokens[this.pos];\n this.pos += 1;\n return token;\n }\n\n private expect(kind: ScimToken['kind'], message: string): ScimToken {\n const token = this.peek();\n if (!token || token.kind !== kind) {\n throw this.error(token, message);\n }\n this.consume();\n return token;\n }\n\n private error(token: ScimToken | undefined, message: string) {\n return scimError(400, 'invalidFilter', 'Bad Request').withDetails({\n message,\n position: token?.start ?? -1,\n });\n }\n}\n","import { scimError } from '../errors/scim.error.js';\nimport { parseScimFilter } from '../filter/filter.parser.js';\nimport type { ScimFilterNode } from '../filter/filter.ast.js';\nimport type { ScimPatchOp, ScimPatchOpKind } from '../types/patch.op.js';\n\n/**\n * Apply a SCIM PATCH operation list to a resource (RFC 7644 §3.5.2).\n * Returns a *new* object — the input is not mutated.\n *\n * Supports the standard `add` / `replace` / `remove` operations and the path\n * mini-language including dotted sub-attributes and value-path filters\n * (e.g. `emails[type eq \"work\"].value`).\n */\nexport const applyScimPatch = <T extends Record<string, unknown>>(resource: T, ops: ScimPatchOp[]): T => {\n // Deep-clone so mutations don't leak to the caller.\n let next: Record<string, unknown> = structuredClone(resource);\n for (const op of ops) {\n next = applyOne(next, op);\n }\n return next as T;\n};\n\nconst applyOne = (resource: Record<string, unknown>, op: ScimPatchOp): Record<string, unknown> => {\n const kind = normaliseOpKind(op.op);\n\n if (op.path === undefined || op.path === '') {\n if (kind === 'remove') {\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: '\"remove\" requires a path' });\n }\n if (typeof op.value !== 'object' || op.value === null || Array.isArray(op.value)) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: 'Pathless add/replace requires an object value' });\n }\n return mergeObject(resource, op.value as Record<string, unknown>, kind);\n }\n\n const path = parsePatchPath(op.path);\n return applyAtPath(resource, path, kind, op.value);\n};\n\nconst normaliseOpKind = (op: ScimPatchOp['op']): ScimPatchOpKind => {\n const lower = String(op).toLowerCase();\n if (lower === 'add' || lower === 'replace' || lower === 'remove') return lower;\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: `Unknown PATCH op \"${op}\"` });\n};\n\ninterface ParsedPath {\n /** Top-level attribute, possibly with sub-attribute segments. */\n segments: string[];\n /** Optional value-path filter applied to the leaf attribute. */\n filter?: ScimFilterNode;\n /** Sub-attribute applied after the value-path filter (e.g. `.value`). */\n filterSubAttr?: string;\n}\n\nconst parsePatchPath = (raw: string): ParsedPath => {\n // Split off optional `[...]filter` segment.\n const bracketStart = raw.indexOf('[');\n if (bracketStart === -1) {\n return { segments: raw.split('.').filter(Boolean) };\n }\n\n const bracketEnd = findMatchingBracket(raw, bracketStart);\n if (bracketEnd === -1) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Unterminated value-path filter' });\n }\n\n const head = raw.slice(0, bracketStart);\n const filterSrc = raw.slice(bracketStart + 1, bracketEnd);\n const tail = raw.slice(bracketEnd + 1);\n\n const segments = head.split('.').filter(Boolean);\n if (segments.length === 0) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Value-path filter requires a target attribute' });\n }\n\n const filter = parseScimFilter(filterSrc);\n\n let filterSubAttr: string | undefined;\n if (tail.length > 0) {\n if (!tail.startsWith('.')) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Expected \".\" after value-path filter' });\n }\n filterSubAttr = tail.slice(1);\n if (filterSubAttr.length === 0 || filterSubAttr.includes('[')) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Invalid sub-attribute after value-path filter' });\n }\n }\n\n return { segments, filter, filterSubAttr };\n};\n\nconst findMatchingBracket = (input: string, openIndex: number): number => {\n let depth = 0;\n let inString = false;\n for (let i = openIndex; i < input.length; i += 1) {\n const ch = input[i]!;\n if (inString) {\n if (ch === '\\\\') { i += 1; continue; }\n if (ch === '\"') inString = false;\n continue;\n }\n if (ch === '\"') { inString = true; continue; }\n if (ch === '[') depth += 1;\n else if (ch === ']') {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n};\n\nconst applyAtPath = (resource: Record<string, unknown>, path: ParsedPath, kind: ScimPatchOpKind, value: unknown): Record<string, unknown> => {\n const [head, ...rest] = path.segments;\n if (!head) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Empty PATCH path' });\n }\n\n if (path.filter && rest.length === 0) {\n return applyFilteredOp(resource, head, path.filter, path.filterSubAttr, kind, value);\n }\n\n if (rest.length === 0) {\n return applySimpleOp(resource, head, kind, value);\n }\n\n const child = resource[head];\n const childObj: Record<string, unknown> = isPlainObject(child) ? { ...child } : {};\n const updated = applyAtPath(childObj, { ...path, segments: rest }, kind, value);\n return { ...resource, [head]: updated };\n};\n\nconst applySimpleOp = (resource: Record<string, unknown>, attr: string, kind: ScimPatchOpKind, value: unknown): Record<string, unknown> => {\n if (kind === 'remove') {\n const next = { ...resource };\n delete next[attr];\n return next;\n }\n\n if (kind === 'replace') {\n return { ...resource, [attr]: value };\n }\n\n // add: for multi-valued attributes, append; otherwise replace.\n const existing = resource[attr];\n if (Array.isArray(existing) && Array.isArray(value)) {\n return { ...resource, [attr]: [...existing, ...value] };\n }\n if (Array.isArray(existing) && value !== undefined) {\n return { ...resource, [attr]: [...existing, value] };\n }\n if (existing === undefined && Array.isArray(value)) {\n return { ...resource, [attr]: [...value] };\n }\n if (isPlainObject(existing) && isPlainObject(value)) {\n return { ...resource, [attr]: { ...existing, ...value } };\n }\n return { ...resource, [attr]: value };\n};\n\nconst applyFilteredOp = (\n resource: Record<string, unknown>,\n attr: string,\n filter: ScimFilterNode,\n subAttr: string | undefined,\n kind: ScimPatchOpKind,\n value: unknown,\n): Record<string, unknown> => {\n const collection = resource[attr];\n if (!Array.isArray(collection)) {\n if (kind === 'add') {\n // Per RFC, add on a non-existent target creates it. For value-path on a\n // missing collection, the closest behaviour is to materialise the matched\n // item from the supplied value.\n return { ...resource, [attr]: [{ ...(value as Record<string, unknown>) }] };\n }\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: `Attribute \"${attr}\" is not multi-valued` });\n }\n\n const matched: number[] = [];\n collection.forEach((item, index) => {\n if (isPlainObject(item) && evaluateFilter(item, filter)) matched.push(index);\n });\n\n if (matched.length === 0 && kind !== 'add') {\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: `No items matched value-path filter on \"${attr}\"` });\n }\n\n if (kind === 'remove') {\n const next = collection.filter((_, idx) => !matched.includes(idx));\n return { ...resource, [attr]: next };\n }\n\n if (kind === 'add' && matched.length === 0) {\n const seed = isPlainObject(value) ? { ...value } : { value };\n return { ...resource, [attr]: [...collection, seed] };\n }\n\n const next = collection.map((item, idx) => {\n if (!matched.includes(idx) || !isPlainObject(item)) return item;\n if (subAttr !== undefined) {\n if (kind === 'replace' || kind === 'add') {\n return { ...item, [subAttr]: value };\n }\n }\n if (kind === 'replace') {\n return isPlainObject(value) ? { ...item, ...value } : value;\n }\n // add: shallow merge\n return isPlainObject(value) ? { ...item, ...value } : item;\n });\n return { ...resource, [attr]: next };\n};\n\nconst mergeObject = (target: Record<string, unknown>, source: Record<string, unknown>, kind: ScimPatchOpKind): Record<string, unknown> => {\n if (kind === 'replace') {\n return { ...target, ...source };\n }\n // add: deep-merge for nested objects, append for arrays\n const out: Record<string, unknown> = { ...target };\n for (const [key, val] of Object.entries(source)) {\n const existing = out[key];\n if (Array.isArray(existing) && Array.isArray(val)) {\n out[key] = [...existing, ...val];\n } else if (isPlainObject(existing) && isPlainObject(val)) {\n out[key] = mergeObject(existing, val, kind);\n } else {\n out[key] = val;\n }\n }\n return out;\n};\n\nconst evaluateFilter = (item: Record<string, unknown>, filter: ScimFilterNode): boolean => {\n switch (filter.kind) {\n case 'comparison':\n return evaluateComparison(item, filter.attribute, filter.operator, filter.value);\n case 'logical':\n return filter.operator === 'and'\n ? evaluateFilter(item, filter.left) && evaluateFilter(item, filter.right)\n : evaluateFilter(item, filter.left) || evaluateFilter(item, filter.right);\n case 'not':\n return !evaluateFilter(item, filter.filter);\n case 'valuePath': {\n const nested = item[filter.attribute];\n if (!Array.isArray(nested)) return false;\n return nested.some(child => isPlainObject(child) && evaluateFilter(child, filter.filter));\n }\n }\n};\n\nconst evaluateComparison = (item: Record<string, unknown>, attr: string, op: string, value: unknown): boolean => {\n const segments = attr.split('.');\n let current: unknown = item;\n for (const seg of segments) {\n if (!isPlainObject(current)) return false;\n current = current[seg];\n }\n if (op === 'pr') return current !== undefined && current !== null && current !== '';\n if (current === undefined || current === null) return false;\n\n switch (op) {\n case 'eq':\n return current === value;\n case 'ne':\n return current !== value;\n case 'co':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().includes(value.toLowerCase());\n case 'sw':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().startsWith(value.toLowerCase());\n case 'ew':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().endsWith(value.toLowerCase());\n case 'gt':\n return compareScalar(current, value) > 0;\n case 'ge':\n return compareScalar(current, value) >= 0;\n case 'lt':\n return compareScalar(current, value) < 0;\n case 'le':\n return compareScalar(current, value) <= 0;\n default:\n return false;\n }\n};\n\nconst compareScalar = (a: unknown, b: unknown): number => {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n const sa = String(a);\n const sb = String(b);\n if (sa < sb) return -1;\n if (sa > sb) return 1;\n return 0;\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n","import type { ScimUser } from '../types/scim.user.js';\nimport type { ScimListQuery, ScimListResult } from './repository.types.js';\n\n/**\n * Storage contract for SCIM `User` resources. The package ships only this\n * abstract class — implement it against your datastore (Kysely, Prisma,\n * Drizzle, in-memory) and pass the instance to {@link createScimRouter}.\n *\n * Implementations are responsible for:\n * - Translating the parsed filter AST in {@link ScimListQuery.filter} into a\n * native query.\n * - Honouring `startIndex` (1-based) and `count` for pagination.\n * - Returning the total number of matching resources, not just the page size.\n * - Persisting `meta.created` / `meta.lastModified` timestamps.\n *\n * Modeled as an abstract class so the runtime reference is a valid InjectKit\n * token (interfaces aren't preserved at runtime).\n */\nexport abstract class ScimUserRepository {\n /** Look up a user by server-assigned id. Return `undefined` if not found. */\n abstract findById(id: string): Promise<ScimUser | undefined>;\n\n /** Look up a user by `userName` (case-insensitive per RFC 7643). */\n abstract findByUserName(userName: string): Promise<ScimUser | undefined>;\n\n /** Look up a user by `externalId` (client-supplied identifier). */\n abstract findByExternalId(externalId: string): Promise<ScimUser | undefined>;\n\n /** List users matching a parsed query. */\n abstract list(query: ScimListQuery): Promise<ScimListResult<ScimUser>>;\n\n /** Persist a fully-formed user. `id`, `schemas`, and `meta` are already populated by {@link ScimUserService}. */\n abstract create(user: ScimUser): Promise<ScimUser>;\n\n /** Replace the entirety of an existing user (PUT semantics). */\n abstract replace(id: string, user: ScimUser): Promise<ScimUser>;\n\n /** Delete a user by id. Implementations may treat missing ids as a no-op. */\n abstract delete(id: string): Promise<void>;\n}\n","import type { ScimGroup } from '../types/scim.group.js';\nimport type { ScimListQuery, ScimListResult } from './repository.types.js';\n\n/**\n * Storage contract for SCIM `Group` resources. See\n * {@link ScimUserRepository} for general implementation guidance.\n */\nexport abstract class ScimGroupRepository {\n /** Look up a group by server-assigned id. */\n abstract findById(id: string): Promise<ScimGroup | undefined>;\n\n /** Look up a group by `displayName`. */\n abstract findByDisplayName(displayName: string): Promise<ScimGroup | undefined>;\n\n /** Look up a group by `externalId`. */\n abstract findByExternalId(externalId: string): Promise<ScimGroup | undefined>;\n\n /** List groups matching a parsed query. */\n abstract list(query: ScimListQuery): Promise<ScimListResult<ScimGroup>>;\n\n /** Persist a new group. */\n abstract create(group: ScimGroup): Promise<ScimGroup>;\n\n /** Replace the entirety of an existing group (PUT semantics). */\n abstract replace(id: string, group: ScimGroup): Promise<ScimGroup>;\n\n /** Delete a group by id. */\n abstract delete(id: string): Promise<void>;\n}\n","import { randomUUID } from 'node:crypto';\nimport { Injectable } from 'injectkit';\nimport { Logger } from '@maroonedsoftware/logger';\nimport { ScimUserRepository } from '../repositories/scim.user.repository.js';\nimport type { ScimListQuery, ScimListResult } from '../repositories/repository.types.js';\nimport type { ScimUser } from '../types/scim.user.js';\nimport type { ScimPatchOp } from '../types/patch.op.js';\nimport { applyScimPatch } from '../patch/patch.applier.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { UserSchemaId } from '../schemas/user.schema.js';\nimport { EnterpriseUserSchemaId } from '../schemas/enterprise.user.schema.js';\n\n/**\n * Application service wrapping a {@link ScimUserRepository}. Owns id and meta\n * assignment, uniqueness enforcement, and PATCH application — keeping the\n * repository focused on storage concerns.\n */\n@Injectable()\nexport class ScimUserService {\n constructor(\n private readonly repository: ScimUserRepository,\n private readonly logger: Logger,\n ) {}\n\n /**\n * Fetch a single user by id.\n *\n * @throws {ScimError} 404 if no user exists with the given id.\n */\n async get(id: string): Promise<ScimUser> {\n const user = await this.repository.findById(id);\n if (!user) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n return user;\n }\n\n /**\n * List users matching a parsed SCIM query, returning the page plus the\n * total number of matches (for the `totalResults` envelope field).\n */\n async list(query: ScimListQuery): Promise<ScimListResult<ScimUser>> {\n return this.repository.list(query);\n }\n\n /**\n * Create a new user. Assigns a server-generated `id`, fills `meta.created`\n * and `meta.lastModified`, and ensures the resource's `schemas` includes the\n * core User URN (and the EnterpriseUser URN when the extension is present).\n *\n * @throws {ScimError} 400 `invalidValue` when `userName` is missing.\n * @throws {ScimError} 409 `uniqueness` when `userName` already exists.\n */\n async create(payload: Partial<ScimUser>): Promise<ScimUser> {\n if (!payload.userName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"userName\" is required' });\n }\n const existing = await this.repository.findByUserName(payload.userName);\n if (existing) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `userName \"${payload.userName}\" already exists` });\n }\n const now = new Date().toISOString();\n const id = payload.id ?? randomUUID();\n const user: ScimUser = {\n ...payload,\n id,\n userName: payload.userName,\n schemas: this.normaliseSchemas(payload.schemas, payload),\n meta: {\n resourceType: 'User',\n created: now,\n lastModified: now,\n location: `/Users/${id}`,\n },\n };\n this.logger.debug('scim: creating user', { id, userName: user.userName });\n return this.repository.create(user);\n }\n\n /**\n * Replace an existing user wholesale (PUT semantics). Preserves the original\n * `id` and `meta.created`; updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n * @throws {ScimError} 400 `invalidValue` when `userName` is missing.\n * @throws {ScimError} 409 `uniqueness` when changing `userName` would collide\n * with another existing user.\n */\n async replace(id: string, payload: Partial<ScimUser>): Promise<ScimUser> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n if (!payload.userName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"userName\" is required' });\n }\n if (payload.userName !== existing.userName) {\n const conflict = await this.repository.findByUserName(payload.userName);\n if (conflict && conflict.id !== id) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `userName \"${payload.userName}\" already exists` });\n }\n }\n const now = new Date().toISOString();\n const user: ScimUser = {\n ...payload,\n id,\n userName: payload.userName,\n schemas: this.normaliseSchemas(payload.schemas, payload),\n meta: {\n ...existing.meta,\n lastModified: now,\n location: existing.meta.location ?? `/Users/${id}`,\n },\n };\n return this.repository.replace(id, user);\n }\n\n /**\n * Apply a sequence of SCIM PATCH ops (RFC 7644 §3.5.2) and persist the\n * result via `replace`. Updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n * @throws {ScimError} 400 propagated from {@link applyScimPatch} for invalid\n * paths, unknown ops, or no-target failures.\n */\n async patch(id: string, ops: ScimPatchOp[]): Promise<ScimUser> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n const patched = applyScimPatch(existing as unknown as Record<string, unknown>, ops) as unknown as ScimUser;\n patched.id = existing.id;\n patched.meta = {\n ...existing.meta,\n lastModified: new Date().toISOString(),\n };\n return this.repository.replace(id, patched);\n }\n\n /**\n * Delete a user by id.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n */\n async delete(id: string): Promise<void> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n await this.repository.delete(id);\n }\n\n private normaliseSchemas(provided: string[] | undefined, payload: Partial<ScimUser>): string[] {\n const schemas = new Set<string>(provided ?? []);\n schemas.add(UserSchemaId);\n if (payload[EnterpriseUserSchemaId]) {\n schemas.add(EnterpriseUserSchemaId);\n }\n return Array.from(schemas);\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { Injectable } from 'injectkit';\nimport { Logger } from '@maroonedsoftware/logger';\nimport { ScimGroupRepository } from '../repositories/scim.group.repository.js';\nimport type { ScimListQuery, ScimListResult } from '../repositories/repository.types.js';\nimport type { ScimGroup } from '../types/scim.group.js';\nimport type { ScimPatchOp } from '../types/patch.op.js';\nimport { applyScimPatch } from '../patch/patch.applier.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { GroupSchemaId } from '../schemas/group.schema.js';\n\n/**\n * Application service wrapping a {@link ScimGroupRepository}. Mirrors\n * {@link ScimUserService}: id/meta assignment, uniqueness on `displayName`,\n * and PATCH application.\n */\n@Injectable()\nexport class ScimGroupService {\n constructor(\n private readonly repository: ScimGroupRepository,\n private readonly logger: Logger,\n ) {}\n\n /**\n * Fetch a single group by id.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n */\n async get(id: string): Promise<ScimGroup> {\n const group = await this.repository.findById(id);\n if (!group) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n return group;\n }\n\n /**\n * List groups matching a parsed SCIM query, returning the page plus the\n * total number of matches.\n */\n async list(query: ScimListQuery): Promise<ScimListResult<ScimGroup>> {\n return this.repository.list(query);\n }\n\n /**\n * Create a new group. Assigns a server-generated `id` and fills `meta`\n * timestamps.\n *\n * @throws {ScimError} 400 `invalidValue` when `displayName` is missing.\n * @throws {ScimError} 409 `uniqueness` when `displayName` already exists.\n */\n async create(payload: Partial<ScimGroup>): Promise<ScimGroup> {\n if (!payload.displayName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"displayName\" is required' });\n }\n const existing = await this.repository.findByDisplayName(payload.displayName);\n if (existing) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `displayName \"${payload.displayName}\" already exists` });\n }\n const now = new Date().toISOString();\n const id = payload.id ?? randomUUID();\n const group: ScimGroup = {\n ...payload,\n id,\n displayName: payload.displayName,\n schemas: this.normaliseSchemas(payload.schemas),\n meta: {\n resourceType: 'Group',\n created: now,\n lastModified: now,\n location: `/Groups/${id}`,\n },\n };\n this.logger.debug('scim: creating group', { id, displayName: group.displayName });\n return this.repository.create(group);\n }\n\n /**\n * Replace an existing group wholesale (PUT semantics). Preserves `id` and\n * `meta.created`; updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n * @throws {ScimError} 400 `invalidValue` when `displayName` is missing.\n * @throws {ScimError} 409 `uniqueness` when changing `displayName` would collide.\n */\n async replace(id: string, payload: Partial<ScimGroup>): Promise<ScimGroup> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n if (!payload.displayName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"displayName\" is required' });\n }\n if (payload.displayName !== existing.displayName) {\n const conflict = await this.repository.findByDisplayName(payload.displayName);\n if (conflict && conflict.id !== id) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `displayName \"${payload.displayName}\" already exists` });\n }\n }\n const now = new Date().toISOString();\n const group: ScimGroup = {\n ...payload,\n id,\n displayName: payload.displayName,\n schemas: this.normaliseSchemas(payload.schemas),\n meta: {\n ...existing.meta,\n lastModified: now,\n location: existing.meta.location ?? `/Groups/${id}`,\n },\n };\n return this.repository.replace(id, group);\n }\n\n /**\n * Apply a sequence of SCIM PATCH ops and persist the result. Updates\n * `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n * @throws {ScimError} 400 propagated from {@link applyScimPatch}.\n */\n async patch(id: string, ops: ScimPatchOp[]): Promise<ScimGroup> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n const patched = applyScimPatch(existing as unknown as Record<string, unknown>, ops) as unknown as ScimGroup;\n patched.id = existing.id;\n patched.meta = {\n ...existing.meta,\n lastModified: new Date().toISOString(),\n };\n return this.repository.replace(id, patched);\n }\n\n /**\n * Delete a group by id.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n */\n async delete(id: string): Promise<void> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n await this.repository.delete(id);\n }\n\n private normaliseSchemas(provided: string[] | undefined): string[] {\n const schemas = new Set<string>(provided ?? []);\n schemas.add(GroupSchemaId);\n return Array.from(schemas);\n }\n}\n","import { Injectable } from 'injectkit';\nimport { buildServiceProviderConfig, type ScimServiceProviderConfig, type ScimServiceProviderConfigOptions } from '../schemas/service.provider.config.schema.js';\nimport { coreSchemas } from '../schemas/index.js';\nimport { userResourceType, groupResourceType, type ScimResourceType } from '../schemas/resource.type.schema.js';\nimport type { ScimSchema } from '../schemas/schema.types.js';\nimport { scimError } from '../errors/scim.error.js';\n\n/**\n * Serves the SCIM discovery endpoints: `/ServiceProviderConfig`, `/Schemas`,\n * and `/ResourceTypes`. The config is fixed at construction time — what the\n * server advertises must match what the router actually implements.\n */\n@Injectable()\nexport class ScimServiceProviderService {\n private readonly config: ScimServiceProviderConfig;\n private readonly schemas: ScimSchema[];\n private readonly resourceTypes: ScimResourceType[];\n\n constructor(options: ScimServiceProviderConfigOptions = {}) {\n this.config = buildServiceProviderConfig(options);\n this.schemas = coreSchemas;\n this.resourceTypes = [userResourceType, groupResourceType];\n }\n\n /** The materialised `/ServiceProviderConfig` response. */\n getServiceProviderConfig(): ScimServiceProviderConfig {\n return this.config;\n }\n\n /** Every schema known to this server, served from `/Schemas`. */\n listSchemas(): ScimSchema[] {\n return this.schemas;\n }\n\n /**\n * Look up a single schema by its URN.\n *\n * @throws {ScimError} 404 if the URN is not registered.\n */\n getSchema(id: string): ScimSchema {\n const found = this.schemas.find(s => s.id === id);\n if (!found) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Schema \"${id}\" not found` });\n return found;\n }\n\n /** Every resource type known to this server, served from `/ResourceTypes`. */\n listResourceTypes(): ScimResourceType[] {\n return this.resourceTypes;\n }\n\n /**\n * Look up a single resource type by id (e.g. `User`, `Group`).\n *\n * @throws {ScimError} 404 if the id is not registered.\n */\n getResourceType(id: string): ScimResourceType {\n const found = this.resourceTypes.find(rt => rt.id === id);\n if (!found) throw scimError(404, undefined, 'Not Found').withDetails({ message: `ResourceType \"${id}\" not found` });\n return found;\n }\n}\n","import type { ServerKitMiddleware } from '@maroonedsoftware/koa';\nimport { scimError } from '../errors/scim.error.js';\n\n/** SCIM media type per RFC 7644 §3.8. */\nexport const SCIM_MEDIA_TYPE = 'application/scim+json';\n\n/**\n * Enforce that mutating SCIM requests carry `Content-Type: application/scim+json`\n * (or `application/json`, which the spec accepts for backward compatibility),\n * and tag the response so it serialises with the SCIM media type.\n */\nexport const scimContentTypeMiddleware = (): ServerKitMiddleware => {\n return async (ctx, next) => {\n const method = ctx.method.toUpperCase();\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n const contentType = (ctx.request.headers['content-type'] ?? '').toLowerCase();\n if (contentType && !contentType.includes(SCIM_MEDIA_TYPE) && !contentType.includes('application/json')) {\n throw scimError(415, undefined, 'Unsupported Media Type').withDetails({\n message: `Content-Type must be ${SCIM_MEDIA_TYPE}`,\n });\n }\n }\n await next();\n if (ctx.body !== undefined && ctx.body !== null) {\n ctx.type = SCIM_MEDIA_TYPE;\n }\n };\n};\n","import type { ServerKitMiddleware } from '@maroonedsoftware/koa';\nimport { IsHttpError, IsServerkitError } from '@maroonedsoftware/errors';\nimport { IsScimError, ScimError, ScimErrorSchema } from '../errors/scim.error.js';\nimport { SCIM_MEDIA_TYPE } from './scim.content.type.middleware.js';\n\n/**\n * SCIM-shaped error middleware. Catches errors thrown by downstream handlers\n * and renders them as the RFC 7644 §3.12 envelope with `Content-Type:\n * application/scim+json`.\n *\n * Mount this *inside* a SCIM sub-router (or in front of the SCIM router on\n * its own Koa instance) — do not replace the application-wide\n * `errorMiddleware` from `@maroonedsoftware/koa` with it.\n */\nexport const scimErrorMiddleware = (): ServerKitMiddleware => {\n return async (ctx, next) => {\n try {\n await next();\n if (ctx.status === 404 && !ctx.body) {\n const status = 404;\n ctx.status = status;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = {\n schemas: [ScimErrorSchema],\n status: String(status),\n detail: `Not Found: ${ctx.URL.pathname}`,\n };\n }\n } catch (error) {\n if (IsScimError(error)) {\n respondWithScimError(ctx, error);\n ctx.app.emit('error', error, ctx);\n return;\n }\n if (IsHttpError(error)) {\n respondWithScimError(ctx, new ScimError(error.statusCode).withDetails(error.details ?? {}).withCause(error));\n ctx.app.emit('error', error, ctx);\n return;\n }\n const status = 500;\n const detail = IsServerkitError(error) ? error.message : 'Internal Server Error';\n ctx.status = status;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = {\n schemas: [ScimErrorSchema],\n status: String(status),\n detail,\n };\n ctx.app.emit('error', error, ctx);\n }\n };\n};\n\nconst respondWithScimError = (ctx: Parameters<ServerKitMiddleware>[0], error: ScimError): void => {\n ctx.status = error.statusCode;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = error.toScimBody();\n if (error.headers) {\n for (const [name, value] of Object.entries(error.headers)) {\n ctx.set(name, value);\n }\n }\n};\n","import type { ServerKitRouterMiddleware } from '@maroonedsoftware/koa';\nimport { invalidAuthenticationSession } from '@maroonedsoftware/authentication';\nimport { scimError } from '../errors/scim.error.js';\n\n/**\n * Router middleware enforcing that the current request carries a SCIM scope\n * on its authentication session. The scope list is read from\n * `ctx.authenticationSession.claims.scimScopes` — a string array the consumer\n * populates when minting the session for the bearer token.\n *\n * Wildcard scope `*` in the session grants every check.\n */\nexport const requireScimScope = (scope: string): ServerKitRouterMiddleware => {\n return async (ctx, next) => {\n const session = ctx.authenticationSession;\n if (!session || session === invalidAuthenticationSession) {\n throw scimError(401, undefined, 'Unauthorized')\n .addHeader('WWW-Authenticate', 'Bearer error=\"invalid_token\"')\n .withDetails({ message: 'Missing or invalid bearer token' });\n }\n const granted = session.claims?.scimScopes;\n if (!Array.isArray(granted) || (!granted.includes('*') && !granted.includes(scope))) {\n throw scimError(403, 'insufficientScope', 'Forbidden').withDetails({ message: `Scope \"${scope}\" required` });\n }\n await next();\n };\n};\n","import type { ServerKitContext, ServerKitRouterMiddleware } from '@maroonedsoftware/koa';\nimport { bodyParserMiddleware, ServerKitRouter } from '@maroonedsoftware/koa';\nimport type Router from '@koa/router';\nimport { ScimUserService } from '../services/scim.user.service.js';\nimport { ScimGroupService } from '../services/scim.group.service.js';\nimport { ScimServiceProviderService } from '../services/scim.service.provider.service.js';\nimport type { ScimUser } from '../types/scim.user.js';\nimport type { ScimGroup } from '../types/scim.group.js';\nimport { type ScimPatchOp, type ScimPatchRequest, PatchOpSchema } from '../types/patch.op.js';\nimport { ListResponseSchema, type ScimListResponse } from '../types/list.response.js';\nimport { type ScimListQuery, type ScimSortOrder } from '../repositories/repository.types.js';\nimport { parseScimFilter } from '../filter/filter.parser.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { SCIM_MEDIA_TYPE } from '../middleware/scim.content.type.middleware.js';\n\n/**\n * Options for {@link createScimRouter}. The caller constructs the three\n * services (wiring them to their backing repositories and a logger) and\n * hands them in.\n */\nexport interface CreateScimRouterOptions {\n /** Service handling all `/Users` endpoints. */\n userService: ScimUserService;\n /** Service handling all `/Groups` endpoints. */\n groupService: ScimGroupService;\n /** Service that owns `/Schemas`, `/ResourceTypes`, `/ServiceProviderConfig`. */\n serviceProviderService: ScimServiceProviderService;\n /** Optional middleware mounted on every route (e.g. `requireScimScope('users:read')`). */\n routeGuards?: ServerKitRouterMiddleware[];\n /**\n * Maximum page size returned from list endpoints. Defaults to the\n * `serviceProviderService` `filter.maxResults` value, falling back to 200.\n */\n maxResults?: number;\n}\n\n/**\n * Build a SCIM 2.0 server router. Mount it inside a Koa app that already has\n * `serverKitContextMiddleware` and `authenticationMiddleware` configured, and\n * use `scimErrorMiddleware()` instead of the default `errorMiddleware()` for\n * the SCIM mountpoint.\n *\n * Endpoints (RFC 7644 §3.4):\n * - `GET /Users` — list users (with `filter`, `startIndex`, `count`, `sortBy`, `sortOrder`)\n * - `POST /Users` — create user\n * - `GET /Users/:id` — fetch one user\n * - `PUT /Users/:id` — replace user\n * - `PATCH /Users/:id` — apply PATCH ops\n * - `DELETE /Users/:id` — delete user\n * - `POST /Users/.search` — list-via-POST so large filters can be sent in the body\n * - Same six endpoints for `/Groups` and `/Groups/.search`\n * - `GET /Schemas`, `GET /Schemas/:id`\n * - `GET /ResourceTypes`, `GET /ResourceTypes/:id`\n * - `GET /ServiceProviderConfig`\n */\nexport const createScimRouter = (options: CreateScimRouterOptions): Router<unknown, ServerKitContext> => {\n const router = ServerKitRouter();\n const guards = options.routeGuards ?? [];\n const json = bodyParserMiddleware([SCIM_MEDIA_TYPE, 'application/json']);\n const maxResults = options.maxResults ?? options.serviceProviderService.getServiceProviderConfig().filter.maxResults ?? 200;\n\n // Discovery endpoints — RFC 7644 §4 says these MAY be unauthenticated. Apply\n // the route guards anyway so the consumer can decide.\n router.get('/ServiceProviderConfig', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getServiceProviderConfig();\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/Schemas', ...guards, async ctx => {\n ctx.body = listEnvelope(options.serviceProviderService.listSchemas());\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/Schemas/:id', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getSchema(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/ResourceTypes', ...guards, async ctx => {\n ctx.body = listEnvelope(options.serviceProviderService.listResourceTypes());\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/ResourceTypes/:id', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getResourceType(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n // Users\n router.get('/Users', ...guards, async ctx => {\n const query = parseListQueryFromUrl(ctx.query, maxResults);\n const result = await options.userService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Users/.search', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx);\n const query = parseListQueryFromBody(requestBody, maxResults);\n const result = await options.userService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Users', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimUser>;\n const created = await options.userService.create(payload);\n ctx.status = 201;\n ctx.body = created;\n ctx.type = SCIM_MEDIA_TYPE;\n if (created.meta.location) ctx.set('Location', created.meta.location);\n });\n\n router.get('/Users/:id', ...guards, async ctx => {\n ctx.body = await options.userService.get(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.put('/Users/:id', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimUser>;\n ctx.body = await options.userService.replace(ctx.params.id!, payload);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.patch('/Users/:id', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx) as Partial<ScimPatchRequest>;\n const ops = validatePatchRequest(requestBody);\n ctx.body = await options.userService.patch(ctx.params.id!, ops);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.delete('/Users/:id', ...guards, async ctx => {\n await options.userService.delete(ctx.params.id!);\n ctx.status = 204;\n });\n\n // Groups\n router.get('/Groups', ...guards, async ctx => {\n const query = parseListQueryFromUrl(ctx.query, maxResults);\n const result = await options.groupService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Groups/.search', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx);\n const query = parseListQueryFromBody(requestBody, maxResults);\n const result = await options.groupService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Groups', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimGroup>;\n const created = await options.groupService.create(payload);\n ctx.status = 201;\n ctx.body = created;\n ctx.type = SCIM_MEDIA_TYPE;\n if (created.meta.location) ctx.set('Location', created.meta.location);\n });\n\n router.get('/Groups/:id', ...guards, async ctx => {\n ctx.body = await options.groupService.get(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.put('/Groups/:id', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimGroup>;\n ctx.body = await options.groupService.replace(ctx.params.id!, payload);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.patch('/Groups/:id', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx) as Partial<ScimPatchRequest>;\n const ops = validatePatchRequest(requestBody);\n ctx.body = await options.groupService.patch(ctx.params.id!, ops);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.delete('/Groups/:id', ...guards, async ctx => {\n await options.groupService.delete(ctx.params.id!);\n ctx.status = 204;\n });\n\n return router;\n};\n\n/**\n * `bodyParserMiddleware` writes the parsed request body to `ctx.body` (the\n * codebase convention). Move it into a local before the handler reassigns\n * `ctx.body` to the response.\n */\nconst takeRequestBody = (ctx: ServerKitContext): unknown => {\n const body = ctx.body;\n ctx.body = undefined;\n return body;\n};\n\nconst parseListQueryFromUrl = (query: ServerKitContext['query'], maxResults: number): ScimListQuery => {\n const filterRaw = pickStringParam(query, 'filter');\n return {\n filter: filterRaw ? parseScimFilter(filterRaw) : undefined,\n startIndex: parsePositiveInt(pickStringParam(query, 'startIndex'), 1),\n count: clamp(parsePositiveInt(pickStringParam(query, 'count'), maxResults), 0, maxResults),\n sortBy: pickStringParam(query, 'sortBy'),\n sortOrder: parseSortOrder(pickStringParam(query, 'sortOrder')),\n attributes: parseCsvParam(pickStringParam(query, 'attributes')),\n excludedAttributes: parseCsvParam(pickStringParam(query, 'excludedAttributes')),\n };\n};\n\nconst parseListQueryFromBody = (body: unknown, maxResults: number): ScimListQuery => {\n if (!isPlainObject(body)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: 'Search body must be a JSON object' });\n }\n const filterRaw = typeof body.filter === 'string' ? body.filter : undefined;\n return {\n filter: filterRaw ? parseScimFilter(filterRaw) : undefined,\n startIndex: typeof body.startIndex === 'number' && body.startIndex > 0 ? Math.floor(body.startIndex) : 1,\n count: clamp(typeof body.count === 'number' ? Math.floor(body.count) : maxResults, 0, maxResults),\n sortBy: typeof body.sortBy === 'string' ? body.sortBy : undefined,\n sortOrder: parseSortOrder(typeof body.sortOrder === 'string' ? body.sortOrder : undefined),\n attributes: Array.isArray(body.attributes) ? body.attributes.filter((a): a is string => typeof a === 'string') : undefined,\n excludedAttributes: Array.isArray(body.excludedAttributes) ? body.excludedAttributes.filter((a): a is string => typeof a === 'string') : undefined,\n };\n};\n\nconst parseSortOrder = (raw: string | undefined): ScimSortOrder | undefined => {\n if (raw === 'ascending' || raw === 'descending') return raw;\n return undefined;\n};\n\nconst parsePositiveInt = (raw: string | undefined, fallback: number): number => {\n if (raw === undefined) return fallback;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 1) return fallback;\n return Math.floor(n);\n};\n\nconst clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(max, value));\n\nconst parseCsvParam = (raw: string | undefined): string[] | undefined => {\n if (!raw) return undefined;\n const parts = raw.split(',').map(s => s.trim()).filter(Boolean);\n return parts.length > 0 ? parts : undefined;\n};\n\nconst pickStringParam = (query: ServerKitContext['query'], key: string): string | undefined => {\n const value = query[key];\n if (typeof value === 'string') return value;\n if (Array.isArray(value) && typeof value[0] === 'string') return value[0];\n return undefined;\n};\n\nconst validatePatchRequest = (body: Partial<ScimPatchRequest> | unknown): ScimPatchOp[] => {\n if (!isPlainObject(body)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: 'PATCH request must be a JSON object' });\n }\n if (!Array.isArray(body.schemas) || !body.schemas.includes(PatchOpSchema)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: `PATCH request schemas must include \"${PatchOpSchema}\"` });\n }\n if (!Array.isArray(body.Operations) || body.Operations.length === 0) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"Operations\" must be a non-empty array' });\n }\n return body.Operations as ScimPatchOp[];\n};\n\nconst listEnvelope = <T>(resources: T[], query?: ScimListQuery, total?: number): ScimListResponse<T> => ({\n schemas: [ListResponseSchema],\n totalResults: total ?? resources.length,\n startIndex: query?.startIndex ?? 1,\n itemsPerPage: resources.length,\n Resources: resources,\n});\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n"],"mappings":"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","names":["ListResponseSchema","PatchOpSchema","UserSchemaId","userSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","multiValuedSubAttrs","canonicalValues","kind","GroupSchemaId","groupSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","canonicalValues","EnterpriseUserSchemaId","enterpriseUserSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","ResourceTypeSchemaId","userResourceType","schemas","id","name","endpoint","description","schema","UserSchemaId","schemaExtensions","EnterpriseUserSchemaId","required","meta","resourceType","location","groupResourceType","GroupSchemaId","ServiceProviderConfigSchemaId","defaultBearer","type","name","description","specUri","primary","buildServiceProviderConfig","options","schemas","documentationUri","patch","supported","bulk","maxOperations","maxPayloadSize","filter","maxResults","changePassword","sort","etag","authenticationSchemes","meta","resourceType","location","coreSchemas","userSchema","groupSchema","enterpriseUserSchema","HttpError","ScimErrorSchema","ScimError","HttpError","scimType","statusCode","message","Object","setPrototypeOf","prototype","toScimBody","schemas","status","String","detail","IsScimError","error","scimError","COMPARISON_OPS","Set","tokenizeScimFilter","input","tokens","i","length","ch","push","kind","value","start","next","scimError","withDetails","position","message","raw","test","num","Number","isNaN","isIdentifierStart","isIdentifierPart","lower","toLowerCase","has","parseScimFilter","input","trimmed","trim","length","scimError","withDetails","message","tokens","tokenizeScimFilter","parser","Parser","node","parseOr","expectEnd","pos","left","parseAnd","peek","kind","consume","right","operator","parseUnary","token","expect","inner","filter","parseComparisonOrValuePath","error","attribute","String","value","next","valueToken","remaining","position","start","applyScimPatch","resource","ops","next","structuredClone","op","applyOne","kind","normaliseOpKind","path","undefined","scimError","withDetails","message","value","Array","isArray","mergeObject","parsePatchPath","applyAtPath","lower","String","toLowerCase","raw","bracketStart","indexOf","segments","split","filter","Boolean","bracketEnd","findMatchingBracket","head","slice","filterSrc","tail","length","parseScimFilter","filterSubAttr","startsWith","includes","input","openIndex","depth","inString","i","ch","rest","applyFilteredOp","applySimpleOp","child","childObj","isPlainObject","updated","attr","existing","subAttr","collection","matched","forEach","item","index","evaluateFilter","push","_","idx","seed","map","target","source","out","key","val","Object","entries","evaluateComparison","attribute","operator","left","right","nested","some","current","seg","endsWith","compareScalar","a","b","sa","sb","ScimUserRepository","ScimGroupRepository","randomUUID","Injectable","Logger","ScimUserService","repository","logger","get","id","user","findById","scimError","undefined","withDetails","message","list","query","create","payload","userName","existing","findByUserName","now","Date","toISOString","randomUUID","schemas","normaliseSchemas","meta","resourceType","created","lastModified","location","debug","replace","conflict","patch","ops","patched","applyScimPatch","delete","provided","Set","add","UserSchemaId","EnterpriseUserSchemaId","Array","from","randomUUID","Injectable","Logger","ScimGroupService","repository","logger","get","id","group","findById","scimError","undefined","withDetails","message","list","query","create","payload","displayName","existing","findByDisplayName","now","Date","toISOString","randomUUID","schemas","normaliseSchemas","meta","resourceType","created","lastModified","location","debug","replace","conflict","patch","ops","patched","applyScimPatch","delete","provided","Set","add","GroupSchemaId","Array","from","Injectable","ScimServiceProviderService","config","schemas","resourceTypes","options","buildServiceProviderConfig","coreSchemas","userResourceType","groupResourceType","getServiceProviderConfig","listSchemas","getSchema","id","found","find","s","scimError","undefined","withDetails","message","listResourceTypes","getResourceType","rt","SCIM_MEDIA_TYPE","scimContentTypeMiddleware","ctx","next","method","toUpperCase","contentType","request","headers","toLowerCase","includes","scimError","undefined","withDetails","message","body","type","IsHttpError","IsServerkitError","scimErrorMiddleware","ctx","next","status","body","type","SCIM_MEDIA_TYPE","schemas","ScimErrorSchema","String","detail","URL","pathname","error","IsScimError","respondWithScimError","app","emit","IsHttpError","ScimError","statusCode","withDetails","details","withCause","IsServerkitError","message","toScimBody","headers","name","value","Object","entries","set","invalidAuthenticationSession","requireScimScope","scope","ctx","next","session","authenticationSession","invalidAuthenticationSession","scimError","undefined","addHeader","withDetails","message","granted","claims","scimScopes","Array","isArray","includes","bodyParserMiddleware","ServerKitRouter","createScimRouter","options","router","ServerKitRouter","guards","routeGuards","json","bodyParserMiddleware","SCIM_MEDIA_TYPE","maxResults","serviceProviderService","getServiceProviderConfig","filter","get","ctx","body","type","listEnvelope","listSchemas","getSchema","params","id","listResourceTypes","getResourceType","query","parseListQueryFromUrl","result","userService","list","resources","totalResults","post","requestBody","takeRequestBody","parseListQueryFromBody","payload","created","create","status","meta","location","set","put","replace","patch","ops","validatePatchRequest","delete","groupService","undefined","filterRaw","pickStringParam","parseScimFilter","startIndex","parsePositiveInt","count","clamp","sortBy","sortOrder","parseSortOrder","attributes","parseCsvParam","excludedAttributes","isPlainObject","scimError","withDetails","message","Math","floor","Array","isArray","a","raw","fallback","n","Number","isFinite","value","min","max","parts","split","map","s","trim","Boolean","length","key","schemas","includes","PatchOpSchema","Operations","total","ListResponseSchema","itemsPerPage","Resources"]}
1
+ {"version":3,"sources":["../src/types/list.response.ts","../src/types/patch.op.ts","../src/schemas/user.schema.ts","../src/schemas/group.schema.ts","../src/schemas/enterprise.user.schema.ts","../src/schemas/resource.type.schema.ts","../src/schemas/service.provider.config.schema.ts","../src/schemas/index.ts","../src/errors/scim.error.ts","../src/filter/filter.tokenizer.ts","../src/filter/filter.parser.ts","../src/patch/patch.applier.ts","../src/repositories/scim.user.repository.ts","../src/repositories/scim.group.repository.ts","../src/services/scim.user.service.ts","../src/services/scim.group.service.ts","../src/services/scim.service.provider.service.ts","../src/middleware/scim.content.type.middleware.ts","../src/middleware/scim.error.middleware.ts","../src/middleware/require.scim.scope.middleware.ts","../src/router/scim.router.ts"],"sourcesContent":["/**\n * Schema URI for the SCIM ListResponse message (RFC 7644 §3.4.2).\n */\nexport const ListResponseSchema = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n/**\n * SCIM ListResponse envelope returned from list/search endpoints.\n */\nexport interface ScimListResponse<TResource> {\n schemas: [typeof ListResponseSchema];\n totalResults: number;\n startIndex?: number;\n itemsPerPage?: number;\n Resources?: TResource[];\n}\n","/**\n * Schema URI for the SCIM PatchOp message (RFC 7644 §3.5.2).\n */\nexport const PatchOpSchema = 'urn:ietf:params:scim:api:messages:2.0:PatchOp';\n\n/**\n * Operation kinds permitted in a SCIM PATCH request.\n * Case-insensitive on the wire; normalised internally.\n */\nexport type ScimPatchOpKind = 'add' | 'replace' | 'remove';\n\n/**\n * A single PATCH operation as it appears in a PatchOp request body.\n */\nexport interface ScimPatchOp {\n op: ScimPatchOpKind | Uppercase<ScimPatchOpKind> | Capitalize<ScimPatchOpKind>;\n path?: string;\n value?: unknown;\n}\n\n/**\n * The full PatchOp request envelope.\n */\nexport interface ScimPatchRequest {\n schemas: [typeof PatchOpSchema];\n Operations: ScimPatchOp[];\n}\n","import type { ScimAttributeDefinition, ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM core User resource. */\nexport const UserSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:User';\n\n/**\n * RFC 7643 §4.1: SCIM core User schema definition. A condensed but\n * spec-compliant subset suitable for `/Schemas` discovery.\n */\nexport const userSchema: ScimSchema = {\n id: UserSchemaId,\n name: 'User',\n description: 'User Account',\n meta: { resourceType: 'Schema', location: `/Schemas/${UserSchemaId}` },\n attributes: [\n {\n name: 'userName',\n type: 'string',\n multiValued: false,\n description: 'Unique identifier for the User, typically used by the user to directly authenticate.',\n required: true,\n caseExact: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'server',\n },\n {\n name: 'name',\n type: 'complex',\n multiValued: false,\n description: 'The components of the user\\'s real name.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'formatted', type: 'string', multiValued: false, description: 'Full name formatted for display.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'familyName', type: 'string', multiValued: false, description: 'Family name (last name).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'givenName', type: 'string', multiValued: false, description: 'Given name (first name).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'middleName', type: 'string', multiValued: false, description: 'Middle name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'honorificPrefix', type: 'string', multiValued: false, description: 'Honorific prefix (e.g., Ms., Dr.).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'honorificSuffix', type: 'string', multiValued: false, description: 'Honorific suffix (e.g., Jr., III).', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n ],\n },\n { name: 'displayName', type: 'string', multiValued: false, description: 'Name displayed to end-users.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'nickName', type: 'string', multiValued: false, description: 'Casual name of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'profileUrl', type: 'reference', multiValued: false, description: 'URL of the User\\'s online profile.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none', referenceTypes: ['external'] },\n { name: 'title', type: 'string', multiValued: false, description: 'Title of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'userType', type: 'string', multiValued: false, description: 'Used to identify the relationship between the organization and the user.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'preferredLanguage', type: 'string', multiValued: false, description: 'Preferred language as per RFC 7231.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'locale', type: 'string', multiValued: false, description: 'Default location of the User.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'timezone', type: 'string', multiValued: false, description: 'Time zone in IANA format.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'active', type: 'boolean', multiValued: false, description: 'Whether the user is active.', required: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'password', type: 'string', multiValued: false, description: 'Cleartext password (write-only).', required: false, caseExact: false, mutability: 'writeOnly', returned: 'never', uniqueness: 'none' },\n {\n name: 'emails',\n type: 'complex',\n multiValued: true,\n description: 'Email addresses for the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: multiValuedSubAttrs('email'),\n },\n {\n name: 'phoneNumbers',\n type: 'complex',\n multiValued: true,\n description: 'Phone numbers for the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: multiValuedSubAttrs('phone'),\n },\n {\n name: 'groups',\n type: 'complex',\n multiValued: true,\n description: 'Groups the user is a member of (read-only).',\n required: false,\n mutability: 'readOnly',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Identifier of the Group.', required: false, caseExact: true, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the Group resource.', required: false, caseExact: true, mutability: 'readOnly', returned: 'default', uniqueness: 'none', referenceTypes: ['Group'] },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable Group name.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: 'Membership type.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none', canonicalValues: ['direct', 'indirect'] },\n ],\n },\n ],\n};\n\nfunction multiValuedSubAttrs(kind: string): ScimAttributeDefinition[] {\n return [\n { name: 'value', type: 'string', multiValued: false, description: `${kind} value.`, required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable display value.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: `Function of the ${kind} (e.g., work, home).`, required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'primary', type: 'boolean', multiValued: false, description: 'Whether this is the primary value.', required: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n ];\n}\n","import type { ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM core Group resource. */\nexport const GroupSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n/**\n * RFC 7643 §4.2: SCIM core Group schema definition.\n */\nexport const groupSchema: ScimSchema = {\n id: GroupSchemaId,\n name: 'Group',\n description: 'Group',\n meta: { resourceType: 'Schema', location: `/Schemas/${GroupSchemaId}` },\n attributes: [\n {\n name: 'displayName',\n type: 'string',\n multiValued: false,\n description: 'Human-readable name for the Group.',\n required: true,\n caseExact: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n },\n {\n name: 'members',\n type: 'complex',\n multiValued: true,\n description: 'List of Group members.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Identifier of the member.', required: false, caseExact: true, mutability: 'immutable', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the member resource.', required: false, caseExact: true, mutability: 'immutable', returned: 'default', uniqueness: 'none', referenceTypes: ['User', 'Group'] },\n { name: 'display', type: 'string', multiValued: false, description: 'Human-readable name of the member.', required: false, caseExact: false, mutability: 'immutable', returned: 'default', uniqueness: 'none' },\n { name: 'type', type: 'string', multiValued: false, description: 'Member type.', required: false, caseExact: false, mutability: 'immutable', returned: 'default', uniqueness: 'none', canonicalValues: ['User', 'Group'] },\n ],\n },\n ],\n};\n","import type { ScimSchema } from './schema.types.js';\n\n/** Schema URI for the SCIM EnterpriseUser extension. */\nexport const EnterpriseUserSchemaId = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n\n/**\n * RFC 7643 §4.3: EnterpriseUser extension schema definition.\n */\nexport const enterpriseUserSchema: ScimSchema = {\n id: EnterpriseUserSchemaId,\n name: 'EnterpriseUser',\n description: 'Enterprise User extension',\n meta: { resourceType: 'Schema', location: `/Schemas/${EnterpriseUserSchemaId}` },\n attributes: [\n { name: 'employeeNumber', type: 'string', multiValued: false, description: 'Employee number.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'costCenter', type: 'string', multiValued: false, description: 'Cost center.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'organization', type: 'string', multiValued: false, description: 'Organization name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'division', type: 'string', multiValued: false, description: 'Division name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: 'department', type: 'string', multiValued: false, description: 'Department name.', required: false, caseExact: false, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n {\n name: 'manager',\n type: 'complex',\n multiValued: false,\n description: 'The manager of the user.',\n required: false,\n mutability: 'readWrite',\n returned: 'default',\n uniqueness: 'none',\n subAttributes: [\n { name: 'value', type: 'string', multiValued: false, description: 'Manager user id.', required: false, caseExact: true, mutability: 'readWrite', returned: 'default', uniqueness: 'none' },\n { name: '$ref', type: 'reference', multiValued: false, description: 'URI of the manager User resource.', required: false, caseExact: true, mutability: 'readWrite', returned: 'default', uniqueness: 'none', referenceTypes: ['User'] },\n { name: 'displayName', type: 'string', multiValued: false, description: 'Manager display name.', required: false, caseExact: false, mutability: 'readOnly', returned: 'default', uniqueness: 'none' },\n ],\n },\n ],\n};\n","import { UserSchemaId } from './user.schema.js';\nimport { GroupSchemaId } from './group.schema.js';\nimport { EnterpriseUserSchemaId } from './enterprise.user.schema.js';\n\n/** Schema URI for the SCIM ResourceType resource. */\nexport const ResourceTypeSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:ResourceType';\n\nexport interface ScimResourceType {\n schemas: [typeof ResourceTypeSchemaId];\n id: string;\n name: string;\n endpoint: string;\n description: string;\n schema: string;\n schemaExtensions?: Array<{ schema: string; required: boolean }>;\n meta: {\n resourceType: 'ResourceType';\n location?: string;\n };\n}\n\nexport const userResourceType: ScimResourceType = {\n schemas: [ResourceTypeSchemaId],\n id: 'User',\n name: 'User',\n endpoint: '/Users',\n description: 'User Account',\n schema: UserSchemaId,\n schemaExtensions: [{ schema: EnterpriseUserSchemaId, required: false }],\n meta: { resourceType: 'ResourceType', location: '/ResourceTypes/User' },\n};\n\nexport const groupResourceType: ScimResourceType = {\n schemas: [ResourceTypeSchemaId],\n id: 'Group',\n name: 'Group',\n endpoint: '/Groups',\n description: 'Group',\n schema: GroupSchemaId,\n meta: { resourceType: 'ResourceType', location: '/ResourceTypes/Group' },\n};\n","/** Schema URI for the SCIM ServiceProviderConfig resource. */\nexport const ServiceProviderConfigSchemaId = 'urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig';\n\n/** Authentication scheme advertised by `/ServiceProviderConfig`. */\nexport interface ScimAuthenticationScheme {\n type: 'oauth' | 'oauth2' | 'oauthbearertoken' | 'httpbasic' | 'httpdigest';\n name: string;\n description: string;\n specUri?: string;\n documentationUri?: string;\n primary?: boolean;\n}\n\n/** Optional features the service provider supports (RFC 7643 §5). */\nexport interface ScimServiceProviderConfigOptions {\n documentationUri?: string;\n patch?: { supported: boolean };\n bulk?: { supported: boolean; maxOperations: number; maxPayloadSize: number };\n filter?: { supported: boolean; maxResults: number };\n changePassword?: { supported: boolean };\n sort?: { supported: boolean };\n etag?: { supported: boolean };\n authenticationSchemes?: ScimAuthenticationScheme[];\n}\n\n/** Materialised ServiceProviderConfig response. */\nexport interface ScimServiceProviderConfig extends Required<Omit<ScimServiceProviderConfigOptions, 'documentationUri' | 'authenticationSchemes'>> {\n schemas: [typeof ServiceProviderConfigSchemaId];\n documentationUri?: string;\n authenticationSchemes: ScimAuthenticationScheme[];\n meta: {\n resourceType: 'ServiceProviderConfig';\n location?: string;\n };\n}\n\nconst defaultBearer: ScimAuthenticationScheme = {\n type: 'oauthbearertoken',\n name: 'OAuth Bearer Token',\n description: 'Authentication scheme using the OAuth Bearer Token Standard.',\n specUri: 'https://www.rfc-editor.org/info/rfc6750',\n primary: true,\n};\n\n/**\n * Build a SCIM ServiceProviderConfig response object, layering caller options\n * over the toolkit's defaults (PATCH on, filter on, sort on; bulk/changePassword/etag off).\n */\nexport const buildServiceProviderConfig = (options: ScimServiceProviderConfigOptions = {}): ScimServiceProviderConfig => ({\n schemas: [ServiceProviderConfigSchemaId],\n documentationUri: options.documentationUri,\n patch: options.patch ?? { supported: true },\n bulk: options.bulk ?? { supported: false, maxOperations: 0, maxPayloadSize: 0 },\n filter: options.filter ?? { supported: true, maxResults: 200 },\n changePassword: options.changePassword ?? { supported: false },\n sort: options.sort ?? { supported: true },\n etag: options.etag ?? { supported: false },\n authenticationSchemes: options.authenticationSchemes ?? [defaultBearer],\n meta: { resourceType: 'ServiceProviderConfig', location: '/ServiceProviderConfig' },\n});\n","export * from './schema.types.js';\nexport * from './user.schema.js';\nexport * from './group.schema.js';\nexport * from './enterprise.user.schema.js';\nexport * from './resource.type.schema.js';\nexport * from './service.provider.config.schema.js';\n\nimport { userSchema } from './user.schema.js';\nimport { groupSchema } from './group.schema.js';\nimport { enterpriseUserSchema } from './enterprise.user.schema.js';\n\n/** All SCIM core + extension schemas this package ships. */\nexport const coreSchemas = [userSchema, groupSchema, enterpriseUserSchema];\n","import { HttpError, HttpStatusCodes, type HttpStatusMessage } from '@maroonedsoftware/errors';\n\n/** Schema URI for the SCIM Error message. */\nexport const ScimErrorSchema = 'urn:ietf:params:scim:api:messages:2.0:Error';\n\n/**\n * `scimType` values defined by RFC 7644 §3.12 plus the few extensions clients\n * commonly emit. Keep this open as `string` to allow vendor-specific values.\n */\nexport type ScimErrorType =\n | 'invalidFilter'\n | 'tooMany'\n | 'uniqueness'\n | 'mutability'\n | 'invalidSyntax'\n | 'invalidPath'\n | 'noTarget'\n | 'invalidValue'\n | 'invalidVers'\n | 'sensitive'\n | 'insufficientScope'\n | (string & {});\n\n/**\n * SCIM error envelope (RFC 7644 §3.12). The HTTP status comes from\n * the underlying {@link HttpError}; the JSON body matches:\n *\n * ```json\n * { \"schemas\": [\"urn:ietf:params:scim:api:messages:2.0:Error\"], \"status\": \"404\", \"scimType\": \"invalidPath\", \"detail\": \"...\" }\n * ```\n */\nexport class ScimError extends HttpError {\n /** SCIM-specific error subtype, see RFC 7644 §3.12. */\n readonly scimType?: ScimErrorType;\n\n constructor(statusCode: HttpStatusCodes, scimType?: ScimErrorType, message?: HttpStatusMessage<HttpStatusCodes>) {\n super(statusCode, message);\n this.scimType = scimType;\n Object.setPrototypeOf(this, ScimError.prototype);\n }\n\n /** Build the SCIM error JSON body for this error. */\n toScimBody(): { schemas: [typeof ScimErrorSchema]; status: string; scimType?: ScimErrorType; detail?: string } {\n return {\n schemas: [ScimErrorSchema],\n status: String(this.statusCode),\n ...(this.scimType ? { scimType: this.scimType } : {}),\n detail: this.message,\n };\n }\n}\n\n/** Type guard for {@link ScimError}. */\nexport const IsScimError = (error: unknown): error is ScimError => error instanceof ScimError;\n\n/**\n * Factory for building a SCIM-shaped HTTP error. The returned object behaves like\n * an {@link HttpError}, so chained `.withDetails()` / `.withCause()` /\n * `.withInternalDetails()` work as usual.\n *\n * @example\n * ```ts\n * throw scimError(400, 'invalidFilter', 'Bad Request');\n * ```\n */\nexport const scimError = <Status extends HttpStatusCodes>(\n statusCode: Status,\n scimType?: ScimErrorType,\n message?: HttpStatusMessage<Status>,\n): ScimError => new ScimError(statusCode, scimType, message);\n","import { scimError } from '../errors/scim.error.js';\n\nexport type ScimTokenKind =\n | 'identifier' // attribute path, including dots, colons, dashes, and URN segments\n | 'string'\n | 'number'\n | 'true'\n | 'false'\n | 'null'\n | 'and'\n | 'or'\n | 'not'\n | 'lparen'\n | 'rparen'\n | 'lbracket'\n | 'rbracket'\n | 'op'; // eq, ne, co, sw, ew, gt, ge, lt, le, pr\n\nexport interface ScimToken {\n kind: ScimTokenKind;\n /** For `identifier`/`string`/`op`: the textual value. For `number`: numeric. */\n value: string | number | boolean | null;\n /** Source position where the token starts. */\n start: number;\n}\n\nconst COMPARISON_OPS = new Set(['eq', 'ne', 'co', 'sw', 'ew', 'gt', 'ge', 'lt', 'le', 'pr']);\n\n/**\n * Tokenize a SCIM filter expression into a stream of {@link ScimToken}s.\n * Throws a `400 invalidFilter` SCIM error on malformed input.\n */\nexport const tokenizeScimFilter = (input: string): ScimToken[] => {\n const tokens: ScimToken[] = [];\n let i = 0;\n\n while (i < input.length) {\n const ch = input[i]!;\n\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n i += 1;\n continue;\n }\n\n if (ch === '(') {\n tokens.push({ kind: 'lparen', value: '(', start: i });\n i += 1;\n continue;\n }\n if (ch === ')') {\n tokens.push({ kind: 'rparen', value: ')', start: i });\n i += 1;\n continue;\n }\n if (ch === '[') {\n tokens.push({ kind: 'lbracket', value: '[', start: i });\n i += 1;\n continue;\n }\n if (ch === ']') {\n tokens.push({ kind: 'rbracket', value: ']', start: i });\n i += 1;\n continue;\n }\n\n if (ch === '\"') {\n const start = i;\n i += 1;\n let value = '';\n while (i < input.length && input[i] !== '\"') {\n if (input[i] === '\\\\' && i + 1 < input.length) {\n const next = input[i + 1]!;\n if (next === '\"' || next === '\\\\' || next === '/') {\n value += next;\n i += 2;\n continue;\n }\n if (next === 'n') { value += '\\n'; i += 2; continue; }\n if (next === 't') { value += '\\t'; i += 2; continue; }\n if (next === 'r') { value += '\\r'; i += 2; continue; }\n if (next === 'b') { value += '\\b'; i += 2; continue; }\n if (next === 'f') { value += '\\f'; i += 2; continue; }\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: i, message: `Unsupported escape sequence \\\\${next}` });\n }\n value += input[i];\n i += 1;\n }\n if (i >= input.length) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: start, message: 'Unterminated string literal' });\n }\n i += 1; // consume closing quote\n tokens.push({ kind: 'string', value, start });\n continue;\n }\n\n if (ch === '-' || (ch >= '0' && ch <= '9')) {\n const start = i;\n let raw = '';\n if (ch === '-') {\n raw += ch;\n i += 1;\n }\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n if (input[i] === '.') {\n raw += '.';\n i += 1;\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n }\n if (input[i] === 'e' || input[i] === 'E') {\n raw += input[i];\n i += 1;\n if (input[i] === '+' || input[i] === '-') {\n raw += input[i];\n i += 1;\n }\n while (i < input.length && /[0-9]/.test(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n }\n const num = Number(raw);\n if (Number.isNaN(num)) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: start, message: `Invalid numeric literal \"${raw}\"` });\n }\n tokens.push({ kind: 'number', value: num, start });\n continue;\n }\n\n if (isIdentifierStart(ch)) {\n const start = i;\n let raw = '';\n while (i < input.length && isIdentifierPart(input[i]!)) {\n raw += input[i];\n i += 1;\n }\n const lower = raw.toLowerCase();\n switch (lower) {\n case 'true':\n tokens.push({ kind: 'true', value: true, start });\n continue;\n case 'false':\n tokens.push({ kind: 'false', value: false, start });\n continue;\n case 'null':\n tokens.push({ kind: 'null', value: null, start });\n continue;\n case 'and':\n case 'or':\n case 'not':\n tokens.push({ kind: lower, value: lower, start });\n continue;\n }\n if (COMPARISON_OPS.has(lower)) {\n tokens.push({ kind: 'op', value: lower, start });\n continue;\n }\n tokens.push({ kind: 'identifier', value: raw, start });\n continue;\n }\n\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ position: i, message: `Unexpected character \"${ch}\"` });\n }\n\n return tokens;\n};\n\nconst isIdentifierStart = (ch: string): boolean => /[A-Za-z_$]/.test(ch);\n\nconst isIdentifierPart = (ch: string): boolean => /[A-Za-z0-9_.\\-:$]/.test(ch);\n","import { scimError } from '../errors/scim.error.js';\nimport type { ScimFilterNode, ScimComparisonOperator } from './filter.ast.js';\nimport { tokenizeScimFilter, type ScimToken } from './filter.tokenizer.js';\n\n/**\n * Parse a SCIM filter expression (RFC 7644 §3.4.2.2) into a typed AST.\n * Throws a `400 invalidFilter` SCIM error on malformed input.\n *\n * Operator precedence (highest first):\n * 1. parentheses, value-path brackets, `not(...)`\n * 2. comparison\n * 3. `and`\n * 4. `or`\n */\nexport const parseScimFilter = (input: string): ScimFilterNode => {\n const trimmed = input.trim();\n if (trimmed.length === 0) {\n throw scimError(400, 'invalidFilter', 'Bad Request').withDetails({ message: 'Filter is empty' });\n }\n const tokens = tokenizeScimFilter(trimmed);\n const parser = new Parser(tokens);\n const node = parser.parseOr();\n parser.expectEnd();\n return node;\n};\n\nclass Parser {\n private pos = 0;\n\n constructor(private readonly tokens: ScimToken[]) {}\n\n parseOr(): ScimFilterNode {\n let left = this.parseAnd();\n while (this.peek()?.kind === 'or') {\n this.consume();\n const right = this.parseAnd();\n left = { kind: 'logical', operator: 'or', left, right };\n }\n return left;\n }\n\n parseAnd(): ScimFilterNode {\n let left = this.parseUnary();\n while (this.peek()?.kind === 'and') {\n this.consume();\n const right = this.parseUnary();\n left = { kind: 'logical', operator: 'and', left, right };\n }\n return left;\n }\n\n parseUnary(): ScimFilterNode {\n const token = this.peek();\n if (token?.kind === 'not') {\n this.consume();\n this.expect('lparen', 'Expected \"(\" after \"not\"');\n const inner = this.parseOr();\n this.expect('rparen', 'Expected \")\" to close \"not(...)\"');\n return { kind: 'not', filter: inner };\n }\n if (token?.kind === 'lparen') {\n this.consume();\n const inner = this.parseOr();\n this.expect('rparen', 'Expected \")\"');\n return inner;\n }\n return this.parseComparisonOrValuePath();\n }\n\n parseComparisonOrValuePath(): ScimFilterNode {\n const token = this.peek();\n if (!token || token.kind !== 'identifier') {\n throw this.error(token, 'Expected attribute path');\n }\n this.consume();\n const attribute = String(token.value);\n\n const next = this.peek();\n if (next?.kind === 'lbracket') {\n this.consume();\n const inner = this.parseOr();\n this.expect('rbracket', 'Expected \"]\" to close value-path filter');\n return { kind: 'valuePath', attribute, filter: inner };\n }\n\n if (!next || next.kind !== 'op') {\n throw this.error(next, 'Expected comparison operator');\n }\n this.consume();\n const operator = String(next.value) as ScimComparisonOperator;\n\n if (operator === 'pr') {\n return { kind: 'comparison', attribute, operator };\n }\n\n const valueToken = this.peek();\n if (!valueToken) {\n throw this.error(valueToken, `Expected value after operator \"${operator}\"`);\n }\n this.consume();\n\n if (valueToken.kind === 'string' || valueToken.kind === 'number' || valueToken.kind === 'true' || valueToken.kind === 'false' || valueToken.kind === 'null') {\n return { kind: 'comparison', attribute, operator, value: valueToken.value as string | number | boolean | null };\n }\n throw this.error(valueToken, `Expected literal value after operator \"${operator}\"`);\n }\n\n expectEnd(): void {\n const remaining = this.peek();\n if (remaining) {\n throw this.error(remaining, 'Unexpected trailing tokens');\n }\n }\n\n private peek(): ScimToken | undefined {\n return this.tokens[this.pos];\n }\n\n private consume(): ScimToken | undefined {\n const token = this.tokens[this.pos];\n this.pos += 1;\n return token;\n }\n\n private expect(kind: ScimToken['kind'], message: string): ScimToken {\n const token = this.peek();\n if (!token || token.kind !== kind) {\n throw this.error(token, message);\n }\n this.consume();\n return token;\n }\n\n private error(token: ScimToken | undefined, message: string) {\n return scimError(400, 'invalidFilter', 'Bad Request').withDetails({\n message,\n position: token?.start ?? -1,\n });\n }\n}\n","import { scimError } from '../errors/scim.error.js';\nimport { parseScimFilter } from '../filter/filter.parser.js';\nimport type { ScimFilterNode } from '../filter/filter.ast.js';\nimport type { ScimPatchOp, ScimPatchOpKind } from '../types/patch.op.js';\n\n/**\n * Apply a SCIM PATCH operation list to a resource (RFC 7644 §3.5.2).\n * Returns a *new* object — the input is not mutated.\n *\n * Supports the standard `add` / `replace` / `remove` operations and the path\n * mini-language including dotted sub-attributes and value-path filters\n * (e.g. `emails[type eq \"work\"].value`).\n */\nexport const applyScimPatch = <T extends Record<string, unknown>>(resource: T, ops: ScimPatchOp[]): T => {\n // Deep-clone so mutations don't leak to the caller.\n let next: Record<string, unknown> = structuredClone(resource);\n for (const op of ops) {\n next = applyOne(next, op);\n }\n return next as T;\n};\n\nconst applyOne = (resource: Record<string, unknown>, op: ScimPatchOp): Record<string, unknown> => {\n const kind = normaliseOpKind(op.op);\n\n if (op.path === undefined || op.path === '') {\n if (kind === 'remove') {\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: '\"remove\" requires a path' });\n }\n if (typeof op.value !== 'object' || op.value === null || Array.isArray(op.value)) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: 'Pathless add/replace requires an object value' });\n }\n return mergeObject(resource, op.value as Record<string, unknown>, kind);\n }\n\n const path = parsePatchPath(op.path);\n return applyAtPath(resource, path, kind, op.value);\n};\n\nconst normaliseOpKind = (op: ScimPatchOp['op']): ScimPatchOpKind => {\n const lower = String(op).toLowerCase();\n if (lower === 'add' || lower === 'replace' || lower === 'remove') return lower;\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: `Unknown PATCH op \"${op}\"` });\n};\n\ninterface ParsedPath {\n /** Top-level attribute, possibly with sub-attribute segments. */\n segments: string[];\n /** Optional value-path filter applied to the leaf attribute. */\n filter?: ScimFilterNode;\n /** Sub-attribute applied after the value-path filter (e.g. `.value`). */\n filterSubAttr?: string;\n}\n\nconst parsePatchPath = (raw: string): ParsedPath => {\n // Split off optional `[...]filter` segment.\n const bracketStart = raw.indexOf('[');\n if (bracketStart === -1) {\n return { segments: raw.split('.').filter(Boolean) };\n }\n\n const bracketEnd = findMatchingBracket(raw, bracketStart);\n if (bracketEnd === -1) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Unterminated value-path filter' });\n }\n\n const head = raw.slice(0, bracketStart);\n const filterSrc = raw.slice(bracketStart + 1, bracketEnd);\n const tail = raw.slice(bracketEnd + 1);\n\n const segments = head.split('.').filter(Boolean);\n if (segments.length === 0) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Value-path filter requires a target attribute' });\n }\n\n const filter = parseScimFilter(filterSrc);\n\n let filterSubAttr: string | undefined;\n if (tail.length > 0) {\n if (!tail.startsWith('.')) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Expected \".\" after value-path filter' });\n }\n filterSubAttr = tail.slice(1);\n if (filterSubAttr.length === 0 || filterSubAttr.includes('[')) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Invalid sub-attribute after value-path filter' });\n }\n }\n\n return { segments, filter, filterSubAttr };\n};\n\nconst findMatchingBracket = (input: string, openIndex: number): number => {\n let depth = 0;\n let inString = false;\n for (let i = openIndex; i < input.length; i += 1) {\n const ch = input[i]!;\n if (inString) {\n if (ch === '\\\\') { i += 1; continue; }\n if (ch === '\"') inString = false;\n continue;\n }\n if (ch === '\"') { inString = true; continue; }\n if (ch === '[') depth += 1;\n else if (ch === ']') {\n depth -= 1;\n if (depth === 0) return i;\n }\n }\n return -1;\n};\n\nconst applyAtPath = (resource: Record<string, unknown>, path: ParsedPath, kind: ScimPatchOpKind, value: unknown): Record<string, unknown> => {\n const [head, ...rest] = path.segments;\n if (!head) {\n throw scimError(400, 'invalidPath', 'Bad Request').withDetails({ message: 'Empty PATCH path' });\n }\n\n if (path.filter && rest.length === 0) {\n return applyFilteredOp(resource, head, path.filter, path.filterSubAttr, kind, value);\n }\n\n if (rest.length === 0) {\n return applySimpleOp(resource, head, kind, value);\n }\n\n const child = resource[head];\n const childObj: Record<string, unknown> = isPlainObject(child) ? { ...child } : {};\n const updated = applyAtPath(childObj, { ...path, segments: rest }, kind, value);\n return { ...resource, [head]: updated };\n};\n\nconst applySimpleOp = (resource: Record<string, unknown>, attr: string, kind: ScimPatchOpKind, value: unknown): Record<string, unknown> => {\n if (kind === 'remove') {\n const next = { ...resource };\n delete next[attr];\n return next;\n }\n\n if (kind === 'replace') {\n return { ...resource, [attr]: value };\n }\n\n // add: for multi-valued attributes, append; otherwise replace.\n const existing = resource[attr];\n if (Array.isArray(existing) && Array.isArray(value)) {\n return { ...resource, [attr]: [...existing, ...value] };\n }\n if (Array.isArray(existing) && value !== undefined) {\n return { ...resource, [attr]: [...existing, value] };\n }\n if (existing === undefined && Array.isArray(value)) {\n return { ...resource, [attr]: [...value] };\n }\n if (isPlainObject(existing) && isPlainObject(value)) {\n return { ...resource, [attr]: { ...existing, ...value } };\n }\n return { ...resource, [attr]: value };\n};\n\nconst applyFilteredOp = (\n resource: Record<string, unknown>,\n attr: string,\n filter: ScimFilterNode,\n subAttr: string | undefined,\n kind: ScimPatchOpKind,\n value: unknown,\n): Record<string, unknown> => {\n const collection = resource[attr];\n if (!Array.isArray(collection)) {\n if (kind === 'add') {\n // Per RFC, add on a non-existent target creates it. For value-path on a\n // missing collection, the closest behaviour is to materialise the matched\n // item from the supplied value.\n return { ...resource, [attr]: [{ ...(value as Record<string, unknown>) }] };\n }\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: `Attribute \"${attr}\" is not multi-valued` });\n }\n\n const matched: number[] = [];\n collection.forEach((item, index) => {\n if (isPlainObject(item) && evaluateFilter(item, filter)) matched.push(index);\n });\n\n if (matched.length === 0 && kind !== 'add') {\n throw scimError(400, 'noTarget', 'Bad Request').withDetails({ message: `No items matched value-path filter on \"${attr}\"` });\n }\n\n if (kind === 'remove') {\n const next = collection.filter((_, idx) => !matched.includes(idx));\n return { ...resource, [attr]: next };\n }\n\n if (kind === 'add' && matched.length === 0) {\n const seed = isPlainObject(value) ? { ...value } : { value };\n return { ...resource, [attr]: [...collection, seed] };\n }\n\n const next = collection.map((item, idx) => {\n if (!matched.includes(idx) || !isPlainObject(item)) return item;\n if (subAttr !== undefined) {\n if (kind === 'replace' || kind === 'add') {\n return { ...item, [subAttr]: value };\n }\n }\n if (kind === 'replace') {\n return isPlainObject(value) ? { ...item, ...value } : value;\n }\n // add: shallow merge\n return isPlainObject(value) ? { ...item, ...value } : item;\n });\n return { ...resource, [attr]: next };\n};\n\nconst mergeObject = (target: Record<string, unknown>, source: Record<string, unknown>, kind: ScimPatchOpKind): Record<string, unknown> => {\n if (kind === 'replace') {\n return { ...target, ...source };\n }\n // add: deep-merge for nested objects, append for arrays\n const out: Record<string, unknown> = { ...target };\n for (const [key, val] of Object.entries(source)) {\n const existing = out[key];\n if (Array.isArray(existing) && Array.isArray(val)) {\n out[key] = [...existing, ...val];\n } else if (isPlainObject(existing) && isPlainObject(val)) {\n out[key] = mergeObject(existing, val, kind);\n } else {\n out[key] = val;\n }\n }\n return out;\n};\n\nconst evaluateFilter = (item: Record<string, unknown>, filter: ScimFilterNode): boolean => {\n switch (filter.kind) {\n case 'comparison':\n return evaluateComparison(item, filter.attribute, filter.operator, filter.value);\n case 'logical':\n return filter.operator === 'and'\n ? evaluateFilter(item, filter.left) && evaluateFilter(item, filter.right)\n : evaluateFilter(item, filter.left) || evaluateFilter(item, filter.right);\n case 'not':\n return !evaluateFilter(item, filter.filter);\n case 'valuePath': {\n const nested = item[filter.attribute];\n if (!Array.isArray(nested)) return false;\n return nested.some(child => isPlainObject(child) && evaluateFilter(child, filter.filter));\n }\n }\n};\n\nconst evaluateComparison = (item: Record<string, unknown>, attr: string, op: string, value: unknown): boolean => {\n const segments = attr.split('.');\n let current: unknown = item;\n for (const seg of segments) {\n if (!isPlainObject(current)) return false;\n current = current[seg];\n }\n if (op === 'pr') return current !== undefined && current !== null && current !== '';\n if (current === undefined || current === null) return false;\n\n switch (op) {\n case 'eq':\n return current === value;\n case 'ne':\n return current !== value;\n case 'co':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().includes(value.toLowerCase());\n case 'sw':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().startsWith(value.toLowerCase());\n case 'ew':\n return typeof current === 'string' && typeof value === 'string' && current.toLowerCase().endsWith(value.toLowerCase());\n case 'gt':\n return compareScalar(current, value) > 0;\n case 'ge':\n return compareScalar(current, value) >= 0;\n case 'lt':\n return compareScalar(current, value) < 0;\n case 'le':\n return compareScalar(current, value) <= 0;\n default:\n return false;\n }\n};\n\nconst compareScalar = (a: unknown, b: unknown): number => {\n if (typeof a === 'number' && typeof b === 'number') return a - b;\n const sa = String(a);\n const sb = String(b);\n if (sa < sb) return -1;\n if (sa > sb) return 1;\n return 0;\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n","import type { ScimUser } from '../types/scim.user.js';\nimport type { ScimListQuery, ScimListResult } from './repository.types.js';\n\n/**\n * Storage contract for SCIM `User` resources. The package ships only this\n * abstract class — implement it against your datastore (Kysely, Prisma,\n * Drizzle, in-memory) and pass the instance to {@link createScimRouter}.\n *\n * Implementations are responsible for:\n * - Translating the parsed filter AST in {@link ScimListQuery.filter} into a\n * native query.\n * - Honouring `startIndex` (1-based) and `count` for pagination.\n * - Returning the total number of matching resources, not just the page size.\n * - Persisting `meta.created` / `meta.lastModified` timestamps.\n *\n * Modeled as an abstract class so the runtime reference is a valid InjectKit\n * token (interfaces aren't preserved at runtime).\n */\nexport abstract class ScimUserRepository {\n /** Look up a user by server-assigned id. Return `undefined` if not found. */\n abstract findById(id: string): Promise<ScimUser | undefined>;\n\n /** Look up a user by `userName` (case-insensitive per RFC 7643). */\n abstract findByUserName(userName: string): Promise<ScimUser | undefined>;\n\n /** Look up a user by `externalId` (client-supplied identifier). */\n abstract findByExternalId(externalId: string): Promise<ScimUser | undefined>;\n\n /** List users matching a parsed query. */\n abstract list(query: ScimListQuery): Promise<ScimListResult<ScimUser>>;\n\n /** Persist a fully-formed user. `id`, `schemas`, and `meta` are already populated by {@link ScimUserService}. */\n abstract create(user: ScimUser): Promise<ScimUser>;\n\n /** Replace the entirety of an existing user (PUT semantics). */\n abstract replace(id: string, user: ScimUser): Promise<ScimUser>;\n\n /** Delete a user by id. Implementations may treat missing ids as a no-op. */\n abstract delete(id: string): Promise<void>;\n}\n","import type { ScimGroup } from '../types/scim.group.js';\nimport type { ScimListQuery, ScimListResult } from './repository.types.js';\n\n/**\n * Storage contract for SCIM `Group` resources. See\n * {@link ScimUserRepository} for general implementation guidance.\n */\nexport abstract class ScimGroupRepository {\n /** Look up a group by server-assigned id. */\n abstract findById(id: string): Promise<ScimGroup | undefined>;\n\n /** Look up a group by `displayName`. */\n abstract findByDisplayName(displayName: string): Promise<ScimGroup | undefined>;\n\n /** Look up a group by `externalId`. */\n abstract findByExternalId(externalId: string): Promise<ScimGroup | undefined>;\n\n /** List groups matching a parsed query. */\n abstract list(query: ScimListQuery): Promise<ScimListResult<ScimGroup>>;\n\n /** Persist a new group. */\n abstract create(group: ScimGroup): Promise<ScimGroup>;\n\n /** Replace the entirety of an existing group (PUT semantics). */\n abstract replace(id: string, group: ScimGroup): Promise<ScimGroup>;\n\n /** Delete a group by id. */\n abstract delete(id: string): Promise<void>;\n}\n","import { randomUUID } from 'node:crypto';\nimport { DateTime } from 'luxon';\nimport { Injectable } from 'injectkit';\nimport { Logger } from '@maroonedsoftware/logger';\nimport { ScimUserRepository } from '../repositories/scim.user.repository.js';\nimport type { ScimListQuery, ScimListResult } from '../repositories/repository.types.js';\nimport type { ScimUser } from '../types/scim.user.js';\nimport type { ScimPatchOp } from '../types/patch.op.js';\nimport { applyScimPatch } from '../patch/patch.applier.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { UserSchemaId } from '../schemas/user.schema.js';\nimport { EnterpriseUserSchemaId } from '../schemas/enterprise.user.schema.js';\n\n/**\n * Application service wrapping a {@link ScimUserRepository}. Owns id and meta\n * assignment, uniqueness enforcement, and PATCH application — keeping the\n * repository focused on storage concerns.\n */\n@Injectable()\nexport class ScimUserService {\n constructor(\n private readonly repository: ScimUserRepository,\n private readonly logger: Logger,\n ) {}\n\n /**\n * Fetch a single user by id.\n *\n * @throws {ScimError} 404 if no user exists with the given id.\n */\n async get(id: string): Promise<ScimUser> {\n const user = await this.repository.findById(id);\n if (!user) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n return user;\n }\n\n /**\n * List users matching a parsed SCIM query, returning the page plus the\n * total number of matches (for the `totalResults` envelope field).\n */\n async list(query: ScimListQuery): Promise<ScimListResult<ScimUser>> {\n return this.repository.list(query);\n }\n\n /**\n * Create a new user. Assigns a server-generated `id`, fills `meta.created`\n * and `meta.lastModified`, and ensures the resource's `schemas` includes the\n * core User URN (and the EnterpriseUser URN when the extension is present).\n *\n * @throws {ScimError} 400 `invalidValue` when `userName` is missing.\n * @throws {ScimError} 409 `uniqueness` when `userName` already exists.\n */\n async create(payload: Partial<ScimUser>): Promise<ScimUser> {\n if (!payload.userName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"userName\" is required' });\n }\n const existing = await this.repository.findByUserName(payload.userName);\n if (existing) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `userName \"${payload.userName}\" already exists` });\n }\n const now = DateTime.utc().toISO();\n const id = payload.id ?? randomUUID();\n const user: ScimUser = {\n ...payload,\n id,\n userName: payload.userName,\n schemas: this.normaliseSchemas(payload.schemas, payload),\n meta: {\n resourceType: 'User',\n created: now,\n lastModified: now,\n location: `/Users/${id}`,\n },\n };\n this.logger.debug('scim: creating user', { id, userName: user.userName });\n return this.repository.create(user);\n }\n\n /**\n * Replace an existing user wholesale (PUT semantics). Preserves the original\n * `id` and `meta.created`; updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n * @throws {ScimError} 400 `invalidValue` when `userName` is missing.\n * @throws {ScimError} 409 `uniqueness` when changing `userName` would collide\n * with another existing user.\n */\n async replace(id: string, payload: Partial<ScimUser>): Promise<ScimUser> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n if (!payload.userName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"userName\" is required' });\n }\n if (payload.userName !== existing.userName) {\n const conflict = await this.repository.findByUserName(payload.userName);\n if (conflict && conflict.id !== id) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `userName \"${payload.userName}\" already exists` });\n }\n }\n const now = DateTime.utc().toISO();\n const user: ScimUser = {\n ...payload,\n id,\n userName: payload.userName,\n schemas: this.normaliseSchemas(payload.schemas, payload),\n meta: {\n ...existing.meta,\n lastModified: now,\n location: existing.meta.location ?? `/Users/${id}`,\n },\n };\n return this.repository.replace(id, user);\n }\n\n /**\n * Apply a sequence of SCIM PATCH ops (RFC 7644 §3.5.2) and persist the\n * result via `replace`. Updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n * @throws {ScimError} 400 propagated from {@link applyScimPatch} for invalid\n * paths, unknown ops, or no-target failures.\n */\n async patch(id: string, ops: ScimPatchOp[]): Promise<ScimUser> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n const patched = applyScimPatch(existing as unknown as Record<string, unknown>, ops) as unknown as ScimUser;\n patched.id = existing.id;\n patched.meta = {\n ...existing.meta,\n lastModified: DateTime.utc().toISO(),\n };\n return this.repository.replace(id, patched);\n }\n\n /**\n * Delete a user by id.\n *\n * @throws {ScimError} 404 when no user exists with the given id.\n */\n async delete(id: string): Promise<void> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `User \"${id}\" not found` });\n await this.repository.delete(id);\n }\n\n private normaliseSchemas(provided: string[] | undefined, payload: Partial<ScimUser>): string[] {\n const schemas = new Set<string>(provided ?? []);\n schemas.add(UserSchemaId);\n if (payload[EnterpriseUserSchemaId]) {\n schemas.add(EnterpriseUserSchemaId);\n }\n return Array.from(schemas);\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { DateTime } from 'luxon';\nimport { Injectable } from 'injectkit';\nimport { Logger } from '@maroonedsoftware/logger';\nimport { ScimGroupRepository } from '../repositories/scim.group.repository.js';\nimport type { ScimListQuery, ScimListResult } from '../repositories/repository.types.js';\nimport type { ScimGroup } from '../types/scim.group.js';\nimport type { ScimPatchOp } from '../types/patch.op.js';\nimport { applyScimPatch } from '../patch/patch.applier.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { GroupSchemaId } from '../schemas/group.schema.js';\n\n/**\n * Application service wrapping a {@link ScimGroupRepository}. Mirrors\n * {@link ScimUserService}: id/meta assignment, uniqueness on `displayName`,\n * and PATCH application.\n */\n@Injectable()\nexport class ScimGroupService {\n constructor(\n private readonly repository: ScimGroupRepository,\n private readonly logger: Logger,\n ) {}\n\n /**\n * Fetch a single group by id.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n */\n async get(id: string): Promise<ScimGroup> {\n const group = await this.repository.findById(id);\n if (!group) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n return group;\n }\n\n /**\n * List groups matching a parsed SCIM query, returning the page plus the\n * total number of matches.\n */\n async list(query: ScimListQuery): Promise<ScimListResult<ScimGroup>> {\n return this.repository.list(query);\n }\n\n /**\n * Create a new group. Assigns a server-generated `id` and fills `meta`\n * timestamps.\n *\n * @throws {ScimError} 400 `invalidValue` when `displayName` is missing.\n * @throws {ScimError} 409 `uniqueness` when `displayName` already exists.\n */\n async create(payload: Partial<ScimGroup>): Promise<ScimGroup> {\n if (!payload.displayName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"displayName\" is required' });\n }\n const existing = await this.repository.findByDisplayName(payload.displayName);\n if (existing) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `displayName \"${payload.displayName}\" already exists` });\n }\n const now = DateTime.utc().toISO();\n const id = payload.id ?? randomUUID();\n const group: ScimGroup = {\n ...payload,\n id,\n displayName: payload.displayName,\n schemas: this.normaliseSchemas(payload.schemas),\n meta: {\n resourceType: 'Group',\n created: now,\n lastModified: now,\n location: `/Groups/${id}`,\n },\n };\n this.logger.debug('scim: creating group', { id, displayName: group.displayName });\n return this.repository.create(group);\n }\n\n /**\n * Replace an existing group wholesale (PUT semantics). Preserves `id` and\n * `meta.created`; updates `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n * @throws {ScimError} 400 `invalidValue` when `displayName` is missing.\n * @throws {ScimError} 409 `uniqueness` when changing `displayName` would collide.\n */\n async replace(id: string, payload: Partial<ScimGroup>): Promise<ScimGroup> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n if (!payload.displayName) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"displayName\" is required' });\n }\n if (payload.displayName !== existing.displayName) {\n const conflict = await this.repository.findByDisplayName(payload.displayName);\n if (conflict && conflict.id !== id) {\n throw scimError(409, 'uniqueness', 'Conflict').withDetails({ message: `displayName \"${payload.displayName}\" already exists` });\n }\n }\n const now = DateTime.utc().toISO();\n const group: ScimGroup = {\n ...payload,\n id,\n displayName: payload.displayName,\n schemas: this.normaliseSchemas(payload.schemas),\n meta: {\n ...existing.meta,\n lastModified: now,\n location: existing.meta.location ?? `/Groups/${id}`,\n },\n };\n return this.repository.replace(id, group);\n }\n\n /**\n * Apply a sequence of SCIM PATCH ops and persist the result. Updates\n * `meta.lastModified`.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n * @throws {ScimError} 400 propagated from {@link applyScimPatch}.\n */\n async patch(id: string, ops: ScimPatchOp[]): Promise<ScimGroup> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n const patched = applyScimPatch(existing as unknown as Record<string, unknown>, ops) as unknown as ScimGroup;\n patched.id = existing.id;\n patched.meta = {\n ...existing.meta,\n lastModified: DateTime.utc().toISO(),\n };\n return this.repository.replace(id, patched);\n }\n\n /**\n * Delete a group by id.\n *\n * @throws {ScimError} 404 when no group exists with the given id.\n */\n async delete(id: string): Promise<void> {\n const existing = await this.repository.findById(id);\n if (!existing) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Group \"${id}\" not found` });\n await this.repository.delete(id);\n }\n\n private normaliseSchemas(provided: string[] | undefined): string[] {\n const schemas = new Set<string>(provided ?? []);\n schemas.add(GroupSchemaId);\n return Array.from(schemas);\n }\n}\n","import { Injectable } from 'injectkit';\nimport { buildServiceProviderConfig, type ScimServiceProviderConfig, type ScimServiceProviderConfigOptions } from '../schemas/service.provider.config.schema.js';\nimport { coreSchemas } from '../schemas/index.js';\nimport { userResourceType, groupResourceType, type ScimResourceType } from '../schemas/resource.type.schema.js';\nimport type { ScimSchema } from '../schemas/schema.types.js';\nimport { scimError } from '../errors/scim.error.js';\n\n/**\n * Serves the SCIM discovery endpoints: `/ServiceProviderConfig`, `/Schemas`,\n * and `/ResourceTypes`. The config is fixed at construction time — what the\n * server advertises must match what the router actually implements.\n */\n@Injectable()\nexport class ScimServiceProviderService {\n private readonly config: ScimServiceProviderConfig;\n private readonly schemas: ScimSchema[];\n private readonly resourceTypes: ScimResourceType[];\n\n constructor(options: ScimServiceProviderConfigOptions = {}) {\n this.config = buildServiceProviderConfig(options);\n this.schemas = coreSchemas;\n this.resourceTypes = [userResourceType, groupResourceType];\n }\n\n /** The materialised `/ServiceProviderConfig` response. */\n getServiceProviderConfig(): ScimServiceProviderConfig {\n return this.config;\n }\n\n /** Every schema known to this server, served from `/Schemas`. */\n listSchemas(): ScimSchema[] {\n return this.schemas;\n }\n\n /**\n * Look up a single schema by its URN.\n *\n * @throws {ScimError} 404 if the URN is not registered.\n */\n getSchema(id: string): ScimSchema {\n const found = this.schemas.find(s => s.id === id);\n if (!found) throw scimError(404, undefined, 'Not Found').withDetails({ message: `Schema \"${id}\" not found` });\n return found;\n }\n\n /** Every resource type known to this server, served from `/ResourceTypes`. */\n listResourceTypes(): ScimResourceType[] {\n return this.resourceTypes;\n }\n\n /**\n * Look up a single resource type by id (e.g. `User`, `Group`).\n *\n * @throws {ScimError} 404 if the id is not registered.\n */\n getResourceType(id: string): ScimResourceType {\n const found = this.resourceTypes.find(rt => rt.id === id);\n if (!found) throw scimError(404, undefined, 'Not Found').withDetails({ message: `ResourceType \"${id}\" not found` });\n return found;\n }\n}\n","import type { ServerKitMiddleware } from '@maroonedsoftware/koa';\nimport { scimError } from '../errors/scim.error.js';\n\n/** SCIM media type per RFC 7644 §3.8. */\nexport const SCIM_MEDIA_TYPE = 'application/scim+json';\n\n/**\n * Enforce that mutating SCIM requests carry `Content-Type: application/scim+json`\n * (or `application/json`, which the spec accepts for backward compatibility),\n * and tag the response so it serialises with the SCIM media type.\n */\nexport const scimContentTypeMiddleware = (): ServerKitMiddleware => {\n return async (ctx, next) => {\n const method = ctx.method.toUpperCase();\n if (method === 'POST' || method === 'PUT' || method === 'PATCH') {\n const contentType = (ctx.request.headers['content-type'] ?? '').toLowerCase();\n if (contentType && !contentType.includes(SCIM_MEDIA_TYPE) && !contentType.includes('application/json')) {\n throw scimError(415, undefined, 'Unsupported Media Type').withDetails({\n message: `Content-Type must be ${SCIM_MEDIA_TYPE}`,\n });\n }\n }\n await next();\n if (ctx.body !== undefined && ctx.body !== null) {\n ctx.type = SCIM_MEDIA_TYPE;\n }\n };\n};\n","import type { ServerKitMiddleware } from '@maroonedsoftware/koa';\nimport { IsHttpError, IsServerkitError } from '@maroonedsoftware/errors';\nimport { IsScimError, ScimError, ScimErrorSchema } from '../errors/scim.error.js';\nimport { SCIM_MEDIA_TYPE } from './scim.content.type.middleware.js';\n\n/**\n * SCIM-shaped error middleware. Catches errors thrown by downstream handlers\n * and renders them as the RFC 7644 §3.12 envelope with `Content-Type:\n * application/scim+json`.\n *\n * Mount this *inside* a SCIM sub-router (or in front of the SCIM router on\n * its own Koa instance) — do not replace the application-wide\n * `errorMiddleware` from `@maroonedsoftware/koa` with it.\n */\nexport const scimErrorMiddleware = (): ServerKitMiddleware => {\n return async (ctx, next) => {\n try {\n await next();\n if (ctx.status === 404 && !ctx.body) {\n const status = 404;\n ctx.status = status;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = {\n schemas: [ScimErrorSchema],\n status: String(status),\n detail: `Not Found: ${ctx.URL.pathname}`,\n };\n }\n } catch (error) {\n if (IsScimError(error)) {\n respondWithScimError(ctx, error);\n ctx.app.emit('error', error, ctx);\n return;\n }\n if (IsHttpError(error)) {\n respondWithScimError(ctx, new ScimError(error.statusCode).withDetails(error.details ?? {}).withCause(error));\n ctx.app.emit('error', error, ctx);\n return;\n }\n const status = 500;\n const detail = IsServerkitError(error) ? error.message : 'Internal Server Error';\n ctx.status = status;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = {\n schemas: [ScimErrorSchema],\n status: String(status),\n detail,\n };\n ctx.app.emit('error', error, ctx);\n }\n };\n};\n\nconst respondWithScimError = (ctx: Parameters<ServerKitMiddleware>[0], error: ScimError): void => {\n ctx.status = error.statusCode;\n ctx.type = SCIM_MEDIA_TYPE;\n ctx.body = error.toScimBody();\n if (error.headers) {\n for (const [name, value] of Object.entries(error.headers)) {\n ctx.set(name, value);\n }\n }\n};\n","import type { ServerKitRouterMiddleware } from '@maroonedsoftware/koa';\nimport { invalidAuthenticationSession } from '@maroonedsoftware/authentication';\nimport { scimError } from '../errors/scim.error.js';\n\n/**\n * Router middleware enforcing that the current request carries a SCIM scope\n * on its authentication session. The scope list is read from\n * `ctx.authenticationSession.claims.scimScopes` — a string array the consumer\n * populates when minting the session for the bearer token.\n *\n * Wildcard scope `*` in the session grants every check.\n */\nexport const requireScimScope = (scope: string): ServerKitRouterMiddleware => {\n return async (ctx, next) => {\n const session = ctx.authenticationSession;\n if (!session || session === invalidAuthenticationSession) {\n throw scimError(401, undefined, 'Unauthorized')\n .addHeader('WWW-Authenticate', 'Bearer error=\"invalid_token\"')\n .withDetails({ message: 'Missing or invalid bearer token' });\n }\n const granted = session.claims?.scimScopes;\n if (!Array.isArray(granted) || (!granted.includes('*') && !granted.includes(scope))) {\n throw scimError(403, 'insufficientScope', 'Forbidden').withDetails({ message: `Scope \"${scope}\" required` });\n }\n await next();\n };\n};\n","import type { ServerKitContext, ServerKitRouterMiddleware } from '@maroonedsoftware/koa';\nimport { bodyParserMiddleware, ServerKitRouter } from '@maroonedsoftware/koa';\nimport type Router from '@koa/router';\nimport { ScimUserService } from '../services/scim.user.service.js';\nimport { ScimGroupService } from '../services/scim.group.service.js';\nimport { ScimServiceProviderService } from '../services/scim.service.provider.service.js';\nimport type { ScimUser } from '../types/scim.user.js';\nimport type { ScimGroup } from '../types/scim.group.js';\nimport { type ScimPatchOp, type ScimPatchRequest, PatchOpSchema } from '../types/patch.op.js';\nimport { ListResponseSchema, type ScimListResponse } from '../types/list.response.js';\nimport { type ScimListQuery, type ScimSortOrder } from '../repositories/repository.types.js';\nimport { parseScimFilter } from '../filter/filter.parser.js';\nimport { scimError } from '../errors/scim.error.js';\nimport { SCIM_MEDIA_TYPE } from '../middleware/scim.content.type.middleware.js';\n\n/**\n * Options for {@link createScimRouter}. The caller constructs the three\n * services (wiring them to their backing repositories and a logger) and\n * hands them in.\n */\nexport interface CreateScimRouterOptions {\n /** Service handling all `/Users` endpoints. */\n userService: ScimUserService;\n /** Service handling all `/Groups` endpoints. */\n groupService: ScimGroupService;\n /** Service that owns `/Schemas`, `/ResourceTypes`, `/ServiceProviderConfig`. */\n serviceProviderService: ScimServiceProviderService;\n /** Optional middleware mounted on every route (e.g. `requireScimScope('users:read')`). */\n routeGuards?: ServerKitRouterMiddleware[];\n /**\n * Maximum page size returned from list endpoints. Defaults to the\n * `serviceProviderService` `filter.maxResults` value, falling back to 200.\n */\n maxResults?: number;\n}\n\n/**\n * Build a SCIM 2.0 server router. Mount it inside a Koa app that already has\n * `serverKitContextMiddleware` and `authenticationMiddleware` configured, and\n * use `scimErrorMiddleware()` instead of the default `errorMiddleware()` for\n * the SCIM mountpoint.\n *\n * Endpoints (RFC 7644 §3.4):\n * - `GET /Users` — list users (with `filter`, `startIndex`, `count`, `sortBy`, `sortOrder`)\n * - `POST /Users` — create user\n * - `GET /Users/:id` — fetch one user\n * - `PUT /Users/:id` — replace user\n * - `PATCH /Users/:id` — apply PATCH ops\n * - `DELETE /Users/:id` — delete user\n * - `POST /Users/.search` — list-via-POST so large filters can be sent in the body\n * - Same six endpoints for `/Groups` and `/Groups/.search`\n * - `GET /Schemas`, `GET /Schemas/:id`\n * - `GET /ResourceTypes`, `GET /ResourceTypes/:id`\n * - `GET /ServiceProviderConfig`\n */\nexport const createScimRouter = (options: CreateScimRouterOptions): Router<unknown, ServerKitContext> => {\n const router = ServerKitRouter();\n const guards = options.routeGuards ?? [];\n const json = bodyParserMiddleware([SCIM_MEDIA_TYPE, 'application/json']);\n const maxResults = options.maxResults ?? options.serviceProviderService.getServiceProviderConfig().filter.maxResults ?? 200;\n\n // Discovery endpoints — RFC 7644 §4 says these MAY be unauthenticated. Apply\n // the route guards anyway so the consumer can decide.\n router.get('/ServiceProviderConfig', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getServiceProviderConfig();\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/Schemas', ...guards, async ctx => {\n ctx.body = listEnvelope(options.serviceProviderService.listSchemas());\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/Schemas/:id', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getSchema(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/ResourceTypes', ...guards, async ctx => {\n ctx.body = listEnvelope(options.serviceProviderService.listResourceTypes());\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.get('/ResourceTypes/:id', ...guards, async ctx => {\n ctx.body = options.serviceProviderService.getResourceType(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n // Users\n router.get('/Users', ...guards, async ctx => {\n const query = parseListQueryFromUrl(ctx.query, maxResults);\n const result = await options.userService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Users/.search', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx);\n const query = parseListQueryFromBody(requestBody, maxResults);\n const result = await options.userService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Users', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimUser>;\n const created = await options.userService.create(payload);\n ctx.status = 201;\n ctx.body = created;\n ctx.type = SCIM_MEDIA_TYPE;\n if (created.meta.location) ctx.set('Location', created.meta.location);\n });\n\n router.get('/Users/:id', ...guards, async ctx => {\n ctx.body = await options.userService.get(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.put('/Users/:id', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimUser>;\n ctx.body = await options.userService.replace(ctx.params.id!, payload);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.patch('/Users/:id', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx) as Partial<ScimPatchRequest>;\n const ops = validatePatchRequest(requestBody);\n ctx.body = await options.userService.patch(ctx.params.id!, ops);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.delete('/Users/:id', ...guards, async ctx => {\n await options.userService.delete(ctx.params.id!);\n ctx.status = 204;\n });\n\n // Groups\n router.get('/Groups', ...guards, async ctx => {\n const query = parseListQueryFromUrl(ctx.query, maxResults);\n const result = await options.groupService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Groups/.search', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx);\n const query = parseListQueryFromBody(requestBody, maxResults);\n const result = await options.groupService.list(query);\n ctx.body = listEnvelope(result.resources, query, result.totalResults);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.post('/Groups', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimGroup>;\n const created = await options.groupService.create(payload);\n ctx.status = 201;\n ctx.body = created;\n ctx.type = SCIM_MEDIA_TYPE;\n if (created.meta.location) ctx.set('Location', created.meta.location);\n });\n\n router.get('/Groups/:id', ...guards, async ctx => {\n ctx.body = await options.groupService.get(ctx.params.id!);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.put('/Groups/:id', ...guards, json, async ctx => {\n const payload = takeRequestBody(ctx) as Partial<ScimGroup>;\n ctx.body = await options.groupService.replace(ctx.params.id!, payload);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.patch('/Groups/:id', ...guards, json, async ctx => {\n const requestBody = takeRequestBody(ctx) as Partial<ScimPatchRequest>;\n const ops = validatePatchRequest(requestBody);\n ctx.body = await options.groupService.patch(ctx.params.id!, ops);\n ctx.type = SCIM_MEDIA_TYPE;\n });\n\n router.delete('/Groups/:id', ...guards, async ctx => {\n await options.groupService.delete(ctx.params.id!);\n ctx.status = 204;\n });\n\n return router;\n};\n\n/**\n * `bodyParserMiddleware` writes the parsed request body to `ctx.body` (the\n * codebase convention). Move it into a local before the handler reassigns\n * `ctx.body` to the response.\n */\nconst takeRequestBody = (ctx: ServerKitContext): unknown => {\n const body = ctx.body;\n ctx.body = undefined;\n return body;\n};\n\nconst parseListQueryFromUrl = (query: ServerKitContext['query'], maxResults: number): ScimListQuery => {\n const filterRaw = pickStringParam(query, 'filter');\n return {\n filter: filterRaw ? parseScimFilter(filterRaw) : undefined,\n startIndex: parsePositiveInt(pickStringParam(query, 'startIndex'), 1),\n count: clamp(parsePositiveInt(pickStringParam(query, 'count'), maxResults), 0, maxResults),\n sortBy: pickStringParam(query, 'sortBy'),\n sortOrder: parseSortOrder(pickStringParam(query, 'sortOrder')),\n attributes: parseCsvParam(pickStringParam(query, 'attributes')),\n excludedAttributes: parseCsvParam(pickStringParam(query, 'excludedAttributes')),\n };\n};\n\nconst parseListQueryFromBody = (body: unknown, maxResults: number): ScimListQuery => {\n if (!isPlainObject(body)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: 'Search body must be a JSON object' });\n }\n const filterRaw = typeof body.filter === 'string' ? body.filter : undefined;\n return {\n filter: filterRaw ? parseScimFilter(filterRaw) : undefined,\n startIndex: typeof body.startIndex === 'number' && body.startIndex > 0 ? Math.floor(body.startIndex) : 1,\n count: clamp(typeof body.count === 'number' ? Math.floor(body.count) : maxResults, 0, maxResults),\n sortBy: typeof body.sortBy === 'string' ? body.sortBy : undefined,\n sortOrder: parseSortOrder(typeof body.sortOrder === 'string' ? body.sortOrder : undefined),\n attributes: Array.isArray(body.attributes) ? body.attributes.filter((a): a is string => typeof a === 'string') : undefined,\n excludedAttributes: Array.isArray(body.excludedAttributes) ? body.excludedAttributes.filter((a): a is string => typeof a === 'string') : undefined,\n };\n};\n\nconst parseSortOrder = (raw: string | undefined): ScimSortOrder | undefined => {\n if (raw === 'ascending' || raw === 'descending') return raw;\n return undefined;\n};\n\nconst parsePositiveInt = (raw: string | undefined, fallback: number): number => {\n if (raw === undefined) return fallback;\n const n = Number(raw);\n if (!Number.isFinite(n) || n < 1) return fallback;\n return Math.floor(n);\n};\n\nconst clamp = (value: number, min: number, max: number): number => Math.max(min, Math.min(max, value));\n\nconst parseCsvParam = (raw: string | undefined): string[] | undefined => {\n if (!raw) return undefined;\n const parts = raw.split(',').map(s => s.trim()).filter(Boolean);\n return parts.length > 0 ? parts : undefined;\n};\n\nconst pickStringParam = (query: ServerKitContext['query'], key: string): string | undefined => {\n const value = query[key];\n if (typeof value === 'string') return value;\n if (Array.isArray(value) && typeof value[0] === 'string') return value[0];\n return undefined;\n};\n\nconst validatePatchRequest = (body: Partial<ScimPatchRequest> | unknown): ScimPatchOp[] => {\n if (!isPlainObject(body)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: 'PATCH request must be a JSON object' });\n }\n if (!Array.isArray(body.schemas) || !body.schemas.includes(PatchOpSchema)) {\n throw scimError(400, 'invalidSyntax', 'Bad Request').withDetails({ message: `PATCH request schemas must include \"${PatchOpSchema}\"` });\n }\n if (!Array.isArray(body.Operations) || body.Operations.length === 0) {\n throw scimError(400, 'invalidValue', 'Bad Request').withDetails({ message: '\"Operations\" must be a non-empty array' });\n }\n return body.Operations as ScimPatchOp[];\n};\n\nconst listEnvelope = <T>(resources: T[], query?: ScimListQuery, total?: number): ScimListResponse<T> => ({\n schemas: [ListResponseSchema],\n totalResults: total ?? resources.length,\n startIndex: query?.startIndex ?? 1,\n itemsPerPage: resources.length,\n Resources: resources,\n});\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n};\n"],"mappings":"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","names":["ListResponseSchema","PatchOpSchema","UserSchemaId","userSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","multiValuedSubAttrs","canonicalValues","kind","GroupSchemaId","groupSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","canonicalValues","EnterpriseUserSchemaId","enterpriseUserSchema","id","name","description","meta","resourceType","location","attributes","type","multiValued","required","caseExact","mutability","returned","uniqueness","subAttributes","referenceTypes","ResourceTypeSchemaId","userResourceType","schemas","id","name","endpoint","description","schema","UserSchemaId","schemaExtensions","EnterpriseUserSchemaId","required","meta","resourceType","location","groupResourceType","GroupSchemaId","ServiceProviderConfigSchemaId","defaultBearer","type","name","description","specUri","primary","buildServiceProviderConfig","options","schemas","documentationUri","patch","supported","bulk","maxOperations","maxPayloadSize","filter","maxResults","changePassword","sort","etag","authenticationSchemes","meta","resourceType","location","coreSchemas","userSchema","groupSchema","enterpriseUserSchema","HttpError","ScimErrorSchema","ScimError","HttpError","scimType","statusCode","message","Object","setPrototypeOf","prototype","toScimBody","schemas","status","String","detail","IsScimError","error","scimError","COMPARISON_OPS","Set","tokenizeScimFilter","input","tokens","i","length","ch","push","kind","value","start","next","scimError","withDetails","position","message","raw","test","num","Number","isNaN","isIdentifierStart","isIdentifierPart","lower","toLowerCase","has","parseScimFilter","input","trimmed","trim","length","scimError","withDetails","message","tokens","tokenizeScimFilter","parser","Parser","node","parseOr","expectEnd","pos","left","parseAnd","peek","kind","consume","right","operator","parseUnary","token","expect","inner","filter","parseComparisonOrValuePath","error","attribute","String","value","next","valueToken","remaining","position","start","applyScimPatch","resource","ops","next","structuredClone","op","applyOne","kind","normaliseOpKind","path","undefined","scimError","withDetails","message","value","Array","isArray","mergeObject","parsePatchPath","applyAtPath","lower","String","toLowerCase","raw","bracketStart","indexOf","segments","split","filter","Boolean","bracketEnd","findMatchingBracket","head","slice","filterSrc","tail","length","parseScimFilter","filterSubAttr","startsWith","includes","input","openIndex","depth","inString","i","ch","rest","applyFilteredOp","applySimpleOp","child","childObj","isPlainObject","updated","attr","existing","subAttr","collection","matched","forEach","item","index","evaluateFilter","push","_","idx","seed","map","target","source","out","key","val","Object","entries","evaluateComparison","attribute","operator","left","right","nested","some","current","seg","endsWith","compareScalar","a","b","sa","sb","ScimUserRepository","ScimGroupRepository","randomUUID","DateTime","Injectable","Logger","ScimUserService","repository","logger","get","id","user","findById","scimError","undefined","withDetails","message","list","query","create","payload","userName","existing","findByUserName","now","DateTime","utc","toISO","randomUUID","schemas","normaliseSchemas","meta","resourceType","created","lastModified","location","debug","replace","conflict","patch","ops","patched","applyScimPatch","delete","provided","Set","add","UserSchemaId","EnterpriseUserSchemaId","Array","from","randomUUID","DateTime","Injectable","Logger","ScimGroupService","repository","logger","get","id","group","findById","scimError","undefined","withDetails","message","list","query","create","payload","displayName","existing","findByDisplayName","now","DateTime","utc","toISO","randomUUID","schemas","normaliseSchemas","meta","resourceType","created","lastModified","location","debug","replace","conflict","patch","ops","patched","applyScimPatch","delete","provided","Set","add","GroupSchemaId","Array","from","Injectable","ScimServiceProviderService","config","schemas","resourceTypes","options","buildServiceProviderConfig","coreSchemas","userResourceType","groupResourceType","getServiceProviderConfig","listSchemas","getSchema","id","found","find","s","scimError","undefined","withDetails","message","listResourceTypes","getResourceType","rt","SCIM_MEDIA_TYPE","scimContentTypeMiddleware","ctx","next","method","toUpperCase","contentType","request","headers","toLowerCase","includes","scimError","undefined","withDetails","message","body","type","IsHttpError","IsServerkitError","scimErrorMiddleware","ctx","next","status","body","type","SCIM_MEDIA_TYPE","schemas","ScimErrorSchema","String","detail","URL","pathname","error","IsScimError","respondWithScimError","app","emit","IsHttpError","ScimError","statusCode","withDetails","details","withCause","IsServerkitError","message","toScimBody","headers","name","value","Object","entries","set","invalidAuthenticationSession","requireScimScope","scope","ctx","next","session","authenticationSession","invalidAuthenticationSession","scimError","undefined","addHeader","withDetails","message","granted","claims","scimScopes","Array","isArray","includes","bodyParserMiddleware","ServerKitRouter","createScimRouter","options","router","ServerKitRouter","guards","routeGuards","json","bodyParserMiddleware","SCIM_MEDIA_TYPE","maxResults","serviceProviderService","getServiceProviderConfig","filter","get","ctx","body","type","listEnvelope","listSchemas","getSchema","params","id","listResourceTypes","getResourceType","query","parseListQueryFromUrl","result","userService","list","resources","totalResults","post","requestBody","takeRequestBody","parseListQueryFromBody","payload","created","create","status","meta","location","set","put","replace","patch","ops","validatePatchRequest","delete","groupService","undefined","filterRaw","pickStringParam","parseScimFilter","startIndex","parsePositiveInt","count","clamp","sortBy","sortOrder","parseSortOrder","attributes","parseCsvParam","excludedAttributes","isPlainObject","scimError","withDetails","message","Math","floor","Array","isArray","a","raw","fallback","n","Number","isFinite","value","min","max","parts","split","map","s","trim","Boolean","length","key","schemas","includes","PatchOpSchema","Operations","total","ListResponseSchema","itemsPerPage","Resources"]}
@@ -1 +1 @@
1
- {"version":3,"file":"scim.group.service.d.ts","sourceRoot":"","sources":["../../src/services/scim.group.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD;;;;GAIG;AACH,qBACa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,MAAM;IAGjC;;;;OAIG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAMzC;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAIpE;;;;;;OAMG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IA0B7D;;;;;;;OAOG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IA2B1E;;;;;;OAMG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;IAY/D;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,OAAO,CAAC,gBAAgB;CAKzB"}
1
+ {"version":3,"file":"scim.group.service.d.ts","sourceRoot":"","sources":["../../src/services/scim.group.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD;;;;GAIG;AACH,qBACa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,mBAAmB,EAC/B,MAAM,EAAE,MAAM;IAGjC;;;;OAIG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAMzC;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAIpE;;;;;;OAMG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IA0B7D;;;;;;;OAOG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC;IA2B1E;;;;;;OAMG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;IAY/D;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,OAAO,CAAC,gBAAgB;CAKzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"scim.user.service.d.ts","sourceRoot":"","sources":["../../src/services/scim.user.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMxD;;;;GAIG;AACH,qBACa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,MAAM;IAGjC;;;;OAIG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAMxC;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAInE;;;;;;;OAOG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA0B3D;;;;;;;;OAQG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA2BxE;;;;;;;OAOG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IAY9D;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,OAAO,CAAC,gBAAgB;CAQzB"}
1
+ {"version":3,"file":"scim.user.service.d.ts","sourceRoot":"","sources":["../../src/services/scim.user.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMxD;;;;GAIG;AACH,qBACa,eAAe;IAExB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,UAAU,EAAE,kBAAkB,EAC9B,MAAM,EAAE,MAAM;IAGjC;;;;OAIG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;IAMxC;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC;IAInE;;;;;;;OAOG;IACG,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA0B3D;;;;;;;;OAQG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;IA2BxE;;;;;;;OAOG;IACG,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;IAY9D;;;;OAIG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvC,OAAO,CAAC,gBAAgB;CAQzB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maroonedsoftware/scim",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "SCIM 2.0 (RFC 7643/7644) server toolkit for ServerKit — schemas, filter parser, PATCH applier, error envelope, and a Koa router with abstract repositories.",
5
5
  "author": {
6
6
  "name": "Marooned Software",
@@ -34,10 +34,11 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "injectkit": "^1.2.0",
37
- "@maroonedsoftware/errors": "1.6.0",
38
- "@maroonedsoftware/authentication": "4.20.0",
39
- "@maroonedsoftware/koa": "2.2.1",
37
+ "luxon": "^3.7.2",
38
+ "@maroonedsoftware/authentication": "4.21.0",
39
+ "@maroonedsoftware/errors": "1.7.0",
40
40
  "@maroonedsoftware/utilities": "1.7.0",
41
+ "@maroonedsoftware/koa": "2.2.3",
41
42
  "@maroonedsoftware/logger": "1.1.0"
42
43
  },
43
44
  "peerDependencies": {
@@ -47,11 +48,12 @@
47
48
  "devDependencies": {
48
49
  "@koa/router": "^15.5.0",
49
50
  "@types/koa": "^3.0.2",
51
+ "@types/luxon": "^3.7.1",
50
52
  "@types/supertest": "^6.0.3",
51
53
  "koa": "^3.2.0",
52
54
  "supertest": "^7.1.4",
53
- "@repo/config-typescript": "0.1.0",
54
- "@repo/config-eslint": "0.2.1"
55
+ "@repo/config-eslint": "0.2.1",
56
+ "@repo/config-typescript": "0.1.0"
55
57
  },
56
58
  "scripts": {
57
59
  "build": "tsup src/index.ts --format esm --sourcemap --dts && tsc --emitDeclarationOnly --declaration",