/**
* Autobase Operation Types for Namespace Registry
*
* Defines operation constants, JSON encode/decode, and validation
* for all Autobase-managed P2P namespace registry operations.
*
* Operations are appended to Autobase writer cores and processed
* by the deterministic apply function to build the Hyperbee view.
*/
// Namespace CRUD
export const OP_CREATE_NAMESPACE = 'create-namespace'
export const OP_UPDATE_NAMESPACE = 'update-namespace'
export const OP_DELETE_NAMESPACE = 'delete-namespace'
// Repo membership
export const OP_ADD_REPO = 'add-repo'
export const OP_REMOVE_REPO = 'remove-repo'
export const OP_MOVE_REPO = 'move-repo'
// Group members
export const OP_ADD_MEMBER = 'add-member'
export const OP_REMOVE_MEMBER = 'remove-member'
// Writer management
export const OP_ADD_WRITER = 'add-writer'
export const OP_REMOVE_WRITER = 'remove-writer'
// Access grants
export const OP_CREATE_GRANT = 'create-grant'
export const OP_REVOKE_GRANT = 'revoke-grant'
// Access invites
export const OP_CREATE_INVITE = 'create-invite'
export const OP_CONSUME_INVITE = 'consume-invite'
export const OP_REVOKE_INVITE = 'revoke-invite'
// Access requests
export const OP_CREATE_ACCESS_REQUEST = 'create-access-request'
export const OP_APPROVE_ACCESS_REQUEST = 'approve-access-request'
export const OP_DENY_ACCESS_REQUEST = 'deny-access-request'
// Config
export const OP_SET_META = 'set-meta'
/**
* Encode an operation to a Buffer for Autobase append
*/
export function encodeOp (op) {
return Buffer.from(JSON.stringify(op))
}
/**
* Decode a Buffer back to an operation object
*/
export function decodeOp (buf) {
return JSON.parse(buf.toString())
}
/**
* Validate an operation has required fields for its type
* @returns {{ valid: boolean, error?: string }}
*/
export function validateOp (op) {
if (!op || !op.type) {
return { valid: false, error: 'Missing operation type' }
}
switch (op.type) {
case OP_CREATE_NAMESPACE:
if (!op.name) return { valid: false, error: 'create-namespace requires name' }
if (!op.nsType || !['user', 'group'].includes(op.nsType)) {
return { valid: false, error: 'create-namespace requires nsType (user|group)' }
}
break
case OP_UPDATE_NAMESPACE:
if (!op.name) return { valid: false, error: 'update-namespace requires name' }
break
case OP_DELETE_NAMESPACE:
if (!op.name) return { valid: false, error: 'delete-namespace requires name' }
break
case OP_ADD_REPO:
if (!op.namespaceName) return { valid: false, error: 'add-repo requires namespaceName' }
if (!op.repoName) return { valid: false, error: 'add-repo requires repoName' }
break
case OP_REMOVE_REPO:
if (!op.namespaceName) return { valid: false, error: 'remove-repo requires namespaceName' }
if (!op.repoName) return { valid: false, error: 'remove-repo requires repoName' }
break
case OP_MOVE_REPO:
if (!op.repoName) return { valid: false, error: 'move-repo requires repoName' }
if (!op.fromNamespace) return { valid: false, error: 'move-repo requires fromNamespace' }
if (!op.toNamespace) return { valid: false, error: 'move-repo requires toNamespace' }
break
case OP_ADD_MEMBER:
if (!op.namespaceName) return { valid: false, error: 'add-member requires namespaceName' }
if (!op.memberId) return { valid: false, error: 'add-member requires memberId' }
if (!op.role || !['admin', 'member'].includes(op.role)) {
return { valid: false, error: 'add-member requires role (admin|member)' }
}
break
case OP_REMOVE_MEMBER:
if (!op.namespaceName) return { valid: false, error: 'remove-member requires namespaceName' }
if (!op.memberId) return { valid: false, error: 'remove-member requires memberId' }
break
case OP_ADD_WRITER:
if (!op.peerId) return { valid: false, error: 'add-writer requires peerId' }
if (!op.serverKey) return { valid: false, error: 'add-writer requires serverKey' }
if (!op.role || !['owner', 'writer', 'mirror'].includes(op.role)) {
return { valid: false, error: 'add-writer requires role (owner|writer|mirror)' }
}
break
case OP_REMOVE_WRITER:
if (!op.peerId) return { valid: false, error: 'remove-writer requires peerId' }
break
case OP_CREATE_GRANT: {
if (!op.grantId) return { valid: false, error: 'create-grant requires grantId' }
if (!op.subjectType || !['user', 'server'].includes(op.subjectType)) {
return { valid: false, error: 'create-grant requires subjectType (user|server)' }
}
if (!op.subjectId) return { valid: false, error: 'create-grant requires subjectId' }
if (!op.grantType || !['group', 'repo'].includes(op.grantType)) {
return { valid: false, error: 'create-grant requires grantType (group|repo)' }
}
if (op.grantType === 'group' && !op.groupName) {
return { valid: false, error: 'create-grant with grantType=group requires groupName' }
}
if (op.grantType === 'repo' && !op.repoName) {
return { valid: false, error: 'create-grant with grantType=repo requires repoName' }
}
if (!op.permission || !['write', 'moderator', 'owner'].includes(op.permission)) {
return { valid: false, error: 'create-grant requires permission (write|moderator|owner)' }
}
break
}
case OP_REVOKE_GRANT:
if (!op.grantId) return { valid: false, error: 'revoke-grant requires grantId' }
break
case OP_CREATE_INVITE: {
if (!op.inviteId) return { valid: false, error: 'create-invite requires inviteId' }
if (!op.inviteType || !['group', 'repo'].includes(op.inviteType)) {
return { valid: false, error: 'create-invite requires inviteType (group|repo)' }
}
if (op.inviteType === 'group' && !op.targetGroup) {
return { valid: false, error: 'create-invite with inviteType=group requires targetGroup' }
}
if (op.inviteType === 'repo' && !op.targetRepo) {
return { valid: false, error: 'create-invite with inviteType=repo requires targetRepo' }
}
if (!op.permission || !['write', 'moderator', 'owner'].includes(op.permission)) {
return { valid: false, error: 'create-invite requires permission (write|moderator|owner)' }
}
break
}
case OP_CONSUME_INVITE:
if (!op.inviteId) return { valid: false, error: 'consume-invite requires inviteId' }
if (!op.grantId) return { valid: false, error: 'consume-invite requires grantId' }
if (!op.subjectType || !['user', 'server'].includes(op.subjectType)) {
return { valid: false, error: 'consume-invite requires subjectType (user|server)' }
}
if (!op.subjectId) return { valid: false, error: 'consume-invite requires subjectId' }
break
case OP_REVOKE_INVITE:
if (!op.inviteId) return { valid: false, error: 'revoke-invite requires inviteId' }
break
case OP_CREATE_ACCESS_REQUEST: {
if (!op.requestId) return { valid: false, error: 'create-access-request requires requestId' }
if (!op.subjectType || !['user', 'server'].includes(op.subjectType)) {
return { valid: false, error: 'create-access-request requires subjectType (user|server)' }
}
if (!op.subjectId) return { valid: false, error: 'create-access-request requires subjectId' }
if (!op.requestType || !['group', 'repo'].includes(op.requestType)) {
return { valid: false, error: 'create-access-request requires requestType (group|repo)' }
}
if (op.requestType === 'group' && !op.groupName) {
return { valid: false, error: 'create-access-request with requestType=group requires groupName' }
}
if (op.requestType === 'repo' && !op.repoName) {
return { valid: false, error: 'create-access-request with requestType=repo requires repoName' }
}
if (!op.permission || !['write', 'moderator', 'owner'].includes(op.permission)) {
return { valid: false, error: 'create-access-request requires permission (write|moderator|owner)' }
}
break
}
case OP_APPROVE_ACCESS_REQUEST:
if (!op.requestId) return { valid: false, error: 'approve-access-request requires requestId' }
if (!op.grantId) return { valid: false, error: 'approve-access-request requires grantId' }
break
case OP_DENY_ACCESS_REQUEST:
if (!op.requestId) return { valid: false, error: 'deny-access-request requires requestId' }
break
case OP_SET_META:
if (!op.key) return { valid: false, error: 'set-meta requires key' }
break
default:
return { valid: false, error: `Unknown operation type: ${op.type}` }
}
return { valid: true }
}