endpoint-permissions-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,20 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/constants.ts", "../../src/state.ts", "../../src/errors.ts", "../../src/resolve.ts", "../../src/validators.ts", "../../src/context.ts", "../../src/registry.ts", "../../src/seal.ts", "../../src/permissions.ts", "../../src/validate.ts", "../../src/index.ts"],
4
+ "sourcesContent": [
5
+ "export const METHODS = ['find', 'update', 'create', 'remove'] as const;\n\nexport const GENERAL_ROLE = 'general';\n\nexport const GLOBAL_HOOK_OWNER = '*';\n\nexport const ALL_FIELDS = '*';\n\nexport const MODULE_SEPARATOR = '.';\n\nexport const PERMISSION_ID_SEPARATOR = '::';\n",
6
+ "import type { ActionDefs, GrantDefs, HookFn, Method, NamedPermissionCatalog } from './types';\nimport { GENERAL_ROLE } from './constants';\n\nexport interface PermissionReference {\n readonly role: string;\n readonly action: string;\n readonly name: string;\n}\n\nexport interface GrantEntry {\n readonly source: PermissionReference;\n readonly actions: GrantDefs;\n}\n\nexport interface NameEntry {\n readonly actions: Map<string, ActionDefs>;\n readonly grants: Map<string, GrantEntry>;\n readonly hooks: Map<string, Map<Method, HookFn[]>>;\n}\n\nexport interface ModuleEntry {\n readonly names: Map<string, NameEntry>;\n readonly hooks: Map<Method, HookFn[]>;\n}\n\ninterface Snapshot {\n readonly named: NamedPermissionCatalog;\n readonly assignable: ReadonlySet<string>;\n}\n\nexport interface State {\n roles: Set<string>;\n readonly modules: Map<string, ModuleEntry>;\n snapshot: Snapshot | null;\n}\n\nexport function getOrCreateState(): State {\n const stateKey = Symbol.for('endpoint-permissions-kit');\n const stateHost = globalThis as typeof globalThis & { [stateKey]?: State };\n\n if (stateHost[stateKey] === undefined) {\n stateHost[stateKey] = { roles: new Set([GENERAL_ROLE]), modules: new Map(), snapshot: null };\n }\n\n return stateHost[stateKey];\n}\n",
7
+ "import type { PkitErrorCode } from './types';\n\nexport type PkitError = Error & { name: 'PkitError' } & (\n | { code: Exclude<PkitErrorCode, 'PROPERTIES_NOT_ALLOWED'> }\n | { code: 'PROPERTIES_NOT_ALLOWED'; fields: readonly string[] }\n);\n\nexport function pkitError<ErrorCode extends PkitErrorCode>(code: ErrorCode, message: string): Error & {\n name: 'PkitError';\n code: ErrorCode;\n} {\n return Object.assign(new Error(message), { name: 'PkitError' as const, code });\n}\n",
8
+ "import type { Authorization, Method, PermissionId, Properties } from './types';\nimport type { NameEntry } from './state';\nimport { PERMISSION_ID_SEPARATOR } from './constants';\n\nexport type Access =\n | { readonly status: 'granted'; readonly properties: Properties; readonly authorization: Authorization }\n | { readonly status: 'disabled' }\n | { readonly status: 'unassigned' };\n\nconst DIRECT_AUTHORIZATION: Authorization = Object.freeze({ direct: true, grantedBy: Object.freeze([]) });\n\nconst DISABLED_ACCESS: Access = Object.freeze({ status: 'disabled' });\n\nconst UNASSIGNED_ACCESS: Access = Object.freeze({ status: 'unassigned' });\n\nexport function permissionIdOf(role: string, action: string, name: string): PermissionId {\n return [role, action, name].join(PERMISSION_ID_SEPARATOR) as PermissionId;\n}\n\nexport function resolveAccess(nameEntry: NameEntry, permissionId: string, role: string, method: Method, assigned: ReadonlySet<string>): Access {\n if (assigned.has(permissionId)) return resolveDirectAccess(nameEntry, role, method);\n\n return resolveGrantedAccess(nameEntry, method, assigned);\n}\n\nfunction resolveDirectAccess(nameEntry: NameEntry, role: string, method: Method): Access {\n const definition = nameEntry.actions.get(role)?.[method];\n if (!definition?.enabled) return DISABLED_ACCESS;\n\n return { status: 'granted', properties: definition.properties, authorization: DIRECT_AUTHORIZATION };\n}\n\nfunction resolveGrantedAccess(nameEntry: NameEntry, method: Method, assigned: ReadonlySet<string>): Access {\n const grantedBy: PermissionId[] = [];\n const properties = new Set<string>();\n let reachable = false;\n\n for (const [enablingId, grant] of nameEntry.grants) {\n if (!assigned.has(enablingId)) continue;\n reachable = true;\n\n const definition = grant.actions[method];\n if (!definition) continue;\n\n grantedBy.push(enablingId as PermissionId);\n for (const field of definition.properties) properties.add(field);\n }\n\n if (grantedBy.length === 0) return reachable ? DISABLED_ACCESS : UNASSIGNED_ACCESS;\n\n const authorization: Authorization = Object.freeze({ direct: false, grantedBy: Object.freeze(grantedBy.sort()) });\n\n return { status: 'granted', properties: Object.freeze([...properties]), authorization };\n}\n",
9
+ "import { ALL_FIELDS, GLOBAL_HOOK_OWNER, METHODS, MODULE_SEPARATOR, PERMISSION_ID_SEPARATOR } from './constants';\nimport { pkitError } from './errors';\nimport { permissionIdOf, resolveAccess } from './resolve';\nimport type { GrantEntry, ModuleEntry, NameEntry, PermissionReference, State } from './state';\nimport type { ActionDef, ActionDefs, Context, Data, FindInput, FindResult, GrantDefs, HookFn, Method, PkitErrorCode, ResolvedPermission, Role, UserAssignments, ValidateInput } from './types';\n\ninterface ValidationFailure {\n code: PkitErrorCode;\n message: string;\n}\n\ninterface StringRules extends ValidationFailure {\n minimumLength: number;\n}\n\ninterface DirectRegistration {\n action: string;\n name: string;\n role: string;\n}\n\ninterface GrantRegistration {\n action: string;\n name: string;\n permissionId: string;\n}\n\ninterface HookRegistration {\n action: string;\n name?: string;\n role?: string;\n method: Method;\n}\n\ninterface Identity {\n role: Role;\n assigned: ReadonlySet<string>;\n}\n\ninterface ValidatedRequest {\n registeredModule: ModuleEntry;\n nameEntry: NameEntry;\n permission: ResolvedPermission;\n data: Data | undefined;\n context: Context | undefined;\n result: FindResult | Data;\n}\n\nfunction validateObject(value: unknown, failure: ValidationFailure): asserts value is Data {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw pkitError(failure.code, failure.message);\n }\n}\n\nexport function validateStrings(value: unknown, rules: StringRules): asserts value is readonly string[] {\n if (!Array.isArray(value)) throw pkitError(rules.code, rules.message);\n\n for (const field of value) {\n if (typeof field !== 'string' || field.length < rules.minimumLength) {\n throw pkitError(rules.code, rules.message);\n }\n }\n}\n\nexport function validateContextKey(key: unknown): asserts key is 'roles' {\n if (key !== 'roles') throw pkitError('INVALID_DEFINITION', `unknown context key: \"${String(key)}\"`);\n}\n\nfunction validateOpenRegistry(state: State): void {\n if (state.snapshot) throw pkitError('SEALED', 'pkit.seal() was already called: no more registrations allowed');\n}\n\nexport function validateSnapshot<Snapshot>(snapshot: Snapshot | null): asserts snapshot is Snapshot {\n if (snapshot === null) {\n throw pkitError('NOT_SEALED', 'pkit.seal() has not been called: call it after importing every permission file');\n }\n}\n\nexport function validateRole(role: unknown, roles: ReadonlySet<string>, code: 'ROLE_NOT_DECLARED' | 'UNKNOWN_ROLE'): asserts role is Role {\n if (typeof role === 'string' && roles.has(role)) return;\n\n if (code === 'ROLE_NOT_DECLARED') {\n throw pkitError(code,\n `role \"${String(role)}\" is not declared. Available roles: ${[...roles].join(', ')}.\\n` +\n \"Is pkit.context.set('roles', [...]) missing from pkit.config.js, or was it imported after this file?\",\n );\n }\n\n throw pkitError(code, `role \"${String(role)}\" is not declared`);\n}\n\nexport function validateRoleCatalog(roles: unknown, state: State): asserts roles is readonly string[] {\n validateOpenRegistry(state);\n\n if (state.modules.size) {\n throw pkitError('INVALID_DEFINITION', 'roles must be declared before registering permissions: import pkit.config.js first');\n }\n\n validateStrings(roles, {\n code: 'INVALID_DEFINITION', message: 'roles must be an array of non-empty strings', minimumLength: 1,\n });\n\n if (roles.length === 0) throw pkitError('INVALID_DEFINITION', 'roles must declare at least one role');\n\n for (const role of roles) validateRoleSegment(role);\n}\n\nfunction isCleanSegment(value: string): boolean {\n return value.length > 0 && value.trim() === value && !value.includes(':');\n}\n\nexport function validateRoleSegment(role: unknown): asserts role is string {\n if (typeof role === 'string' && isCleanSegment(role) && role !== GLOBAL_HOOK_OWNER) return;\n\n throw pkitError('INVALID_DEFINITION',\n `invalid role: \"${String(role)}\" (non-empty string, no \":\" or surrounding whitespace; \"${GLOBAL_HOOK_OWNER}\" is reserved for global hooks)`,\n );\n}\n\nexport function validateModuleName(moduleName: unknown): asserts moduleName is string {\n if (typeof moduleName === 'string' && isCleanSegment(moduleName) && !moduleName.includes(MODULE_SEPARATOR)) return;\n\n throw pkitError('INVALID_DEFINITION',\n `invalid module name: \"${String(moduleName)}\" (non-empty string, no dots, no \":\" or surrounding whitespace)`,\n );\n}\n\nexport function validatePermissionName(name: unknown): asserts name is string {\n if (typeof name === 'string' && isCleanSegment(name) && name !== GLOBAL_HOOK_OWNER) return;\n\n throw pkitError('INVALID_DEFINITION',\n `invalid permission name: \"${String(name)}\" (non-empty string, no \":\" or surrounding whitespace; \"*\" is reserved)`,\n );\n}\n\nexport function parsePermissionId(value: unknown, failure: ValidationFailure): PermissionReference {\n if (typeof value !== 'string') throw pkitError(failure.code, failure.message);\n\n const parts = value.split(PERMISSION_ID_SEPARATOR);\n const [role, action, name] = parts;\n\n if (parts.length !== 3 || role === undefined || action === undefined || name === undefined) {\n throw pkitError(failure.code, failure.message);\n }\n\n const isValidRole = isCleanSegment(role) && role !== GLOBAL_HOOK_OWNER;\n const isValidName = isCleanSegment(name) && name !== GLOBAL_HOOK_OWNER;\n const isValidAction = action.split(MODULE_SEPARATOR).every(isCleanSegment);\n\n if (!isValidRole || !isValidName || !isValidAction) throw pkitError(failure.code, failure.message);\n\n return { role, action, name };\n}\n\nfunction validateMethod(method: unknown, failure: ValidationFailure): asserts method is Method {\n if ((METHODS as readonly unknown[]).includes(method)) return;\n\n throw pkitError(failure.code, `${failure.message}: method \"${String(method)}\" does not exist. Methods: ${METHODS.join(', ')}`);\n}\n\nfunction readActionDefinition(definition: unknown, permissionPath: string): ActionDef {\n validateObject(definition, { code: 'INVALID_DEFINITION', message: `${permissionPath}: must be an object` });\n\n if (typeof definition.enabled !== 'boolean') {\n throw pkitError('INVALID_DEFINITION', `${permissionPath}: enabled must be a boolean`);\n }\n\n const { properties } = definition;\n\n if (properties === ALL_FIELDS) return Object.freeze({ enabled: definition.enabled, properties });\n\n validateStrings(properties, {\n code: 'INVALID_DEFINITION', message: `${permissionPath}: properties must be string[] or '*'`, minimumLength: 1,\n });\n\n if (properties.includes(ALL_FIELDS)) {\n throw pkitError('INVALID_DEFINITION', `${permissionPath}: '${ALL_FIELDS}' is only allowed as the whole properties value`);\n }\n\n if (new Set(properties).size !== properties.length) {\n throw pkitError('INVALID_DEFINITION', `${permissionPath}: properties contains duplicate fields`);\n }\n\n return Object.freeze({ enabled: definition.enabled, properties: Object.freeze([...properties]) });\n}\n\nfunction readActionDefinitions(actions: unknown, permissionPath: string): ActionDefs {\n validateObject(actions, { code: 'INVALID_DEFINITION', message: `${permissionPath}: registerActions expects an object` });\n\n const registeredActions: ActionDefs = Object.create(null);\n\n for (const [method, definition] of Object.entries(actions)) {\n validateMethod(method, { code: 'INVALID_DEFINITION', message: permissionPath });\n registeredActions[method] = readActionDefinition(definition, `${permissionPath}.${method}`);\n }\n\n return Object.freeze(registeredActions);\n}\n\nexport function validateActions(actions: unknown, registration: DirectRegistration, state: State): ActionDefs {\n const { action, name, role } = registration;\n\n validateOpenRegistry(state);\n validateRole(role, state.roles, 'ROLE_NOT_DECLARED');\n\n if (state.modules.get(action)?.names.get(name)?.actions.has(role)) {\n throw pkitError('DUPLICATE_REGISTRATION', `\"${action}::${name}\" already has actions registered for role \"${role}\"`);\n }\n\n return readActionDefinitions(actions, `${action}::${name} [${role}]`);\n}\n\nexport function validateGrantActions(actions: unknown, registration: GrantRegistration, state: State): GrantEntry {\n const { action, name, permissionId } = registration;\n\n validateOpenRegistry(state);\n\n const source = parsePermissionId(permissionId, {\n code: 'INVALID_DEFINITION',\n message: `\"${action}::${name}\": invalid grantTo identifier: \"${String(permissionId)}\" (format role::module::name)`,\n });\n\n validateRole(source.role, state.roles, 'ROLE_NOT_DECLARED');\n\n if (source.action === action && source.name === name) {\n throw pkitError('INVALID_DEFINITION', `\"${permissionId}\" cannot grant to itself`);\n }\n\n if (state.modules.get(action)?.names.get(name)?.grants.has(permissionId)) {\n throw pkitError('DUPLICATE_REGISTRATION', `\"${action}::${name}\" already has a grant for \"${permissionId}\"`);\n }\n\n const permissionPath = `${action}::${name} [grantTo ${permissionId}]`;\n const registeredActions = readActionDefinitions(actions, permissionPath);\n\n for (const [method, definition] of Object.entries(registeredActions)) {\n if (definition.enabled !== true) {\n throw pkitError('INVALID_DEFINITION', `${permissionPath}.${method}: a grant does not allow enabled: false`);\n }\n\n if (definition.properties === ALL_FIELDS) {\n throw pkitError('INVALID_DEFINITION', `${permissionPath}.${method}: a grant requires an explicit properties list`);\n }\n }\n\n return { source, actions: registeredActions as GrantDefs };\n}\n\nexport function validateHook(hook: unknown, registration: HookRegistration, state: State): asserts hook is HookFn {\n const { action, name, role, method } = registration;\n\n validateOpenRegistry(state);\n\n if (role !== undefined && role !== GLOBAL_HOOK_OWNER) validateRole(role, state.roles, 'ROLE_NOT_DECLARED');\n\n const permissionPath = name === undefined ? action : `${action}::${name}`;\n\n validateMethod(method, { code: 'INVALID_DEFINITION', message: permissionPath });\n\n if (typeof hook !== 'function') throw pkitError('INVALID_DEFINITION', `${permissionPath}: hook(\"${method}\") expects a function`);\n}\n\nfunction declaresMethod(nameEntry: NameEntry, method: string): boolean {\n for (const actions of nameEntry.actions.values()) {\n if (Object.hasOwn(actions, method)) return true;\n }\n\n return false;\n}\n\nfunction hasAccessPath(nameEntry: NameEntry, role: string, method: Method): boolean {\n if (nameEntry.actions.get(role)?.[method]) return true;\n\n for (const grant of nameEntry.grants.values()) {\n if (grant.source.role === role && grant.actions[method]) return true;\n }\n\n return false;\n}\n\nfunction validateGrantReferences(permissionPath: string, nameEntry: NameEntry, modules: ReadonlyMap<string, ModuleEntry>): void {\n for (const [permissionId, grant] of nameEntry.grants) {\n const sourceEntry = modules.get(grant.source.action)?.names.get(grant.source.name);\n\n if (!sourceEntry?.actions.has(grant.source.role)) {\n throw pkitError('INVALID_DEFINITION', `\"${permissionPath}\": grantTo \"${permissionId}\" references a permission with no registered actions`);\n }\n\n for (const method of Object.keys(grant.actions)) {\n if (declaresMethod(nameEntry, method)) continue;\n\n throw pkitError('INVALID_DEFINITION',\n `\"${permissionPath}\": grantTo \"${permissionId}\" grants \"${method}\", which no role declares on that permission`,\n );\n }\n }\n}\n\nfunction validateRoleHooks(permissionPath: string, nameEntry: NameEntry): void {\n for (const [hookRole, methodHooks] of nameEntry.hooks) {\n if (hookRole === GLOBAL_HOOK_OWNER) continue;\n\n for (const method of methodHooks.keys()) {\n if (hasAccessPath(nameEntry, hookRole, method)) continue;\n\n throw pkitError('INVALID_DEFINITION',\n `\"${permissionPath}\": hook for \"${hookRole}\" on \"${method}\" has no registered actions or grant for that role`,\n );\n }\n }\n}\n\nexport function validateSealedRegistry(modules: ReadonlyMap<string, ModuleEntry>): void {\n for (const [action, registeredModule] of modules) {\n if (registeredModule.names.size === 0) {\n throw pkitError('INVALID_DEFINITION', `\"${action}\" has hooks but no name with registered actions`);\n }\n\n for (const [name, nameEntry] of registeredModule.names) {\n const permissionPath = `${action}::${name}`;\n\n if (nameEntry.actions.size === 0) {\n throw pkitError('INVALID_DEFINITION', `\"${permissionPath}\" has no registered actions for any role`);\n }\n\n validateGrantReferences(permissionPath, nameEntry, modules);\n validateRoleHooks(permissionPath, nameEntry);\n }\n }\n}\n\nfunction validateAssignments(permissions: unknown, role: string, assignable: ReadonlySet<string>): ReadonlySet<string> {\n validateStrings(permissions, { code: 'INVALID_INPUT', message: 'permissions must be an array of strings', minimumLength: 1 });\n\n const assigned = new Set<string>();\n\n for (const permissionId of permissions) {\n const reference = parsePermissionId(permissionId, {\n code: 'INVALID_INPUT', message: `invalid permission identifier: \"${permissionId}\" (format role::module::name)`,\n });\n\n if (reference.role !== role) {\n throw pkitError('PERMISSION_ROLE_MISMATCH', `\"${permissionId}\" belongs to role \"${reference.role}\", not the authenticated role \"${role}\"`);\n }\n\n if (!assignable.has(permissionId)) {\n throw pkitError('UNKNOWN_PERMISSION', `\"${permissionId}\" is not an assignable permission`);\n }\n\n assigned.add(permissionId);\n }\n\n return assigned;\n}\n\nexport function validateIdentity(assignments: UserAssignments, state: State): Identity {\n validateSnapshot(state.snapshot);\n\n const { role, permissions } = assignments;\n\n if (typeof role !== 'string') throw pkitError('INVALID_INPUT', 'role is required');\n validateRole(role, state.roles, 'UNKNOWN_ROLE');\n\n return { role, assigned: validateAssignments(permissions, role, state.snapshot.assignable) };\n}\n\nfunction trimSelection(select: unknown, properties: readonly string[]): readonly string[] {\n validateStrings(select, { code: 'INVALID_INPUT', message: 'select must be an array of strings', minimumLength: 0 });\n\n const selectedFields: string[] = [];\n\n for (const field of select) {\n if (properties.includes(field)) selectedFields.push(field);\n }\n\n return selectedFields;\n}\n\nfunction rejectForbiddenFields(data: Data, properties: readonly string[], permissionPath: string): void {\n const forbiddenFields: string[] = [];\n\n for (const field of Object.keys(data)) {\n if (!properties.includes(field)) forbiddenFields.push(field);\n }\n\n if (forbiddenFields.length === 0) return;\n\n throw Object.assign(\n pkitError('PROPERTIES_NOT_ALLOWED', `fields not allowed in \"${permissionPath}\": ${forbiddenFields.join(', ')}`),\n { fields: forbiddenFields },\n );\n}\n\nexport function validateRequest(input: ValidateInput, state: State): ValidatedRequest {\n validateSnapshot(state.snapshot);\n\n const { action, name, method } = input;\n\n validateMethod(method, { code: 'INVALID_INPUT', message: 'method is required' });\n if (method !== 'find' && Object.hasOwn(input, 'select')) throw pkitError('INVALID_INPUT', 'select only applies to find');\n if (typeof action !== 'string' || typeof name !== 'string') throw pkitError('INVALID_INPUT', 'action and name are required');\n\n const { role, assigned } = validateIdentity(input, state);\n\n const registeredModule = state.modules.get(action);\n\n if (!registeredModule) throw pkitError('UNKNOWN_ACTION', `module \"${action}\" is not registered`);\n\n const nameEntry = registeredModule.names.get(name);\n if (!nameEntry) throw pkitError('UNKNOWN_PERMISSION', `permission \"${action}::${name}\" is not registered`);\n\n const permissionId = permissionIdOf(role, action, name);\n const access = resolveAccess(nameEntry, permissionId, role, method, assigned);\n\n if (access.status === 'unassigned') {\n throw pkitError('PERMISSION_NOT_ASSIGNED', `\"${permissionId}\" is not assigned or granted by the user permissions`);\n }\n\n if (access.status === 'disabled') throw pkitError('METHOD_DISABLED', `\"${permissionId}.${method}\" is not enabled`);\n\n const { data, context } = input;\n\n if (context !== undefined) validateObject(context, { code: 'INVALID_INPUT', message: 'context must be an object' });\n\n const { properties, authorization } = access;\n const permission: ResolvedPermission = Object.freeze({ role, action, name, permissionId, method, enabled: true, properties, authorization });\n const request = { registeredModule, nameEntry, permission, data, context };\n\n if (method === 'find') {\n if (data !== undefined) validateObject(data, { code: 'INVALID_INPUT', message: 'data must be an object' });\n\n const { select } = input as FindInput;\n\n if (select === undefined) return { ...request, result: properties };\n if (properties === ALL_FIELDS) {\n validateStrings(select, { code: 'INVALID_INPUT', message: 'select must be an array of strings', minimumLength: 0 });\n return { ...request, result: select };\n }\n\n return { ...request, result: trimSelection(select, properties) };\n }\n\n validateObject(data, { code: 'INVALID_INPUT', message: 'data must be an object' });\n if (properties !== ALL_FIELDS) rejectForbiddenFields(data, properties, `${permissionId}.${method}`);\n\n return { ...request, result: data };\n}\n",
10
+ "import { getOrCreateState } from './state';\nimport { validateContextKey, validateRoleCatalog } from './validators';\n\nfunction setRoles(key: 'roles', roles: readonly string[]): void {\n validateContextKey(key);\n\n const state = getOrCreateState();\n\n validateRoleCatalog(roles, state);\n\n state.roles = new Set(roles);\n}\n\nfunction getRoles(key: 'roles'): readonly string[] {\n validateContextKey(key);\n\n return [...getOrCreateState().roles];\n}\n\nexport const context = Object.freeze({ set: setRoles, get: getRoles });\n",
11
+ "import type { ActionDefs, GrantDefs, HookFn, Method, PermissionId, Role } from './types';\nimport { GLOBAL_HOOK_OWNER, MODULE_SEPARATOR } from './constants';\nimport { getOrCreateState, type ModuleEntry, type NameEntry, type State } from './state';\nimport { validateActions, validateGrantActions, validateHook, validateModuleName, validatePermissionName, validateRoleSegment } from './validators';\n\nexport interface ModuleBuilder {\n module(segment: string): ModuleBuilder;\n name(name: string): NameBuilder;\n hook(method: Method, hook: HookFn): ModuleBuilder;\n}\n\nexport interface NameBuilder {\n role(role: Role): RoleBuilder;\n grantTo(permissionId: PermissionId): GrantBuilder;\n hook(method: Method, hook: HookFn): NameBuilder;\n}\n\nexport interface RoleBuilder {\n registerActions(actions: ActionDefs): RoleBuilder;\n hook(method: Method, hook: HookFn): RoleBuilder;\n}\n\nexport interface GrantBuilder {\n registerActions(actions: GrantDefs): GrantBuilder;\n}\n\ninterface ModuleScope {\n action: string;\n builder: ModuleBuilder;\n}\n\ninterface NameScope<Builder> {\n action: string;\n name: string;\n role: string;\n builder: Builder;\n}\n\ninterface GrantScope {\n action: string;\n name: string;\n permissionId: string;\n builder: GrantBuilder;\n}\n\nfunction appendHook(methodHooks: Map<Method, HookFn[]>, method: Method, hook: HookFn): void {\n const hooks = methodHooks.get(method) ?? [];\n\n methodHooks.set(method, hooks);\n hooks.push(hook);\n}\n\nfunction registerActions(scope: NameScope<RoleBuilder>, actions: ActionDefs): RoleBuilder {\n const state = getOrCreateState();\n const registeredActions = validateActions(actions, scope, state);\n\n ensureName(state, scope.action, scope.name).actions.set(scope.role, registeredActions);\n\n return scope.builder;\n}\n\nfunction registerGrant(scope: GrantScope, actions: GrantDefs): GrantBuilder {\n const state = getOrCreateState();\n const grant = validateGrantActions(actions, scope, state);\n\n ensureName(state, scope.action, scope.name).grants.set(scope.permissionId, grant);\n\n return scope.builder;\n}\n\nfunction registerModuleHook(scope: ModuleScope, method: Method, hook: HookFn): ModuleBuilder {\n const state = getOrCreateState();\n\n validateHook(hook, { action: scope.action, method }, state);\n\n appendHook(ensureModule(state, scope.action).hooks, method, hook);\n\n return scope.builder;\n}\n\nfunction registerNameHook<Builder>(scope: NameScope<Builder>, method: Method, hook: HookFn): Builder {\n const state = getOrCreateState();\n\n validateHook(hook, { ...scope, method }, state);\n\n const nameEntry = ensureName(state, scope.action, scope.name);\n const roleHooks = nameEntry.hooks.get(scope.role) ?? new Map<Method, HookFn[]>();\n\n nameEntry.hooks.set(scope.role, roleHooks);\n\n appendHook(roleHooks, method, hook);\n\n return scope.builder;\n}\n\nfunction createRoleBuilder(action: string, name: string, role: string): RoleBuilder {\n validateRoleSegment(role);\n\n const builder = {} as RoleBuilder;\n const scope = { action, name, role, builder };\n\n return Object.assign(builder, {\n registerActions: registerActions.bind(null, scope),\n hook: (registerNameHook<RoleBuilder>).bind(null, scope),\n });\n}\n\nfunction createGrantBuilder(action: string, name: string, permissionId: string): GrantBuilder {\n const builder = {} as GrantBuilder;\n const scope = { action, name, permissionId, builder };\n\n return Object.assign(builder, { registerActions: registerGrant.bind(null, scope) });\n}\n\nfunction createNameBuilder(action: string, name: string): NameBuilder {\n validatePermissionName(name);\n\n const builder = {} as NameBuilder;\n const scope = { action, name, role: GLOBAL_HOOK_OWNER, builder };\n\n return Object.assign(builder, {\n role: createRoleBuilder.bind(null, action, name),\n grantTo: createGrantBuilder.bind(null, action, name),\n hook: (registerNameHook<NameBuilder>).bind(null, scope),\n });\n}\n\nfunction createModuleBuilder(action: string): ModuleBuilder {\n const builder = {} as ModuleBuilder;\n const scope = { action, builder };\n\n return Object.assign(builder, {\n module: appendModule.bind(null, action),\n name: createNameBuilder.bind(null, action),\n hook: registerModuleHook.bind(null, scope),\n });\n}\n\nfunction appendModule(parentAction: string, segment: string): ModuleBuilder {\n validateModuleName(segment);\n\n return createModuleBuilder(`${parentAction}${MODULE_SEPARATOR}${segment}`);\n}\n\nexport function defineModule(segment: string): ModuleBuilder {\n validateModuleName(segment);\n\n return createModuleBuilder(segment);\n}\n\nfunction ensureModule(state: State, action: string): ModuleEntry {\n const registeredModule = state.modules.get(action);\n\n if (registeredModule) return registeredModule;\n\n const newModule: ModuleEntry = { names: new Map(), hooks: new Map() };\n\n state.modules.set(action, newModule);\n\n return newModule;\n}\n\nfunction ensureName(state: State, action: string, name: string): NameEntry {\n const registeredModule = ensureModule(state, action);\n const registeredName = registeredModule.names.get(name);\n\n if (registeredName) return registeredName;\n\n const newName: NameEntry = { actions: new Map(), grants: new Map(), hooks: new Map() };\n\n registeredModule.names.set(name, newName);\n\n return newName;\n}\n",
12
+ "import type { Method, NamedPermissionCatalog, PermissionEntry } from './types';\nimport { getOrCreateState } from './state';\nimport { permissionIdOf } from './resolve';\nimport { validateSealedRegistry } from './validators';\n\nexport function seal(): void {\n const state = getOrCreateState();\n\n if (state.snapshot) return;\n\n validateSealedRegistry(state.modules);\n\n const named: Record<string, Readonly<Partial<Record<Method, PermissionEntry>>>> = Object.create(null);\n\n for (const [action, registeredModule] of state.modules) {\n for (const [name, nameEntry] of registeredModule.names) {\n for (const [role, actions] of nameEntry.actions) {\n named[permissionIdOf(role, action, name)] = actions;\n }\n }\n }\n\n state.snapshot = { named: Object.freeze(named) as NamedPermissionCatalog, assignable: new Set(Object.keys(named)) };\n}\n",
13
+ "import type { MethodAccessMap, NamedPermissionCatalog, UserAssignments, UserPermissionMap } from './types';\nimport { METHODS } from './constants';\nimport { permissionIdOf, resolveAccess } from './resolve';\nimport { getOrCreateState, type NameEntry } from './state';\nimport { validateIdentity, validateSnapshot } from './validators';\n\nfunction getNamedCatalog(): NamedPermissionCatalog {\n const { snapshot } = getOrCreateState();\n\n validateSnapshot(snapshot);\n\n return snapshot.named;\n}\n\nfunction resolveMethodAccess(nameEntry: NameEntry, permissionId: string, role: string, assigned: ReadonlySet<string>): MethodAccessMap | undefined {\n const methodAccess: Record<string, boolean> = Object.create(null);\n let reachable = false;\n\n for (const method of METHODS) {\n const access = resolveAccess(nameEntry, permissionId, role, method, assigned);\n\n methodAccess[method] = access.status === 'granted';\n if (access.status !== 'unassigned') reachable = true;\n }\n\n return reachable ? Object.freeze(methodAccess) as MethodAccessMap : undefined;\n}\n\nfunction forUser(assignments: UserAssignments): UserPermissionMap {\n const state = getOrCreateState();\n const { role, assigned } = validateIdentity(assignments, state);\n\n const access: Record<string, MethodAccessMap> = Object.create(null);\n\n for (const [action, registeredModule] of state.modules) {\n for (const [name, nameEntry] of registeredModule.names) {\n const permissionId = permissionIdOf(role, action, name);\n const methodAccess = resolveMethodAccess(nameEntry, permissionId, role, assigned);\n\n if (methodAccess) access[permissionId] = methodAccess;\n }\n }\n\n return Object.freeze(access) as UserPermissionMap;\n}\n\nexport const permissions = Object.freeze(\n Object.defineProperty({ forUser }, 'named', { get: getNamedCatalog, enumerable: true, configurable: false }),\n) as {\n readonly named: NamedPermissionCatalog;\n readonly forUser: typeof forUser;\n};\n",
14
+ "import type { Context, Data, FindInput, FindResult, HookFn, ResolvedPermission, ValidateInput, ValidateResult, ValidationError, WriteInput } from './types';\nimport { GLOBAL_HOOK_OWNER } from './constants';\nimport { getOrCreateState } from './state';\nimport type { PkitError } from './errors';\nimport { validateRequest } from './validators';\n\ninterface HookCall {\n data: Data | undefined;\n context: Context | undefined;\n permission: ResolvedPermission;\n}\n\nasync function invokeHook(hook: HookFn, request: HookCall): Promise<unknown> {\n return hook(request.data, request.context, request.permission);\n}\n\nfunction describeHookFailure(reason: unknown): string {\n try {\n return reason instanceof Error ? reason.message : String(reason);\n } catch {\n return 'the hook threw a value that cannot be described';\n }\n}\n\nexport function validate(input: FindInput): Promise<ValidateResult<FindResult>>;\nexport function validate<RequestData extends Data>(input: WriteInput<RequestData>): Promise<ValidateResult<RequestData>>;\nexport async function validate(input: ValidateInput): Promise<ValidateResult<FindResult | Data>> {\n try {\n const request = validateRequest(input, getOrCreateState());\n const { registeredModule, nameEntry, permission, result } = request;\n const { method, role } = permission;\n\n const hookGroups = [\n registeredModule.hooks.get(method),\n nameEntry.hooks.get(GLOBAL_HOOK_OWNER)?.get(method),\n nameEntry.hooks.get(role)?.get(method),\n ];\n\n const hookCalls: Promise<unknown>[] = [];\n\n for (const hooks of hookGroups) {\n if (!hooks) continue;\n for (const hook of hooks) hookCalls.push(invokeHook(hook, request));\n }\n\n const hookResults = await Promise.allSettled(hookCalls);\n const errors: ValidationError[] = [];\n\n for (const hookResult of hookResults) {\n if (hookResult.status === 'fulfilled') continue;\n\n const hookCause: unknown = hookResult.reason;\n errors.push({ code: 'HOOK_ERROR', message: describeHookFailure(hookCause), cause: hookCause });\n }\n\n if (errors.length) return { result: null, errors: Object.freeze(errors) };\n\n return { result, errors: Object.freeze([] as const) };\n } catch (cause) {\n if (cause instanceof Error && cause.name === 'PkitError') {\n const permissionError = cause as PkitError;\n const error: ValidationError = permissionError.code === 'PROPERTIES_NOT_ALLOWED'\n ? { code: permissionError.code, message: permissionError.message, fields: permissionError.fields }\n : { code: permissionError.code, message: permissionError.message };\n\n return { result: null, errors: Object.freeze([error]) };\n }\n\n return {\n result: null,\n errors: Object.freeze([{ code: 'VALIDATION_ERROR', message: 'permission could not be validated', cause }]),\n };\n }\n}\n",
15
+ "import { context } from './context';\nimport { defineModule } from './registry';\nimport { seal } from './seal';\nimport { permissions } from './permissions';\nimport { validate } from './validate';\n\nexport type {\n ActionDef,\n ActionDefs,\n Authorization,\n Context,\n Data,\n FindInput,\n FindResult,\n GrantDef,\n GrantDefs,\n HookFn,\n Method,\n MethodAccessMap,\n NamedPermissionCatalog,\n PermissionEntry,\n PermissionId,\n PkitErrorCode,\n Properties,\n ResolvedPermission,\n Role,\n RoleRegistry,\n UserAssignments,\n UserPermissionMap,\n ValidateInput,\n ValidateResult,\n ValidationError,\n ValidationErrorCode,\n WriteInput,\n} from './types';\nexport { METHODS } from './constants';\nexport type { PkitError } from './errors';\nexport type { GrantBuilder, ModuleBuilder, NameBuilder, RoleBuilder } from './registry';\nexport { context, seal, permissions, validate, defineModule as module };\n\nexport const pkit = Object.freeze({ context, module: defineModule, seal, permissions, validate });\nexport default pkit;\n"
16
+ ],
17
+ "mappings": "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",
18
+ "debugId": "60F9871502AF5BAC64756E2164756E21",
19
+ "names": []
20
+ }
@@ -0,0 +1,2 @@
1
+
2
+ //# debugId=F2B76011AEAE140064756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "F2B76011AEAE140064756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,17 @@
1
+ interface GenerateOptions {
2
+ cwd: string;
3
+ config?: string;
4
+ out?: string;
5
+ }
6
+ interface GenerateResult {
7
+ configPath: string;
8
+ outPath: string;
9
+ roles: readonly string[];
10
+ }
11
+ interface CheckResult extends GenerateResult {
12
+ isStale: boolean;
13
+ }
14
+ export declare function generate(options: GenerateOptions): Promise<GenerateResult>;
15
+ export declare function checkGenerated(options: GenerateOptions): Promise<CheckResult>;
16
+ export declare function main(commandArguments: readonly string[]): Promise<void>;
17
+ export {};
@@ -0,0 +1,8 @@
1
+ export declare const EXIT_CODE: {
2
+ readonly success: 0;
3
+ readonly failure: 1;
4
+ readonly usage: 2;
5
+ };
6
+ export declare const CATALOG_MARKER = "__PKIT_CATALOG__";
7
+ export declare const CHILD_TIMEOUT_MS = 30000;
8
+ export declare const CHILD_MAX_BUFFER_BYTES = 1048576;
@@ -0,0 +1,6 @@
1
+ export declare const METHODS: readonly ["find", "update", "create", "remove"];
2
+ export declare const GENERAL_ROLE = "general";
3
+ export declare const GLOBAL_HOOK_OWNER = "*";
4
+ export declare const ALL_FIELDS = "*";
5
+ export declare const MODULE_SEPARATOR = ".";
6
+ export declare const PERMISSION_ID_SEPARATOR = "::";
@@ -0,0 +1,7 @@
1
+ declare function setRoles(key: 'roles', roles: readonly string[]): void;
2
+ declare function getRoles(key: 'roles'): readonly string[];
3
+ export declare const context: Readonly<{
4
+ set: typeof setRoles;
5
+ get: typeof getRoles;
6
+ }>;
7
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { PkitErrorCode } from './types';
2
+ export type PkitError = Error & {
3
+ name: 'PkitError';
4
+ } & ({
5
+ code: Exclude<PkitErrorCode, 'PROPERTIES_NOT_ALLOWED'>;
6
+ } | {
7
+ code: 'PROPERTIES_NOT_ALLOWED';
8
+ fields: readonly string[];
9
+ });
10
+ export declare function pkitError<ErrorCode extends PkitErrorCode>(code: ErrorCode, message: string): Error & {
11
+ name: 'PkitError';
12
+ code: ErrorCode;
13
+ };
@@ -0,0 +1,24 @@
1
+ import { context } from './context';
2
+ import { defineModule } from './registry';
3
+ import { seal } from './seal';
4
+ import { permissions } from './permissions';
5
+ import { validate } from './validate';
6
+ export type { ActionDef, ActionDefs, Authorization, Context, Data, FindInput, FindResult, GrantDef, GrantDefs, HookFn, Method, MethodAccessMap, NamedPermissionCatalog, PermissionEntry, PermissionId, PkitErrorCode, Properties, ResolvedPermission, Role, RoleRegistry, UserAssignments, UserPermissionMap, ValidateInput, ValidateResult, ValidationError, ValidationErrorCode, WriteInput, } from './types';
7
+ export { METHODS } from './constants';
8
+ export type { PkitError } from './errors';
9
+ export type { GrantBuilder, ModuleBuilder, NameBuilder, RoleBuilder } from './registry';
10
+ export { context, seal, permissions, validate, defineModule as module };
11
+ export declare const pkit: Readonly<{
12
+ context: Readonly<{
13
+ set: (key: "roles", roles: readonly string[]) => void;
14
+ get: (key: "roles") => readonly string[];
15
+ }>;
16
+ module: typeof defineModule;
17
+ seal: typeof seal;
18
+ permissions: {
19
+ readonly named: import("./types").NamedPermissionCatalog;
20
+ readonly forUser: (assignments: import("./types").UserAssignments) => import("./types").UserPermissionMap;
21
+ };
22
+ validate: typeof validate;
23
+ }>;
24
+ export default pkit;
@@ -0,0 +1,7 @@
1
+ import type { NamedPermissionCatalog, UserAssignments, UserPermissionMap } from './types';
2
+ declare function forUser(assignments: UserAssignments): UserPermissionMap;
3
+ export declare const permissions: {
4
+ readonly named: NamedPermissionCatalog;
5
+ readonly forUser: typeof forUser;
6
+ };
7
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { ActionDefs, GrantDefs, HookFn, Method, PermissionId, Role } from './types';
2
+ export interface ModuleBuilder {
3
+ module(segment: string): ModuleBuilder;
4
+ name(name: string): NameBuilder;
5
+ hook(method: Method, hook: HookFn): ModuleBuilder;
6
+ }
7
+ export interface NameBuilder {
8
+ role(role: Role): RoleBuilder;
9
+ grantTo(permissionId: PermissionId): GrantBuilder;
10
+ hook(method: Method, hook: HookFn): NameBuilder;
11
+ }
12
+ export interface RoleBuilder {
13
+ registerActions(actions: ActionDefs): RoleBuilder;
14
+ hook(method: Method, hook: HookFn): RoleBuilder;
15
+ }
16
+ export interface GrantBuilder {
17
+ registerActions(actions: GrantDefs): GrantBuilder;
18
+ }
19
+ export declare function defineModule(segment: string): ModuleBuilder;
@@ -0,0 +1,13 @@
1
+ import type { Authorization, Method, PermissionId, Properties } from './types';
2
+ import type { NameEntry } from './state';
3
+ export type Access = {
4
+ readonly status: 'granted';
5
+ readonly properties: Properties;
6
+ readonly authorization: Authorization;
7
+ } | {
8
+ readonly status: 'disabled';
9
+ } | {
10
+ readonly status: 'unassigned';
11
+ };
12
+ export declare function permissionIdOf(role: string, action: string, name: string): PermissionId;
13
+ export declare function resolveAccess(nameEntry: NameEntry, permissionId: string, role: string, method: Method, assigned: ReadonlySet<string>): Access;
@@ -0,0 +1 @@
1
+ export declare function seal(): void;
@@ -0,0 +1,30 @@
1
+ import type { ActionDefs, GrantDefs, HookFn, Method, NamedPermissionCatalog } from './types';
2
+ export interface PermissionReference {
3
+ readonly role: string;
4
+ readonly action: string;
5
+ readonly name: string;
6
+ }
7
+ export interface GrantEntry {
8
+ readonly source: PermissionReference;
9
+ readonly actions: GrantDefs;
10
+ }
11
+ export interface NameEntry {
12
+ readonly actions: Map<string, ActionDefs>;
13
+ readonly grants: Map<string, GrantEntry>;
14
+ readonly hooks: Map<string, Map<Method, HookFn[]>>;
15
+ }
16
+ export interface ModuleEntry {
17
+ readonly names: Map<string, NameEntry>;
18
+ readonly hooks: Map<Method, HookFn[]>;
19
+ }
20
+ interface Snapshot {
21
+ readonly named: NamedPermissionCatalog;
22
+ readonly assignable: ReadonlySet<string>;
23
+ }
24
+ export interface State {
25
+ roles: Set<string>;
26
+ readonly modules: Map<string, ModuleEntry>;
27
+ snapshot: Snapshot | null;
28
+ }
29
+ export declare function getOrCreateState(): State;
30
+ export {};
@@ -0,0 +1,81 @@
1
+ import type { ALL_FIELDS, METHODS } from './constants';
2
+ export interface RoleRegistry {
3
+ general: true;
4
+ }
5
+ export type Role = keyof RoleRegistry & string;
6
+ export type Method = (typeof METHODS)[number];
7
+ export type Properties = readonly string[] | typeof ALL_FIELDS;
8
+ export type PermissionId = `${Role}::${string}::${string}`;
9
+ export interface ActionDef {
10
+ enabled: boolean;
11
+ properties: Properties;
12
+ }
13
+ export type ActionDefs = Partial<Record<Method, ActionDef>>;
14
+ export interface GrantDef {
15
+ enabled: true;
16
+ properties: readonly string[];
17
+ }
18
+ export type GrantDefs = Partial<Record<Method, GrantDef>>;
19
+ export type Data = Record<string, unknown>;
20
+ export type Context = Record<string, unknown>;
21
+ export interface Authorization {
22
+ readonly direct: boolean;
23
+ readonly grantedBy: readonly PermissionId[];
24
+ }
25
+ export interface ResolvedPermission {
26
+ readonly role: Role;
27
+ readonly action: string;
28
+ readonly name: string;
29
+ readonly permissionId: PermissionId;
30
+ readonly method: Method;
31
+ readonly enabled: true;
32
+ readonly properties: Properties;
33
+ readonly authorization: Authorization;
34
+ }
35
+ export type HookFn = (data: Data | undefined, context: Context | undefined, permission: ResolvedPermission) => unknown;
36
+ export type ValidationError = {
37
+ readonly code: Exclude<PkitErrorCode, 'PROPERTIES_NOT_ALLOWED'>;
38
+ readonly message: string;
39
+ } | {
40
+ readonly code: 'PROPERTIES_NOT_ALLOWED';
41
+ readonly message: string;
42
+ readonly fields: readonly string[];
43
+ } | {
44
+ readonly code: 'HOOK_ERROR' | 'VALIDATION_ERROR';
45
+ readonly message: string;
46
+ readonly cause: unknown;
47
+ };
48
+ export type ValidationErrorCode = ValidationError['code'];
49
+ export type PkitErrorCode = 'ROLE_NOT_DECLARED' | 'DUPLICATE_REGISTRATION' | 'INVALID_DEFINITION' | 'INVALID_INPUT' | 'SEALED' | 'NOT_SEALED' | 'UNKNOWN_ROLE' | 'UNKNOWN_ACTION' | 'UNKNOWN_PERMISSION' | 'PERMISSION_ROLE_MISMATCH' | 'PERMISSION_NOT_ASSIGNED' | 'METHOD_DISABLED' | 'PROPERTIES_NOT_ALLOWED';
50
+ export interface UserAssignments {
51
+ role: Role;
52
+ permissions: readonly string[];
53
+ }
54
+ interface PermissionInput extends UserAssignments {
55
+ action: string;
56
+ name: string;
57
+ context?: Context;
58
+ }
59
+ export interface FindInput extends PermissionInput {
60
+ method: 'find';
61
+ select?: readonly string[];
62
+ data?: Data;
63
+ }
64
+ export interface WriteInput<RequestData extends Data = Data> extends PermissionInput {
65
+ method: Exclude<Method, 'find'>;
66
+ data: RequestData;
67
+ }
68
+ export type ValidateInput = FindInput | WriteInput;
69
+ export type FindResult = Properties;
70
+ export type ValidateResult<Result> = {
71
+ readonly result: Result;
72
+ readonly errors: readonly [];
73
+ } | {
74
+ readonly result: null;
75
+ readonly errors: readonly ValidationError[];
76
+ };
77
+ export type PermissionEntry = Readonly<ActionDef>;
78
+ export type NamedPermissionCatalog = Readonly<Record<PermissionId, Readonly<Partial<Record<Method, PermissionEntry>>>>>;
79
+ export type MethodAccessMap = Readonly<Record<Method, boolean>>;
80
+ export type UserPermissionMap = Readonly<Record<PermissionId, MethodAccessMap>>;
81
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { Data, FindInput, FindResult, ValidateResult, WriteInput } from './types';
2
+ export declare function validate(input: FindInput): Promise<ValidateResult<FindResult>>;
3
+ export declare function validate<RequestData extends Data>(input: WriteInput<RequestData>): Promise<ValidateResult<RequestData>>;
@@ -0,0 +1,53 @@
1
+ import type { GrantEntry, ModuleEntry, NameEntry, PermissionReference, State } from './state';
2
+ import type { ActionDefs, Context, Data, FindResult, HookFn, Method, PkitErrorCode, ResolvedPermission, Role, UserAssignments, ValidateInput } from './types';
3
+ interface ValidationFailure {
4
+ code: PkitErrorCode;
5
+ message: string;
6
+ }
7
+ interface StringRules extends ValidationFailure {
8
+ minimumLength: number;
9
+ }
10
+ interface DirectRegistration {
11
+ action: string;
12
+ name: string;
13
+ role: string;
14
+ }
15
+ interface GrantRegistration {
16
+ action: string;
17
+ name: string;
18
+ permissionId: string;
19
+ }
20
+ interface HookRegistration {
21
+ action: string;
22
+ name?: string;
23
+ role?: string;
24
+ method: Method;
25
+ }
26
+ interface Identity {
27
+ role: Role;
28
+ assigned: ReadonlySet<string>;
29
+ }
30
+ interface ValidatedRequest {
31
+ registeredModule: ModuleEntry;
32
+ nameEntry: NameEntry;
33
+ permission: ResolvedPermission;
34
+ data: Data | undefined;
35
+ context: Context | undefined;
36
+ result: FindResult | Data;
37
+ }
38
+ export declare function validateStrings(value: unknown, rules: StringRules): asserts value is readonly string[];
39
+ export declare function validateContextKey(key: unknown): asserts key is 'roles';
40
+ export declare function validateSnapshot<Snapshot>(snapshot: Snapshot | null): asserts snapshot is Snapshot;
41
+ export declare function validateRole(role: unknown, roles: ReadonlySet<string>, code: 'ROLE_NOT_DECLARED' | 'UNKNOWN_ROLE'): asserts role is Role;
42
+ export declare function validateRoleCatalog(roles: unknown, state: State): asserts roles is readonly string[];
43
+ export declare function validateRoleSegment(role: unknown): asserts role is string;
44
+ export declare function validateModuleName(moduleName: unknown): asserts moduleName is string;
45
+ export declare function validatePermissionName(name: unknown): asserts name is string;
46
+ export declare function parsePermissionId(value: unknown, failure: ValidationFailure): PermissionReference;
47
+ export declare function validateActions(actions: unknown, registration: DirectRegistration, state: State): ActionDefs;
48
+ export declare function validateGrantActions(actions: unknown, registration: GrantRegistration, state: State): GrantEntry;
49
+ export declare function validateHook(hook: unknown, registration: HookRegistration, state: State): asserts hook is HookFn;
50
+ export declare function validateSealedRegistry(modules: ReadonlyMap<string, ModuleEntry>): void;
51
+ export declare function validateIdentity(assignments: UserAssignments, state: State): Identity;
52
+ export declare function validateRequest(input: ValidateInput, state: State): ValidatedRequest;
53
+ export {};
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "endpoint-permissions-kit",
3
+ "version": "0.1.0",
4
+ "description": "Framework-agnostic endpoint permissions with an in-memory registry, typed roles and validation hooks",
5
+ "license": "Apache-2.0",
6
+ "author": "yellyoshua",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/yellyoshua/endpoint-permissions-kit.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/yellyoshua/endpoint-permissions-kit/issues"
13
+ },
14
+ "homepage": "https://github.com/yellyoshua/endpoint-permissions-kit#readme",
15
+ "keywords": [
16
+ "permissions",
17
+ "authorization",
18
+ "rbac",
19
+ "endpoint",
20
+ "typescript",
21
+ "bun",
22
+ "framework-agnostic"
23
+ ],
24
+ "sideEffects": false,
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "type": "module",
29
+ "main": "./dist/cjs/index.cjs",
30
+ "module": "./dist/esm/index.js",
31
+ "types": "./dist/types/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/types/index.d.ts",
35
+ "import": "./dist/esm/index.js",
36
+ "require": "./dist/cjs/index.cjs"
37
+ },
38
+ "./types": {
39
+ "types": "./dist/types/types.d.ts",
40
+ "import": "./dist/esm/types.js",
41
+ "require": "./dist/cjs/types.cjs"
42
+ },
43
+ "./package.json": "./package.json"
44
+ },
45
+ "bin": {
46
+ "pkit": "./bin/pkit.mjs"
47
+ },
48
+ "files": [
49
+ "dist",
50
+ "bin"
51
+ ],
52
+ "engines": {
53
+ "node": ">=20"
54
+ },
55
+ "scripts": {
56
+ "build": "bun run scripts/build.ts",
57
+ "clean": "rm -rf dist",
58
+ "test": "bun test",
59
+ "typecheck": "tsc --noEmit && tsc --noEmit -p tests/typecheck",
60
+ "prepublishOnly": "bun run typecheck && bun test && bun run build"
61
+ },
62
+ "devDependencies": {
63
+ "@types/bun": "latest",
64
+ "@types/node": "^26.2.0",
65
+ "typescript": "^5.9.3"
66
+ }
67
+ }