mirror of
https://github.com/modrinth/code.git
synced 2026-08-27 01:54:47 +00:00
feat: hosting access tab (#5995)
* feat: implement access tab with dummy data * fix: spacing * feat: qa * feat: implement backend * qa: qa pass * feat: fix user "search" * fix: lint * feat: change to bitfield * feat: fix fields * fix: lint * fix: lint * feat: hook up api * feat: fix permissions * feat: audit log table event start * feat: better mobile mode for audit log table * feat: i18n * feat: qa * feat: enforce permissions * feat: email template start * feat: qa * fix: tooltip bug * feat: qa * impl: sse support in api-client * feat: sse impl * fix: desync path * feat: time frame picker from analytics * feat: QA * fix: spacing * fix: permisison audit log entries * fix: hosting manage page shared server detection * fix: lint * feat: qa + lint * feat: audit log table sort by time * feat: finish frontend panel stuff * fix: lint * fix: backend alignment * fix: lint * fix: supress friend errors * feat: qa * fix: qa * fix: lint * fix: utils barrel * fix: safari cookies in dev * fix: pin nuxt * feat: fixes + notif fix * fix: notifications * feat: qa * fix: notification sync not happening immediately * fix: qa * fix: qa * feat: qa * blog + prepr * feat: toast shit * blog images * thumbnail update one last time * prepr * feat: use reinvite route * update images * fix: reinvite stuff * fix: lint * fix: alignment of save bar * fix: notif sizing * fix: split up access * fix: lint * fix: lint * fix: link --------- Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonActionsV1Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_actions_v1'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get server action log entries.
|
||||
* GET /v1/servers/:server_id/action-log
|
||||
*/
|
||||
public async list(
|
||||
serverId: string,
|
||||
options: Archon.Actions.v1.ListActionLogOptions = {},
|
||||
): Promise<Archon.Actions.v1.ActionLogResponse> {
|
||||
const params: Record<string, string | number> = {}
|
||||
if (options.filter) params.filter = JSON.stringify(options.filter)
|
||||
if (options.limit !== undefined) params.limit = options.limit
|
||||
if (options.offset !== undefined) params.offset = options.offset
|
||||
if (options.order !== undefined) params.order = options.order
|
||||
if (options.min_datetime !== undefined) params.min_datetime = options.min_datetime
|
||||
if (options.max_datetime !== undefined) params.max_datetime = options.max_datetime
|
||||
|
||||
return this.client.request<Archon.Actions.v1.ActionLogResponse>(
|
||||
`/servers/${serverId}/action-log`,
|
||||
{
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'GET',
|
||||
params: Object.keys(params).length > 0 ? params : undefined,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './actions/v1'
|
||||
export * from './backups/v1'
|
||||
export * from './backups-queue/v1'
|
||||
export * from './content/v1'
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonNodesInternalModule extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_nodes_internal'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get node hostnames and region summary for admin tooling.
|
||||
* GET /_internal/nodes/overview
|
||||
*/
|
||||
public async overview(): Promise<Archon.Nodes.Internal.Overview> {
|
||||
return this.client.request<Archon.Nodes.Internal.Overview>('/nodes/overview', {
|
||||
api: 'archon',
|
||||
version: 'internal',
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonNoticesV0Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_notices_v0'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all server notices.
|
||||
* GET /modrinth/v0/notices
|
||||
*/
|
||||
public async list(): Promise<Archon.Notices.v0.ListedNotice[]> {
|
||||
return this.client.request<Archon.Notices.v0.ListedNotice[]>('/notices', {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a server notice.
|
||||
* POST /modrinth/v0/notices
|
||||
*/
|
||||
public async create(
|
||||
request: Archon.Notices.v0.Announce,
|
||||
): Promise<Archon.Notices.v0.PostNoticeResponseBody> {
|
||||
return this.client.request<Archon.Notices.v0.PostNoticeResponseBody>('/notices', {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'POST',
|
||||
body: request,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a server notice.
|
||||
* PATCH /modrinth/v0/notices/:id
|
||||
*/
|
||||
public async update(id: number, request: Archon.Notices.v0.AnnouncePatch): Promise<void> {
|
||||
await this.client.request(`/notices/${id}`, {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'PATCH',
|
||||
body: request,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a server notice.
|
||||
* DELETE /modrinth/v0/notices/:id
|
||||
*/
|
||||
public async delete(id: number): Promise<void> {
|
||||
await this.client.request(`/notices/${id}`, {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a notice to a server or node.
|
||||
* PUT /modrinth/v0/notices/:id/assign?server=:serverId
|
||||
* PUT /modrinth/v0/notices/:id/assign?node=:nodeId
|
||||
*/
|
||||
public async assign(id: number, target: Archon.Notices.v0.AssignmentTarget): Promise<void> {
|
||||
await this.client.request(`/notices/${id}/assign`, {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'PUT',
|
||||
params: this.assignmentTargetToParams(target),
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Unassign a notice from a server or node.
|
||||
* PUT /modrinth/v0/notices/:id/unassign?server=:serverId
|
||||
* PUT /modrinth/v0/notices/:id/unassign?node=:nodeId
|
||||
*/
|
||||
public async unassign(id: number, target: Archon.Notices.v0.AssignmentTarget): Promise<void> {
|
||||
await this.client.request(`/notices/${id}/unassign`, {
|
||||
api: 'archon',
|
||||
version: 'modrinth/v0',
|
||||
method: 'PUT',
|
||||
params: this.assignmentTargetToParams(target),
|
||||
})
|
||||
}
|
||||
|
||||
private assignmentTargetToParams(
|
||||
target: Archon.Notices.v0.AssignmentTarget,
|
||||
): Record<string, string> {
|
||||
if ('server' in target) {
|
||||
return { server: target.server }
|
||||
}
|
||||
|
||||
return { node: target.node }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonServerUsersV1Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_server_users_v1'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of users with access to a server
|
||||
* GET /v1/servers/:server_id/users
|
||||
*/
|
||||
public async list(serverId: string): Promise<Archon.ServerUsers.v1.ServerUser[]> {
|
||||
return this.client.request<Archon.ServerUsers.v1.ServerUser[]>(`/servers/${serverId}/users`, {
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user to a server
|
||||
* POST /v1/servers/:server_id/users
|
||||
*/
|
||||
public async add(
|
||||
serverId: string,
|
||||
user: Archon.ServerUsers.v1.AddServerUserRequest,
|
||||
): Promise<void> {
|
||||
await this.client.request(`/servers/${serverId}/users`, {
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'POST',
|
||||
body: user,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-send an invite to a pending server user.
|
||||
* POST /v1/servers/:server_id/users/:user_id/reinvite
|
||||
*/
|
||||
public async reinvite(
|
||||
serverId: string,
|
||||
userId: string,
|
||||
): Promise<Archon.ServerUsers.v1.ReinviteResponse> {
|
||||
return this.client.request<Archon.ServerUsers.v1.ReinviteResponse>(
|
||||
`/servers/${serverId}/users/${userId}/reinvite`,
|
||||
{
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'POST',
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user from a server
|
||||
* DELETE /v1/servers/:server_id/users/:user_id
|
||||
*/
|
||||
public async delete(serverId: string, userId: string): Promise<void> {
|
||||
await this.client.request(`/servers/${serverId}/users/${userId}`, {
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a user's server role
|
||||
* PATCH /v1/servers/:server_id/users/:user_id
|
||||
*/
|
||||
public async update(
|
||||
serverId: string,
|
||||
userId: string,
|
||||
role: Archon.ServerUsers.v1.AssignableServerUserRole,
|
||||
): Promise<void> {
|
||||
await this.client.request(`/servers/${serverId}/users/${userId}`, {
|
||||
api: 'archon',
|
||||
version: 1,
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(role),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Archon } from '../types'
|
||||
|
||||
export class ArchonTransfersInternalModule extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'archon_transfers_internal'
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule transfers for specific servers.
|
||||
* POST /_internal/transfers/schedule/servers
|
||||
*/
|
||||
public async scheduleServers(
|
||||
request: Archon.Transfers.Internal.ScheduleServerTransfersRequest,
|
||||
): Promise<Archon.Transfers.Internal.ScheduleTransfersResponse> {
|
||||
return this.client.request<Archon.Transfers.Internal.ScheduleTransfersResponse>(
|
||||
'/transfers/schedule/servers',
|
||||
{
|
||||
api: 'archon',
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: request,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule transfers for all servers on specific nodes.
|
||||
* POST /_internal/transfers/schedule/nodes
|
||||
*/
|
||||
public async scheduleNodes(
|
||||
request: Archon.Transfers.Internal.ScheduleNodeTransfersRequest,
|
||||
): Promise<Archon.Transfers.Internal.ScheduleTransfersResponse> {
|
||||
return this.client.request<Archon.Transfers.Internal.ScheduleTransfersResponse>(
|
||||
'/transfers/schedule/nodes',
|
||||
{
|
||||
api: 'archon',
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: request,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get transfer batch history.
|
||||
* GET /_internal/transfers/history
|
||||
*/
|
||||
public async history(
|
||||
options?: Archon.Transfers.Internal.TransferHistoryQuery,
|
||||
): Promise<Archon.Transfers.Internal.TransferHistoryResponse> {
|
||||
const params: Record<string, number> = {}
|
||||
if (options?.page !== undefined) params.page = options.page
|
||||
if (options?.page_size !== undefined) params.page_size = options.page_size
|
||||
|
||||
return this.client.request<Archon.Transfers.Internal.TransferHistoryResponse>(
|
||||
'/transfers/history',
|
||||
{
|
||||
api: 'archon',
|
||||
version: 'internal',
|
||||
method: 'GET',
|
||||
params,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel pending transfer batches.
|
||||
* POST /_internal/transfers/cancel
|
||||
*/
|
||||
public async cancel(
|
||||
request: Archon.Transfers.Internal.CancelTransfersRequest,
|
||||
): Promise<Archon.Transfers.Internal.CancelTransfersResponse> {
|
||||
return this.client.request<Archon.Transfers.Internal.CancelTransfersResponse>(
|
||||
'/transfers/cancel',
|
||||
{
|
||||
api: 'archon',
|
||||
version: 'internal',
|
||||
method: 'POST',
|
||||
body: request,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,287 @@
|
||||
import type { Labrinth } from '../labrinth/types'
|
||||
|
||||
export namespace Archon {
|
||||
export namespace Nodes {
|
||||
export namespace Internal {
|
||||
export type Node = {
|
||||
id: string
|
||||
hostname: string
|
||||
region: string
|
||||
created_at: string | null
|
||||
locked: boolean
|
||||
}
|
||||
|
||||
export type Server = {
|
||||
id: string
|
||||
available: boolean
|
||||
}
|
||||
|
||||
export type NodeFull = Node & {
|
||||
servers: Server[]
|
||||
}
|
||||
|
||||
export type Overview = {
|
||||
node_hostnames: string[]
|
||||
regions: Region[]
|
||||
total_servers_active: number
|
||||
}
|
||||
|
||||
export type Region = {
|
||||
display_name: string
|
||||
country_code: string
|
||||
key: string
|
||||
server_count: number
|
||||
node_count: number
|
||||
}
|
||||
|
||||
export type RegionWithStatistics = {
|
||||
region: Region
|
||||
active_servers: string[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Notices {
|
||||
export namespace v0 {
|
||||
export type Notice = {
|
||||
id: number
|
||||
dismissable: boolean
|
||||
title: string | null
|
||||
message: string
|
||||
level: string
|
||||
announced: string
|
||||
}
|
||||
|
||||
export type ListedNotice = {
|
||||
id: number
|
||||
dismissable: boolean
|
||||
message: string
|
||||
title: string | null
|
||||
level: string
|
||||
announce_at: string
|
||||
expires: string | null
|
||||
assigned: Assignment[]
|
||||
dismissed_by: Dismisser[]
|
||||
}
|
||||
|
||||
export type Dismisser = {
|
||||
server: string
|
||||
dismissed_on: string
|
||||
}
|
||||
|
||||
export type Assignment = {
|
||||
kind: string
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export type AssignmentTarget = { server: string } | { node: string }
|
||||
|
||||
export type Announce = {
|
||||
message: string
|
||||
title?: string | null
|
||||
level: string
|
||||
dismissable: boolean
|
||||
announce_at: string
|
||||
expires?: string | null
|
||||
}
|
||||
|
||||
export type AnnouncePatch = {
|
||||
message?: string
|
||||
title?: string | null
|
||||
level?: string
|
||||
dismissable?: boolean
|
||||
announce_at?: string
|
||||
expires?: string | null
|
||||
}
|
||||
|
||||
export type PostNoticeResponseBody = {
|
||||
id: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Actions {
|
||||
export namespace v1 {
|
||||
export type SortOrder = 'asc' | 'desc'
|
||||
|
||||
export type ActionName =
|
||||
| 'server_created'
|
||||
| 'changed_server_name'
|
||||
| 'changed_server_subdomain'
|
||||
| 'server_reallocated'
|
||||
| 'server_plan_changed'
|
||||
| 'user_invited'
|
||||
| 'user_invite_revoked'
|
||||
| 'user_permission_modified'
|
||||
| 'user_removed'
|
||||
| 'addon_added'
|
||||
| 'addon_uploaded'
|
||||
| 'addon_disabled'
|
||||
| 'addon_enabled'
|
||||
| 'addon_deleted'
|
||||
| 'addon_updated'
|
||||
| 'modpack_changed'
|
||||
| 'modpack_unlinked'
|
||||
| 'server_repaired'
|
||||
| 'server_reset'
|
||||
| 'server_started'
|
||||
| 'server_stopped'
|
||||
| 'server_restarted'
|
||||
| 'server_killed'
|
||||
| 'port_allocation_added'
|
||||
| 'port_allocation_removed'
|
||||
| 'loader_version_edited'
|
||||
| 'game_version_edited'
|
||||
| 'server_properties_modified'
|
||||
| 'file_uploaded'
|
||||
| 'file_deleted'
|
||||
| 'file_renamed'
|
||||
| 'file_edited'
|
||||
| 'sftp_login'
|
||||
| 'console_command_executed'
|
||||
| 'console_cleared'
|
||||
| 'backup_created'
|
||||
| 'backup_renamed'
|
||||
| 'backup_restored'
|
||||
| 'backup_deleted'
|
||||
| 'startup_command_modified'
|
||||
| 'java_runtime_modified'
|
||||
| 'java_version_modified'
|
||||
|
||||
export type Action = {
|
||||
action: ActionName | string
|
||||
metadata?: unknown
|
||||
}
|
||||
|
||||
export type UserPermissionsActionMetadata = {
|
||||
user_id: string
|
||||
permissions?: ServerUsers.v1.UserScope | null
|
||||
}
|
||||
|
||||
export type ActionUser =
|
||||
| {
|
||||
type: 'user'
|
||||
user_id: string
|
||||
}
|
||||
| {
|
||||
type: 'support'
|
||||
user_id?: string | null
|
||||
}
|
||||
|
||||
export type ActionEntry = {
|
||||
actor: ActionUser
|
||||
action: Action
|
||||
server_id: string
|
||||
world_id?: string | null
|
||||
timestamp: string
|
||||
}
|
||||
|
||||
export type UserResp = {
|
||||
username: string
|
||||
avatar_url?: string | null
|
||||
}
|
||||
|
||||
export type AddonResp = {
|
||||
title: string
|
||||
slug?: string | null
|
||||
icon_url?: string | null
|
||||
version?: string | null
|
||||
}
|
||||
|
||||
export type VersionResp = {
|
||||
name: string
|
||||
version_number?: string | null
|
||||
}
|
||||
|
||||
export type ActionLogResponse = {
|
||||
next_offset?: number | null
|
||||
data: ActionEntry[]
|
||||
users: Record<string, UserResp>
|
||||
addons: Record<string, AddonResp>
|
||||
versions: Record<string, VersionResp>
|
||||
}
|
||||
|
||||
export type ActionLogFilter = {
|
||||
users?: string[]
|
||||
worlds?: Array<string | null>
|
||||
actions?: ActionName[]
|
||||
}
|
||||
|
||||
export type ListActionLogOptions = {
|
||||
filter?: ActionLogFilter
|
||||
limit?: number
|
||||
offset?: number
|
||||
order?: SortOrder
|
||||
min_datetime?: string
|
||||
max_datetime?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Transfers {
|
||||
export namespace Internal {
|
||||
export type ProvisionOptions = {
|
||||
region?: string | null
|
||||
node_tags: string[]
|
||||
}
|
||||
|
||||
export type ScheduleServerTransfersRequest = {
|
||||
server_ids: string[]
|
||||
scheduled_at?: string | null
|
||||
target_region?: string | null
|
||||
node_tags?: string[]
|
||||
reason?: string | null
|
||||
}
|
||||
|
||||
export type ScheduleNodeTransfersRequest = {
|
||||
node_hostnames: string[]
|
||||
scheduled_at?: string | null
|
||||
target_region?: string | null
|
||||
node_tags?: string[]
|
||||
reason?: string | null
|
||||
cordon_nodes?: boolean
|
||||
tag_nodes?: string | null
|
||||
}
|
||||
|
||||
export type ScheduleTransfersResponse = {
|
||||
batch_id: number
|
||||
scheduled_count: number
|
||||
}
|
||||
|
||||
export type CancelTransfersRequest = {
|
||||
batch_ids: number[]
|
||||
}
|
||||
|
||||
export type CancelTransfersResponse = {
|
||||
cancelled_count: number
|
||||
}
|
||||
|
||||
export type TransferLogBatchEntry = {
|
||||
id: number
|
||||
created_by: string
|
||||
created_at: string
|
||||
reason?: string | null
|
||||
scheduled_at: string
|
||||
cancelled: boolean
|
||||
log_count: number
|
||||
provision_options: ProvisionOptions
|
||||
}
|
||||
|
||||
export type TransferHistoryQuery = {
|
||||
page?: number
|
||||
page_size?: number
|
||||
}
|
||||
|
||||
export type TransferHistoryResponse = {
|
||||
batches: TransferLogBatchEntry[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Content {
|
||||
export namespace v1 {
|
||||
export type AddonKind = 'mod' | 'plugin' | 'datapack' | 'shader' | 'resourcepack'
|
||||
@@ -222,11 +503,66 @@ export namespace Archon {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ServerUsers {
|
||||
export namespace v1 {
|
||||
export type ServerUserRole = 'Owner' | 'Editor' | 'Viewer' | 'Unknown'
|
||||
|
||||
export type AssignableServerUserRole = Exclude<ServerUserRole, 'Owner' | 'Unknown'>
|
||||
|
||||
export const UserScope = {
|
||||
NONE: '',
|
||||
SERVER_ADMIN: 'SERVER_ADMIN',
|
||||
BASE_READ: 'BASE_READ',
|
||||
POWER_ACTIONS: 'POWER_ACTIONS',
|
||||
EXEC_COMMANDS: 'EXEC_COMMANDS',
|
||||
FILES_WRITE: 'FILES_WRITE',
|
||||
SETUP: 'SETUP',
|
||||
BACKUPS: 'BACKUPS',
|
||||
ADVANCED: 'ADVANCED',
|
||||
RESET_SERVER: 'RESET_SERVER',
|
||||
MANAGE_USERS: 'MANAGE_USERS',
|
||||
SUPPORT_AGENT: 'SUPPORT_AGENT',
|
||||
INFRA_MANAGER: 'INFRA_MANAGER',
|
||||
INFRA_MANAGER_READ: 'INFRA_MANAGER_READ',
|
||||
INFRA_SERVERS_XFER: 'INFRA_SERVERS_XFER',
|
||||
INFRA_USERS: 'INFRA_USERS',
|
||||
} as const
|
||||
|
||||
export type UserScope = string | number
|
||||
|
||||
export type UserResp = {
|
||||
id: string
|
||||
username: string
|
||||
avatar_url?: string | null
|
||||
}
|
||||
|
||||
export type ServerUser = {
|
||||
user: UserResp
|
||||
added_on?: string | null
|
||||
last_invite_sent?: string | null
|
||||
permissions: UserScope
|
||||
}
|
||||
|
||||
export type AddServerUserRequest = {
|
||||
server_id?: string | null
|
||||
user_id: string
|
||||
added_on?: string | null
|
||||
role: ServerUserRole
|
||||
}
|
||||
|
||||
export type ReinviteResponse = {
|
||||
sent: boolean
|
||||
cooldown_seconds: number | null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Servers {
|
||||
export namespace v0 {
|
||||
export type ServerGetResponse = {
|
||||
servers: Server[]
|
||||
pagination: Pagination
|
||||
users: Record<string, ServerOwner>
|
||||
}
|
||||
|
||||
export type Pagination = {
|
||||
@@ -236,6 +572,12 @@ export namespace Archon {
|
||||
total_items: number
|
||||
}
|
||||
|
||||
export type ServerOwner = {
|
||||
id: string
|
||||
username: string
|
||||
avatar_url?: string | null
|
||||
}
|
||||
|
||||
export type Status = 'installing' | 'broken' | 'available' | 'suspended'
|
||||
|
||||
export type SuspensionReason =
|
||||
@@ -281,12 +623,15 @@ export namespace Archon {
|
||||
node: NodeInfo | null
|
||||
flows: Flows
|
||||
is_medal: boolean
|
||||
current_user_permissions: UserScope
|
||||
|
||||
medal_expires?: string
|
||||
}
|
||||
|
||||
export type UserScope = number
|
||||
|
||||
export type Net = {
|
||||
ip: string
|
||||
ip: string | null
|
||||
port: number
|
||||
domain: string
|
||||
}
|
||||
@@ -422,9 +767,9 @@ export namespace Archon {
|
||||
modloader: string
|
||||
modloader_version: string
|
||||
game_version: string
|
||||
java_version: number
|
||||
invocation: string
|
||||
original_invocation: string
|
||||
java_version: number | null
|
||||
invocation: string | null
|
||||
original_invocation: string | null
|
||||
}
|
||||
|
||||
export type Region = {
|
||||
@@ -555,6 +900,106 @@ export namespace Archon {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Sync {
|
||||
export namespace v1 {
|
||||
export type SyncCategory = 'backup' | 'users' | 'server' | 'protocol' | 'world'
|
||||
export type SyncIntent = 'all' | SyncCategory | SyncCategory[]
|
||||
export type BackupOperationStatus = 'completed' | 'cancelled' | 'failed' | 'timed-out'
|
||||
export type ServerNetworkPort = { port: number; name: string }
|
||||
|
||||
export type ProtocolResetEvent = { type: 'protocol.reset' }
|
||||
export type ProtocolInvalidEvent = { type: 'protocol.invalid' }
|
||||
export type ProtocolErrorEvent = { type: 'protocol.error'; error: string }
|
||||
|
||||
export type BackupNewEvent = { type: 'backup.new'; id: string }
|
||||
export type BackupPatchEvent = {
|
||||
type: 'backup.patch'
|
||||
world_id: string
|
||||
backup_id: string
|
||||
name: string
|
||||
}
|
||||
export type BackupDeleteEvent = {
|
||||
type: 'backup.delete'
|
||||
world_id: string
|
||||
backup_id: string
|
||||
}
|
||||
export type BackupOperationStartEvent = {
|
||||
type:
|
||||
| 'backup.operation.create.init'
|
||||
| 'backup.operation.create.start'
|
||||
| 'backup.operation.restore.init'
|
||||
| 'backup.operation.restore.start'
|
||||
world_id: string
|
||||
backup_id: string
|
||||
operation_id: number
|
||||
}
|
||||
export type BackupOperationDoneEvent = {
|
||||
type: 'backup.operation.create.done' | 'backup.operation.restore.done'
|
||||
world_id: string
|
||||
backup_id: string
|
||||
operation_id: number
|
||||
status: BackupOperationStatus
|
||||
}
|
||||
|
||||
export type ServerPatchEvent = {
|
||||
type: 'server.patch'
|
||||
name: string
|
||||
subdomain: string
|
||||
}
|
||||
export type ServerNetworkPatchEvent = {
|
||||
type: 'server.network.patch'
|
||||
ports: ServerNetworkPort[]
|
||||
}
|
||||
export type ServerTransferEvent = {
|
||||
type: 'server.transfer.start' | 'server.transfer.done'
|
||||
target_node: string
|
||||
}
|
||||
|
||||
export type UsersPatchEvent = { type: 'users.patch' }
|
||||
|
||||
export type WorldPatchEvent = {
|
||||
type: 'world.patch'
|
||||
world_id: string
|
||||
name: string
|
||||
}
|
||||
export type WorldStartupPatchEvent = {
|
||||
type: 'world.startup.patch'
|
||||
world_id: string
|
||||
java_version: number | null
|
||||
invocation: string | null
|
||||
original_invocation: string | null
|
||||
}
|
||||
export type WorldContentAddonPatchEvent = {
|
||||
type: 'world.content.addon.patch'
|
||||
world_id: string
|
||||
specs: Archon.Content.v1.Addon[]
|
||||
}
|
||||
export type WorldContentBaseUpdateEvent = {
|
||||
type: 'world.content.base.update'
|
||||
world_id: string
|
||||
spec: Archon.Content.v1.Addons
|
||||
}
|
||||
|
||||
export type SyncEvent =
|
||||
| ProtocolResetEvent
|
||||
| ProtocolInvalidEvent
|
||||
| ProtocolErrorEvent
|
||||
| BackupNewEvent
|
||||
| BackupPatchEvent
|
||||
| BackupDeleteEvent
|
||||
| BackupOperationStartEvent
|
||||
| BackupOperationDoneEvent
|
||||
| ServerPatchEvent
|
||||
| ServerNetworkPatchEvent
|
||||
| ServerTransferEvent
|
||||
| UsersPatchEvent
|
||||
| WorldPatchEvent
|
||||
| WorldStartupPatchEvent
|
||||
| WorldContentAddonPatchEvent
|
||||
| WorldContentBaseUpdateEvent
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Websocket {
|
||||
export namespace v0 {
|
||||
export type WSAuth = {
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import type { AbstractModrinthClient } from '../core/abstract-client'
|
||||
import type { AbstractModule } from '../core/abstract-module'
|
||||
import { ArchonActionsV1Module } from './archon/actions/v1'
|
||||
import { ArchonBackupsV1Module } from './archon/backups/v1'
|
||||
import { ArchonBackupsQueueV1Module } from './archon/backups-queue/v1'
|
||||
import { ArchonContentV1Module } from './archon/content/v1'
|
||||
import { ArchonNodesInternalModule } from './archon/nodes/internal'
|
||||
import { ArchonNoticesV0Module } from './archon/notices/v0'
|
||||
import { ArchonOptionsV1Module } from './archon/options/v1'
|
||||
import { ArchonPropertiesV1Module } from './archon/properties/v1'
|
||||
import { ArchonServerUsersV1Module } from './archon/server-users/v1'
|
||||
import { ArchonServersV0Module } from './archon/servers/v0'
|
||||
import { ArchonServersV1Module } from './archon/servers/v1'
|
||||
import { ArchonTransfersInternalModule } from './archon/transfers/internal'
|
||||
import { ISO3166Module } from './iso3166'
|
||||
import { KyrosContentV1Module } from './kyros/content/v1'
|
||||
import { KyrosFilesV0Module } from './kyros/files/v0'
|
||||
@@ -21,6 +26,7 @@ import { LabrinthBillingInternalModule } from './labrinth/billing/internal'
|
||||
import { LabrinthCampaignInternalModule } from './labrinth/campaign/internal'
|
||||
import { LabrinthCollectionsModule } from './labrinth/collections'
|
||||
import { LabrinthExternalProjectsInternalModule } from './labrinth/external-projects/internal'
|
||||
import { LabrinthFriendsV3Module } from './labrinth/friends/v3'
|
||||
import { LabrinthGlobalsInternalModule } from './labrinth/globals/internal'
|
||||
import { LabrinthLimitsV3Module } from './labrinth/limits/v3'
|
||||
import { LabrinthModerationInternalModule } from './labrinth/moderation/internal'
|
||||
@@ -61,13 +67,18 @@ type ModuleConstructor = new (client: AbstractModrinthClient) => AbstractModule
|
||||
* TODO: Better way? Probably not
|
||||
*/
|
||||
export const MODULE_REGISTRY = {
|
||||
archon_actions_v1: ArchonActionsV1Module,
|
||||
archon_backups_queue_v1: ArchonBackupsQueueV1Module,
|
||||
archon_backups_v1: ArchonBackupsV1Module,
|
||||
archon_content_v1: ArchonContentV1Module,
|
||||
archon_nodes_internal: ArchonNodesInternalModule,
|
||||
archon_notices_v0: ArchonNoticesV0Module,
|
||||
archon_options_v1: ArchonOptionsV1Module,
|
||||
archon_properties_v1: ArchonPropertiesV1Module,
|
||||
archon_server_users_v1: ArchonServerUsersV1Module,
|
||||
archon_servers_v0: ArchonServersV0Module,
|
||||
archon_servers_v1: ArchonServersV1Module,
|
||||
archon_transfers_internal: ArchonTransfersInternalModule,
|
||||
iso3166_data: ISO3166Module,
|
||||
mclogs_insights_v1: MclogsInsightsV1Module,
|
||||
mclogs_logs_v1: MclogsLogsV1Module,
|
||||
@@ -84,6 +95,7 @@ export const MODULE_REGISTRY = {
|
||||
labrinth_campaign_internal: LabrinthCampaignInternalModule,
|
||||
labrinth_collections: LabrinthCollectionsModule,
|
||||
labrinth_external_projects_internal: LabrinthExternalProjectsInternalModule,
|
||||
labrinth_friends_v3: LabrinthFriendsV3Module,
|
||||
labrinth_globals_internal: LabrinthGlobalsInternalModule,
|
||||
labrinth_moderation_internal: LabrinthModerationInternalModule,
|
||||
labrinth_notifications_v2: LabrinthNotificationsV2Module,
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { AbstractModule } from '../../../core/abstract-module'
|
||||
import type { Labrinth } from '../types'
|
||||
|
||||
export class LabrinthFriendsV3Module extends AbstractModule {
|
||||
public getModuleID(): string {
|
||||
return 'labrinth_friends_v3'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get friends and pending friend requests for the authenticated user
|
||||
*
|
||||
* @returns Promise resolving to friend relationships
|
||||
*/
|
||||
public async list(): Promise<Labrinth.Friends.v3.UserFriend[]> {
|
||||
return this.client.request<Labrinth.Friends.v3.UserFriend[]>('/friends', {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Send or accept a friend request
|
||||
*
|
||||
* @param idOrUsername - The target user's ID or username
|
||||
*/
|
||||
public async add(idOrUsername: string): Promise<void> {
|
||||
return this.client.request(`/friend/${encodeURIComponent(idOrUsername)}`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'POST',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a friend or pending friend request
|
||||
*
|
||||
* @param idOrUsername - The target user's ID or username
|
||||
*/
|
||||
public async remove(idOrUsername: string): Promise<void> {
|
||||
return this.client.request(`/friend/${encodeURIComponent(idOrUsername)}`, {
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ export * from './auth/v2'
|
||||
export * from './billing/internal'
|
||||
export * from './collections'
|
||||
export * from './external-projects/internal'
|
||||
export * from './friends/v3'
|
||||
export * from './globals/internal'
|
||||
export * from './limits/v3'
|
||||
export * from './moderation/internal'
|
||||
|
||||
@@ -1350,6 +1350,12 @@ export namespace Labrinth {
|
||||
github_id?: number
|
||||
}
|
||||
|
||||
export type SearchUser = {
|
||||
id: string
|
||||
username: string
|
||||
avatar_url: string | null
|
||||
}
|
||||
|
||||
export type AllProjectsResponse = {
|
||||
projects: Projects.v3.Project[]
|
||||
organizations: Record<string, Organizations.v3.Organization>
|
||||
@@ -1357,6 +1363,17 @@ export namespace Labrinth {
|
||||
}
|
||||
}
|
||||
|
||||
export namespace Friends {
|
||||
export namespace v3 {
|
||||
export type UserFriend = {
|
||||
id: string
|
||||
friend_id: string
|
||||
accepted: boolean
|
||||
created: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export namespace ServerPing {
|
||||
export namespace Internal {
|
||||
export type MinecraftJavaPingRequest = {
|
||||
|
||||
@@ -37,6 +37,25 @@ export class LabrinthUsersV3Module extends AbstractModule {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search users by username prefix.
|
||||
*
|
||||
* @param query - Username search query
|
||||
* @returns Promise resolving to compact user search results
|
||||
*
|
||||
* GET /v3/users/search?query=:query
|
||||
*/
|
||||
public async search(query: string): Promise<Labrinth.Users.v3.SearchUser[]> {
|
||||
return this.client.request<Labrinth.Users.v3.SearchUser[]>(
|
||||
`/users/search?query=${encodeURIComponent(query)}`,
|
||||
{
|
||||
api: 'labrinth',
|
||||
version: 3,
|
||||
method: 'GET',
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all projects the authenticated user can access directly or through
|
||||
* their organizations.
|
||||
|
||||
Reference in New Issue
Block a user