OverviewFilesCommitsIssuesDocsReleasesPeers

pear-git / scripts / old-apply / namespace-operations.js

221 lines · javascript ref:
/**
 * 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 }
}