UNPKG

@authup/core-kit

Version:

Package containing global constants, types & interfaces.

1 lines 89.3 kB
{"version":3,"file":"index.mjs","sources":["../src/constants.ts","../src/domains/client/error.ts","../src/helpers/name-valid.ts","../src/domains/client/helpers.ts","../src/domains/client/validator.ts","../src/domains/identity/constants.ts","../src/domains/identity-provider/constants.ts","../src/domains/identity-provider/ldap/check.ts","../src/domains/identity-provider/ldap/validator.ts","../src/domains/identity-provider/oauth2/check.ts","../src/domains/identity-provider/preset/constants.ts","../src/domains/identity-provider/preset/utils.ts","../src/domains/identity-provider/oauth2/preset-validator.ts","../src/domains/identity-provider/oauth2/validator.ts","../src/domains/identity-provider/attributes-validator.ts","../src/domains/identity-provider/utils.ts","../src/domains/identity-provider/oidc/check.ts","../src/domains/identity-provider/validator.ts","../src/domains/permission/constants.ts","../src/domains/permission/helpers.ts","../src/domains/permission/validator.ts","../src/domains/permission-binding/helpers/key.ts","../src/domains/permission-binding/helpers/equal.ts","../src/domains/permission-binding/helpers/merge.ts","../src/domains/policy/helpers.ts","../src/domains/policy/validator.ts","../src/domains/realm/constants.ts","../src/domains/realm/helpers.ts","../src/domains/realm/validator.ts","../src/domains/robot/helpers.ts","../src/domains/robot/error.ts","../src/domains/robot/validator.ts","../src/domains/role/constants.ts","../src/domains/role/utils.ts","../src/domains/role/validator.ts","../src/domains/scope/constants.ts","../src/domains/scope/utils.ts","../src/domains/scope/validator.ts","../src/domains/user/error.ts","../src/domains/user/utils.ts","../src/domains/user/validator.ts","../src/domains/contstants.ts","../src/domains/helpers.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum ValidatorGroup {\n CREATE = 'create',\n UPDATE = 'update',\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { AuthupError, ErrorCode } from '@authup/errors';\n\nexport class ClientError extends AuthupError {\n static credentialsInvalid() {\n return new ClientError({\n code: ErrorCode.ENTITY_CREDENTIALS_INVALID,\n message: 'The client credentials are invalid.',\n });\n }\n\n static invalid() {\n return new ClientError({\n code: ErrorCode.OAUTH_CLIENT_INVALID,\n message: 'The client is invalid.',\n });\n }\n\n static notFound() {\n return new ClientError({\n code: ErrorCode.ENTITY_NOT_FOUND,\n message: 'The client account was not found.',\n });\n }\n\n static inactive() {\n return new ClientError({\n code: ErrorCode.ENTITY_INACTIVE,\n message: 'The client account is inactive.',\n });\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { AuthupError } from '@authup/errors';\n\nexport type NameValidOptions = {\n throwOnFailure?: boolean;\n};\nexport function isNameValid(input: string, options: NameValidOptions = {}): boolean {\n if (/\\s/g.test(input)) {\n if (options.throwOnFailure) {\n throw new AuthupError('Whitespace character is not allowed.');\n }\n\n return false;\n }\n\n if (/^[A-Za-z0-9-_.]+$/.test(input)) {\n return true;\n }\n\n if (options.throwOnFailure) {\n throw new AuthupError('Only the characters [A-Za-z0-9-_.]+ are allowed.');\n }\n\n return false;\n}\n","/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isClientNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2025-2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants';\nimport type { Client } from './entity';\nimport { isClientNameValid } from './helpers';\n\nexport class ClientValidator extends Container<Client> {\n protected override initialize() {\n super.initialize();\n\n // ----------------------------------------------\n\n this.mount(\n 'active',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n this.mount(\n 'is_confidential',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n // ----------------------------------------------\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isClientNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The client name is not valid.',\n });\n }\n }),\n );\n\n this.mount(\n 'name',\n { group: ValidatorGroup.CREATE },\n nameValidator,\n );\n this.mount(\n 'name',\n { group: ValidatorGroup.UPDATE, optional: true },\n nameValidator,\n );\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(3).max(4096).nullable()),\n );\n\n // ----------------------------------------------\n\n this.mount(\n 'secret',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'secret_encrypted',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n this.mount(\n 'secret_hashed',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n // ----------------------------------------------\n\n this.mount(\n 'redirect_uri',\n { optional: true },\n createValidator(\n z\n .string()\n .check((ctx) => {\n const validator = z.url();\n const urls = ctx.value.split(',');\n for (const url of urls) {\n try {\n validator.parse(url);\n } catch (e) {\n ctx.issues.push({\n input: url,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The redirect_uri is not valid.',\n });\n }\n }\n })\n .nullable(),\n ),\n );\n\n this.mount(\n 'base_url',\n { optional: true },\n createValidator(\n z.url().nullable(),\n ),\n );\n\n this.mount(\n 'root_url',\n { optional: true },\n createValidator(\n z.url().nullable(),\n ),\n );\n\n this.mount(\n 'grant_types',\n { optional: true },\n createValidator(z.string().min(3).max(512).nullable()),\n );\n\n this.mount(\n 'scope',\n { optional: true },\n createValidator(z.string().min(3).max(512).nullable()),\n );\n\n // ----------------------------------------------\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid()),\n );\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum IdentityType {\n CLIENT = 'client',\n ROBOT = 'robot',\n USER = 'user',\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum IdentityProviderProtocol {\n LDAP = 'ldap',\n OAUTH2 = 'oauth2',\n OIDC = 'oidc',\n}\n\nexport enum IdentityProviderMappingSyncMode {\n /**\n * Synchronize on initial user login.\n */\n ONCE = 'once',\n /**\n * Synchronize on every user login.\n */\n ALWAYS = 'always',\n /**\n * Synchronize based on idp configuration.\n */\n INHERIT = 'inherit',\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { IdentityProviderProtocol } from '../constants';\nimport type { IdentityProvider } from '../entity';\nimport type { LdapIdentityProvider } from './types';\n\nexport function isLdapIdentityProvider(input: IdentityProvider) : input is LdapIdentityProvider {\n return input.protocol === IdentityProviderProtocol.LDAP;\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { IdentityProviderProtocol } from '../constants';\nimport type { LdapIdentityProvider } from './types';\n\nexport class IdentityProviderLDAPAttributesValidator extends Container<LdapIdentityProvider> {\n protected override initialize() {\n super.initialize();\n\n this.mount(\n 'protocol',\n createValidator(z.string().check((ctx) => {\n if (ctx.value !== IdentityProviderProtocol.LDAP) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: 'The protocol should be LDAP.',\n });\n }\n })),\n );\n\n this.mount('url', createValidator(z.url()));\n\n this.mount('timeout', { optional: true }, createValidator(z.number().min(0).optional().nullable()));\n\n this.mount('start_tls', { optional: true }, createValidator(z.boolean().optional().nullable()));\n\n this.mount('tls', { optional: true }, createValidator(z.any().optional().nullable()));\n\n this.mount(\n 'base_dn',\n { optional: true },\n createValidator(z.string().min(3).max(2000).optional()\n .nullable()),\n );\n this.mount('user', createValidator(z.string().min(3)));\n\n this.mount('password', createValidator(z.string().min(3)));\n\n this.mount('user_base_dn', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('user_filter', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('user_name_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('user_mail_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('user_display_name_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_base_dn', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_filter', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_name_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_class', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_member_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n\n this.mount('group_member_user_attribute', { optional: true }, createValidator(z.string().optional().nullable()));\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { IdentityProviderProtocol } from '../constants';\nimport type { IdentityProvider } from '../entity';\nimport type { OAuth2IdentityProvider } from './types';\n\nexport function isOAuth2IdentityProvider(input: IdentityProvider) : input is OAuth2IdentityProvider {\n return input.protocol === IdentityProviderProtocol.OAUTH2;\n}\n","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum IdentityProviderPreset {\n FACEBOOK = 'facebook',\n GITHUB = 'github',\n GITLAB = 'gitlab',\n GOOGLE = 'google',\n PAYPAL = 'paypal',\n INSTAGRAM = 'instagram',\n STACKOVERFLOW = 'stackoverflow',\n TWITTER = 'twitter',\n}\n","/*\n * Copyright (c) 2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { IdentityProviderProtocol } from '../constants';\nimport { IdentityProviderPreset } from './constants';\n\nexport function getIdentityProviderProtocolForPreset(\n id: string,\n) : `${IdentityProviderProtocol}` | null {\n switch (id) {\n case IdentityProviderPreset.GITHUB:\n case IdentityProviderPreset.GITLAB:\n case IdentityProviderPreset.GOOGLE:\n case IdentityProviderPreset.FACEBOOK:\n case IdentityProviderPreset.INSTAGRAM:\n case IdentityProviderPreset.PAYPAL:\n case IdentityProviderPreset.STACKOVERFLOW:\n case IdentityProviderPreset.TWITTER:\n return IdentityProviderProtocol.OIDC;\n }\n\n return null;\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { IdentityProviderProtocol } from '../constants';\nimport { getIdentityProviderProtocolForPreset } from '../preset';\nimport type { OAuth2IdentityProvider } from './types';\n\nexport class IdentityProviderOAuth2PresetAttributesValidator extends Container<OAuth2IdentityProvider> {\n protected override initialize() {\n super.initialize();\n\n this.mount(\n 'preset',\n createValidator(z.string().check((ctx) => {\n const protocol = getIdentityProviderProtocolForPreset(ctx.value);\n\n if (\n protocol !== IdentityProviderProtocol.OAUTH2 &&\n protocol !== IdentityProviderProtocol.OIDC\n ) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: `The resolved protocol should be ${IdentityProviderProtocol.OAUTH2} or ${IdentityProviderProtocol.OIDC}`,\n });\n }\n })),\n );\n\n this.mount(\n 'client_id',\n createValidator(z.string().min(3).max(128)),\n );\n\n this.mount(\n 'client_secret',\n { optional: true },\n createValidator(z.string().min(3).max(128).optional()\n .nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { getIdentityProviderProtocolForPreset } from '../preset';\nimport type { OAuth2IdentityProvider } from './types';\n\nexport class IdentityProviderOAuth2AttributesValidator extends Container<OAuth2IdentityProvider> {\n protected override initialize() {\n super.initialize();\n\n this.mount(\n 'preset',\n createValidator(z\n .string()\n .optional()\n .nullable()\n .check((ctx) => {\n let protocol : string | null | undefined;\n if (typeof ctx.value === 'string') {\n protocol = getIdentityProviderProtocolForPreset(ctx.value);\n }\n\n if (typeof protocol === 'string') {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: 'The preset should not be defined.',\n });\n }\n })),\n );\n\n this.mount(\n 'client_id',\n createValidator(z.string().min(3).max(128)),\n );\n\n this.mount(\n 'client_secret',\n { optional: true },\n createValidator(z.string().min(3).max(128).optional()\n .nullable()),\n );\n\n this.mount(\n 'token_url',\n createValidator(z.url()),\n );\n\n this.mount(\n 'token_revoke_url',\n { optional: true },\n createValidator(z.url().optional().nullable()),\n );\n\n this.mount(\n 'authorize_url',\n createValidator(z.url()),\n );\n\n this.mount(\n 'user_info_url',\n { optional: true },\n createValidator(z.url().optional().nullable()),\n );\n\n this.mount(\n 'scope',\n createValidator(z.string().min(3).max(2000).optional()\n .nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { ObjectLiteral } from '@authup/kit';\nimport type { ContainerOptions } from 'validup';\nimport { Container } from 'validup';\nimport { IdentityProviderLDAPAttributesValidator } from './ldap';\nimport { IdentityProviderOAuth2AttributesValidator, IdentityProviderOAuth2PresetAttributesValidator } from './oauth2';\n\nexport class IdentityProviderAttributesValidator extends Container<ObjectLiteral> {\n constructor(options: ContainerOptions<ObjectLiteral> = {}) {\n super({\n ...options,\n oneOf: true,\n });\n }\n\n protected override initialize() {\n super.initialize();\n\n this.mount(new IdentityProviderLDAPAttributesValidator());\n this.mount(new IdentityProviderOAuth2AttributesValidator());\n this.mount(new IdentityProviderOAuth2PresetAttributesValidator());\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function buildIdentityProviderAuthorizeCallbackPath(id: string | number) {\n return `/identity-providers/${id}/authorize-in`;\n}\n\nexport function buildIdentityProviderAuthorizePath(id: string | number) {\n return `/identity-providers/${id}/authorize-out`;\n}\n\nexport function isIdentityProviderNameValid(input: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(input, options);\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { IdentityProviderProtocol } from '../constants';\nimport type { IdentityProvider } from '../entity';\nimport type { OpenIDIdentityProvider } from './types';\n\nexport function isOpenIDIdentityProvider(input: IdentityProvider) : input is OpenIDIdentityProvider {\n return input.protocol === IdentityProviderProtocol.OIDC;\n}\n","/*\n * Copyright (c) 2025-2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport zod from 'zod';\nimport { ValidatorGroup } from '../../constants';\nimport { IdentityProviderProtocol } from './constants';\nimport type { IdentityProvider } from './entity';\nimport { IdentityProviderPreset } from './preset';\nimport { isIdentityProviderNameValid } from './utils';\n\nexport class IdentityProviderValidator extends Container<IdentityProvider> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n zod.string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isIdentityProviderNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The name is not valid.',\n });\n }\n }),\n );\n\n this.mount('name', { group: ValidatorGroup.CREATE }, nameValidator);\n this.mount('name', { group: ValidatorGroup.UPDATE, optional: true }, nameValidator);\n\n this.mount('display_name', { optional: true }, createValidator(\n zod.string().min(3).max(256),\n ));\n\n const enabledValidator = createValidator(zod.boolean());\n this.mount('enabled', { group: ValidatorGroup.CREATE }, enabledValidator);\n this.mount('enabled', { group: ValidatorGroup.UPDATE, optional: true }, enabledValidator);\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(zod.uuid()),\n );\n\n this.mount('protocol', createValidator(zod.enum(IdentityProviderProtocol)));\n\n this.mount('preset', { optional: true }, createValidator(zod.enum(IdentityProviderPreset).optional().nullable()));\n }\n}\n","/*\n * Copyright (c) 2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum PermissionName {\n CLIENT_CREATE = 'client_create',\n CLIENT_DELETE = 'client_delete',\n CLIENT_UPDATE = 'client_update',\n CLIENT_READ = 'client_read',\n CLIENT_SELF_MANAGE = 'client_self_manage',\n\n CLIENT_PERMISSION_CREATE = 'client_permission_create',\n CLIENT_PERMISSION_DELETE = 'client_permission_delete',\n CLIENT_PERMISSION_READ = 'client_permission_read',\n\n CLIENT_ROLE_CREATE = 'client_role_create',\n CLIENT_ROLE_DELETE = 'client_role_delete',\n CLIENT_ROLE_UPDATE = 'client_role_update',\n CLIENT_ROLE_READ = 'client_role_read',\n\n CLIENT_SCOPE_CREATE = 'client_scope_create',\n CLIENT_SCOPE_DELETE = 'client_scope_delete',\n\n IDENTITY_PROVIDER_CREATE = 'identity_provider_create',\n IDENTITY_PROVIDER_DELETE = 'identity_provider_delete',\n IDENTITY_PROVIDER_UPDATE = 'identity_provider_update',\n IDENTITY_PROVIDER_READ = 'identity_provider_read',\n\n IDENTITY_PROVIDER_ROLE_CREATE = 'identity_provider_role_create',\n IDENTITY_PROVIDER_ROLE_DELETE = 'identity_provider_role_delete',\n IDENTITY_PROVIDER_ROLE_UPDATE = 'identity_provider_role_update',\n\n PERMISSION_CREATE = 'permission_create',\n PERMISSION_DELETE = 'permission_delete',\n PERMISSION_UPDATE = 'permission_update',\n PERMISSION_READ = 'permission_read',\n\n REALM_CREATE = 'realm_create',\n REALM_DELETE = 'realm_delete',\n REALM_UPDATE = 'realm_update',\n REALM_READ = 'realm_read',\n\n ROBOT_CREATE = 'robot_create',\n ROBOT_DELETE = 'robot_delete',\n ROBOT_UPDATE = 'robot_update',\n ROBOT_READ = 'robot_read',\n ROBOT_SELF_MANAGE = 'robot_self_manage',\n\n ROBOT_PERMISSION_CREATE = 'robot_permission_create',\n ROBOT_PERMISSION_DELETE = 'robot_permission_delete',\n ROBOT_PERMISSION_READ = 'robot_permission_read',\n\n ROBOT_ROLE_CREATE = 'robot_role_create',\n ROBOT_ROLE_DELETE = 'robot_role_delete',\n ROBOT_ROLE_UPDATE = 'robot_role_update',\n ROBOT_ROLE_READ = 'robot_role_read',\n\n ROLE_CREATE = 'role_create',\n ROLE_DELETE = 'role_delete',\n ROLE_UPDATE = 'role_update',\n ROLE_READ = 'role_read',\n\n ROLE_PERMISSION_CREATE = 'role_permission_create',\n ROLE_PERMISSION_DELETE = 'role_permission_delete',\n ROLE_PERMISSION_READ = 'role_permission_read',\n\n SCOPE_CREATE = 'scope_create',\n SCOPE_DELETE = 'scope_delete',\n SCOPE_UPDATE = 'scope_update',\n SCOPE_READ = 'scope_read',\n\n USER_CREATE = 'user_create',\n USER_DELETE = 'user_delete',\n USER_UPDATE = 'user_update',\n USER_READ = 'user_read',\n USER_SELF_MANAGE = 'user_self_update',\n\n USER_PERMISSION_CREATE = 'user_permission_create',\n USER_PERMISSION_DELETE = 'user_permission_delete',\n USER_PERMISSION_READ = 'user_permission_read',\n\n USER_ROLE_CREATE = 'user_role_create',\n USER_ROLE_DELETE = 'user_role_delete',\n USER_ROLE_UPDATE = 'user_role_update',\n USER_ROLE_READ = 'user_role_read',\n}\n","/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isPermissionNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { DecisionStrategy } from '@authup/kit';\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Permission } from './entity.ts';\nimport { isPermissionNameValid } from './helpers.ts';\n\nexport class PermissionValidator extends Container<\n Permission\n> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isPermissionNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The permission name is not valid.',\n });\n }\n }),\n );\n this.mount('name', { group: ValidatorGroup.CREATE }, nameValidator);\n this.mount('name', { group: ValidatorGroup.UPDATE, optional: true }, nameValidator);\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(5).max(4096).nullable()),\n );\n\n this.mount(\n 'client_id',\n { optional: true },\n createValidator(z.uuid()),\n );\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid().nullable().optional()),\n );\n\n this.mount(\n 'decision_strategy',\n { optional: true },\n createValidator(\n z.enum(DecisionStrategy)\n .nullable(),\n ),\n );\n }\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { PermissionBindingPermission } from '../types';\n\nfunction formatKeySegment(value?: string | null): string {\n if (typeof value === 'undefined') {\n return '*';\n }\n\n return value || '_';\n}\n\nexport function buildPermissionBindingKey(\n input: PermissionBindingPermission,\n) {\n return `${formatKeySegment(input.realm_id)}/${formatKeySegment(input.client_id)}/${input.name}`;\n}\n","/*\n * Copyright (c) 2024-2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { PermissionBinding } from '../types';\n\nexport function isPermissionBindingEqual(a: PermissionBinding, b: PermissionBinding): boolean {\n if (a.permission.name !== b.permission.name) {\n return false;\n }\n\n if ((a.permission.realm_id ?? null) !== (b.permission.realm_id ?? null)) {\n return false;\n }\n\n if ((a.permission.client_id ?? null) !== (b.permission.client_id ?? null)) {\n return false;\n }\n\n return true;\n}\n","/*\n * Copyright (c) 2024-2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { DecisionStrategy } from '@authup/kit';\nimport type { PolicyWithType } from '../../policy';\nimport type { PermissionBinding } from '../types';\nimport { buildPermissionBindingKey } from './key';\n\ntype CompositePolicy = {\n decision_strategy?: `${DecisionStrategy}`,\n children: PolicyWithType[],\n};\n\nexport function mergePermissionBindings(input: PermissionBinding[]) : PermissionBinding[] {\n const grouped : Record<string, PermissionBinding[]> = input\n .reduce((previous, current) => {\n const key = buildPermissionBindingKey(current.permission);\n if (!previous[key]) {\n previous[key] = [];\n }\n\n previous[key].push(current);\n\n return previous;\n }, {} as Record<string, PermissionBinding[]>);\n\n const output : PermissionBinding[] = [];\n const keys = Object.keys(grouped);\n for (const key of keys) {\n const group = grouped[key]!;\n const first = group[0]!;\n\n if (group.length === 1) {\n output.push(first);\n continue;\n }\n\n const children : PolicyWithType[] = [];\n\n for (const element of group) {\n if (!element.policies || element.policies.length === 0) {\n continue;\n }\n\n const policy: PolicyWithType<CompositePolicy> = {\n type: 'composite',\n decision_strategy: element.permission.decision_strategy || DecisionStrategy.UNANIMOUS,\n children: element.policies,\n };\n\n children.push(policy);\n }\n\n let mergedPolicies: PolicyWithType[] | undefined;\n\n if (\n children.length > 0 &&\n children.length === group.length\n ) {\n const policy: PolicyWithType<CompositePolicy> = {\n type: 'composite',\n decision_strategy: DecisionStrategy.AFFIRMATIVE,\n children,\n };\n\n mergedPolicies = [policy];\n }\n\n output.push({\n permission: {\n ...first.permission,\n decision_strategy: DecisionStrategy.AFFIRMATIVE,\n },\n policies: mergedPolicies,\n });\n }\n\n return output;\n}\n","/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isPolicyNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Policy } from './entity.ts';\nimport { isPolicyNameValid } from './helpers.ts';\n\nexport class PolicyValidator extends Container<\n Policy\n> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isPolicyNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The policy name is not valid.',\n });\n }\n }),\n );\n\n this.mount('name', { group: ValidatorGroup.CREATE }, nameValidator);\n this.mount('name', { group: ValidatorGroup.UPDATE, optional: true }, nameValidator);\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'invert',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n this.mount(\n 'type',\n { group: ValidatorGroup.CREATE },\n createValidator(z.string().min(3).max(128)),\n );\n\n this.mount(\n 'parent_id',\n { optional: true },\n createValidator(z.uuid().nullable()),\n );\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid().nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport const REALM_MASTER_NAME = 'master';\nexport const REALM_NAME_REGEX = /^[a-zA-Z0-9_]{3,128}$/;\n","/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isRealmNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Realm } from './entity.ts';\nimport { isRealmNameValid } from './helpers.ts';\n\nexport class RealmValidator extends Container<\n Realm\n> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isRealmNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The realm name is not valid.',\n });\n }\n }),\n );\n\n this.mount('name', { group: ValidatorGroup.CREATE }, nameValidator);\n this.mount('name', { group: ValidatorGroup.UPDATE, optional: true }, nameValidator);\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(5).max(4096).nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isRobotNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { AuthupError, ErrorCode } from '@authup/errors';\n\nexport class RobotError extends AuthupError {\n static credentialsInvalid() {\n return new RobotError({\n code: ErrorCode.ENTITY_CREDENTIALS_INVALID,\n message: 'The robot credentials are invalid.',\n });\n }\n\n static notFound() {\n return new RobotError({\n code: ErrorCode.ENTITY_NOT_FOUND,\n message: 'The robot account was not found.',\n });\n }\n\n static inactive() {\n return new RobotError({\n code: ErrorCode.ENTITY_INACTIVE,\n message: 'The robot account is inactive.',\n });\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Robot } from './entity.ts';\nimport { isRobotNameValid } from './helpers.ts';\n\nexport class RobotValidator extends Container<\n Robot\n> {\n protected override initialize() {\n super.initialize();\n\n this.mount(\n 'secret',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'active',\n { optional: true },\n createValidator(z.boolean()),\n );\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isRobotNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The robot name is not valid.',\n });\n }\n }),\n );\n\n this.mount(\n 'name',\n { group: ValidatorGroup.CREATE },\n nameValidator,\n );\n this.mount(\n 'name',\n { group: ValidatorGroup.UPDATE, optional: true },\n nameValidator,\n );\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(5).max(4096).nullable()),\n );\n\n this.mount(\n 'user_id',\n { optional: true },\n createValidator(z.uuid()),\n );\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid()),\n );\n }\n}\n","/*\n * Copyright (c) 2024.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport const ROLE_ADMIN_NAME = 'admin';\nexport const ROLE_REALM_ADMIN_NAME = 'realm_admin';\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isRoleNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Role } from './entity.ts';\nimport { isRoleNameValid } from './utils.ts';\n\nexport class RoleValidator extends Container<\n Role\n> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isRoleNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The role name is not valid.',\n });\n }\n }),\n );\n\n this.mount('name', { group: ValidatorGroup.CREATE }, nameValidator);\n this.mount('name', { group: ValidatorGroup.UPDATE, optional: true }, nameValidator);\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(5).max(4096).nullable()),\n );\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid().nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nexport enum ScopeName {\n /**\n * Full permissions\n */\n GLOBAL = 'global',\n\n /**\n * for Openid usage (id-token)\n */\n OPEN_ID = 'openid',\n\n /**\n * /users/@me with email (userinfo & id-token)\n */\n EMAIL = 'email',\n\n /**\n * Roles array (id-token)\n */\n ROLES = 'roles',\n\n /**\n * /users/@me without email (userinfo & id-token)\n */\n IDENTITY = 'identity',\n}\n","/*\n * Copyright (c) 2022-2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isScopeNameValid(name: string, options: NameValidOptions = {}) : boolean {\n return isNameValid(name, options);\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createValidator } from '@validup/adapter-zod';\nimport { Container } from 'validup';\nimport { z } from 'zod';\nimport { ValidatorGroup } from '../../constants.ts';\nimport type { Scope } from './entity.ts';\nimport { isScopeNameValid } from './utils.ts';\n\nexport class ScopeValidator extends Container<\n Scope\n> {\n protected override initialize() {\n super.initialize();\n\n const nameValidator = createValidator(\n z\n .string()\n .min(3)\n .max(128)\n .check((ctx) => {\n try {\n isScopeNameValid(ctx.value, { throwOnFailure: true });\n } catch (e) {\n ctx.issues.push({\n input: ctx.value,\n code: 'custom',\n message: e instanceof Error ? e.message : 'The scope name is not valid.',\n });\n }\n }),\n );\n\n this.mount(\n 'name',\n { group: ValidatorGroup.CREATE },\n nameValidator,\n );\n this.mount(\n 'name',\n { group: ValidatorGroup.UPDATE, optional: true },\n nameValidator,\n );\n\n this.mount(\n 'display_name',\n { optional: true },\n createValidator(z.string().min(3).max(256).nullable()),\n );\n\n this.mount(\n 'description',\n { optional: true },\n createValidator(z.string().min(5).max(4096).nullable()),\n );\n\n this.mount(\n 'realm_id',\n { group: ValidatorGroup.CREATE, optional: true },\n createValidator(z.uuid().nullable()),\n );\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { AuthupError, ErrorCode } from '@authup/errors';\n\nexport class UserError extends AuthupError {\n static credentialsInvalid() {\n return new UserError({\n code: ErrorCode.ENTITY_CREDENTIALS_INVALID,\n message: 'The user credentials are invalid.',\n });\n }\n\n static notFound() {\n return new UserError({\n code: ErrorCode.ENTITY_NOT_FOUND,\n message: 'The user account was not found.',\n });\n }\n\n static inactive() {\n return new UserError({\n code: ErrorCode.ENTITY_INACTIVE,\n message: 'The user account is inactive.',\n });\n }\n}\n","/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { AuthupError } from '@authup/errors';\nimport type { NameValidOptions } from '../../helpers';\nimport { isNameValid } from '../../helpers';\n\nexport function isUserNameValid(input: string, options: NameValidOptions = {}) : boolean {\n if (!isNameValid(input, options)) return false;\n\n input = input.toLowerCase();\n\n const isReservedName = [