---@meta
-- Editor-only declarations. This file is not loaded by the server.
-- Server dnf/v1 API, checked 2026-10-26. See api.md for runtime constraints.
-- The framework exposes only api_version/plugins; main.lua exposes the other
-- members. require("dnf") is the only supported module; no user Lua modules.

---@alias DNF.Permission 'notice.broadcast'|'progression.clear_experience'|'inventory.item_use'|'commerce.shop_purchase'|'dungeon.admission'|'chat.message'
---@alias DNF.DecisionPoint 'inventory.item_use'|'commerce.shop_purchase'|'dungeon.admission'|'chat.message'
---@alias DNF.ExtensionPoint 'dungeon.clear_announcement'|'progression.clear_experience'|DNF.DecisionPoint
---@alias DNF.AnnouncementMode 'auto'|'builtin'|'plugin'
---@alias DNF.Scope 'instance'|'channel'

---@class DNF.Character
---@field id string Keep as string; never infer account ownership
---@field channel_id integer

---@class DNF.OperationFinishedData
---@field character DNF.Character
---@field source string
---@field handler_failed boolean False does not imply business success

---@class DNF.DungeonClearedData
---@field character DNF.Character
---@field dungeon_id integer
---@field dungeon_name string
---@field player_name string
---@field party boolean
---@field elapsed_ms? integer Absent when authoritative duration is unknown
---@field source string

---@class DNF.SettlementCommittedData
---@field character DNF.Character
---@field dungeon_id integer
---@field completion_key string
---@field experience integer Committed gain, not the base EXP hook input
---@field level integer

---@class DNF.OwnerOperationData
---@field character DNF.Character
---@field operation string Successful owner operation; may be a no-op
---@field item_id string
---@field source_list integer
---@field source_slot integer
---@field target_list integer
---@field target_slot integer

---@class DNF.QuestData
---@field character DNF.Character
---@field quest_id integer
---@field progress integer

---@class DNF.DungeonStateData
---@field character DNF.Character
---@field dungeon_id integer
---@field difficulty integer
---@field run_id string Process-local identity, not a durable receipt
---@field room string
---@field map_id integer
---@field party boolean
---@field details? table Event-specific detached values; see api.md

---@class DNF.SocialStateData
---@field character DNF.Character
---@field group_id string
---@field target_id? string
---@field member_ids? string[]
---@field operation? string
---@field details? table

---@class DNF.CommerceItem
---@field item_id integer Zero in Cera request Hook; present after commit
---@field count integer Cera request Hook uses one per cart row
---@field commodity_id? integer Cera commodity identity

---@class DNF.ShopPurchaseContext
---@field character DNF.Character
---@field source 'npc'|'secret'|'cera'
---@field items DNF.CommerceItem[] Requested rows in Hook; purchased products in notification

---@class DNF.ItemUseContext
---@field character DNF.Character
---@field item_id string
---@field list_type integer
---@field slot_index integer
---@field count string Current source stack, not arbitrary plugin-controlled consumption
---@field in_dungeon boolean

---@class DNF.DungeonAdmissionContext
---@field character DNF.Character
---@field dungeon_id integer
---@field difficulty integer
---@field members DNF.Character[] Prepared leader and followers

---@class DNF.ChatMessageContext
---@field character DNF.Character
---@field mode integer
---@field text string Decoded snapshot; Hook may not replace it
---@field item_links integer
---@field source string
---@field recipients integer Host acceptance count, not client acknowledgement

---@class DNF.GameplayOperationData
---@field character DNF.Character
---@field module string
---@field transport string
---@field opcode integer
---@field handler_failed boolean False does not imply business success

---@class DNF.AuctionData
---@field character DNF.Character
---@field source 'item'|'gold'
---@field listing_id string
---@field seller_id string
---@field item_id integer
---@field count integer

---@class DNF.PrivateStoreData
---@field character DNF.Character
---@field seller_id string
---@field rows integer
---@field item_id? integer
---@field count? integer

---@class DNF.MailData
---@field character DNF.Character
---@field recipient_id? string
---@field claim_rows? integer

---@class DNF.ActivityRewardData
---@field character DNF.Character
---@field activity string
---@field stage string
---@field mail_count integer

---@class DNF.Notice
---@field text string Nonblank; at most 511 UTF-16 units
---@field scope? DNF.Scope Defaults to instance
---@field channel_id? integer Positive when scope is channel
---@field surface? 'native_chat'
---@field color? integer ARGB uint32; omitted/zero defaults to 0xFFFFD54F

---@class DNF.Event
---@field id string
---@field name string
---@field version 1
---@field occurred_at_ms integer Unix milliseconds
---@field data table Detached event-specific snapshot

---@class DNF.CharacterEvent: DNF.Event
---@field name 'character.bound'|'character.unbound'
---@field data DNF.Character

---@class DNF.OperationFinishedEvent: DNF.Event
---@field name 'game.operation.finished'
---@field data DNF.OperationFinishedData

---@class DNF.DungeonClearedEvent: DNF.Event
---@field name 'dungeon.cleared'
---@field data DNF.DungeonClearedData

---@class DNF.SettlementCommittedEvent: DNF.Event
---@field name 'dungeon.settlement_committed'
---@field data DNF.SettlementCommittedData

---@class DNF.ClearExperienceContext
---@field character DNF.Character
---@field dungeon_id integer No event.data envelope on this hook

---@class DNF.ClearAnnouncementPlan
---@field enabled boolean
---@field text string
---@field color integer ARGB uint32
---@field scope DNF.Scope
---@field channel_id integer

---@class DNF.ClearAnnouncementPatch
---@field enabled? boolean False cancels this presentation
---@field text? string
---@field color? integer ARGB uint32
---@field scope? DNF.Scope
---@field channel_id? integer

---@class DNF.ClearExperiencePlan
---@field enabled boolean
---@field amount integer Positive uint32; base ordinary-dungeon clear EXP

---@class DNF.ClearExperiencePatch
---@field enabled? boolean False keeps the original base EXP
---@field amount? integer 1..4294967295, even when enabled is false

---@class DNF.OperationDecision
---@field enabled boolean False rejects this adapter's native operation
---@field allowed boolean False rejects; true never bypasses core validation

---@class DNF.OperationDecisionPatch
---@field enabled? boolean False rejects; evaluator errors retain core rules
---@field allowed? boolean

---@class DNF.HookDefinition
---@field permission DNF.Permission
---@field fields string[] Allowed patch fields
---@field failure string Failure policy description

---@class DNF.Context
---@field config table<string, any> VM-local; no persistence or cross-VM state
---@field notice DNF.NoticeAPI

---@class DNF.NoticeAPI
local notice = {}
---Observer callbacks only, requires notice.broadcast permission. Raises on
---invalid input. All handlers for one event share a four-notice batch; any
---handler error discards that batch. Success only stages an action.
---@param request DNF.Notice
---@return boolean accepted Not a client delivery acknowledgement
function notice.broadcast(request) end

---@class DNF.Events
local events = {}
---Initialization only; at most 64 handlers. Exact, longest domain prefix,
---shorter prefixes, then global '*'; one queue item for all matching groups.
---All handlers for one plugin/event share a 10ms budget and four notices.
---@overload fun(name: 'character.bound'|'character.unbound', handler: fun(ctx: DNF.Context, event: DNF.CharacterEvent))
---@overload fun(name: 'game.operation.finished', handler: fun(ctx: DNF.Context, event: DNF.OperationFinishedEvent))
---@overload fun(name: 'dungeon.cleared', handler: fun(ctx: DNF.Context, event: DNF.DungeonClearedEvent))
---@overload fun(name: 'dungeon.settlement_committed', handler: fun(ctx: DNF.Context, event: DNF.SettlementCommittedEvent))
---@param name string Stable event, known domain.*, *, or exact game.game-* diagnostic
---@param handler fun(ctx: DNF.Context, event: DNF.Event)
function events.on(name, handler) end
---Returns a detached name -> semantic description catalog.
---@return table<string, string>
function events.catalog() end

---@class DNF.Hooks
local hooks = {}
---Initialization only. False cancels presentation, retains base EXP, or rejects
---one of the four dedicated business-decision adapters. See the point contract.
---@overload fun(point: 'dungeon.clear_announcement', handler: fun(ctx: DNF.Context, plan: DNF.ClearAnnouncementPlan, event: DNF.DungeonClearedEvent): boolean)
---@overload fun(point: 'progression.clear_experience', handler: fun(ctx: DNF.Context, plan: DNF.ClearExperiencePlan, event: DNF.ClearExperienceContext): boolean)
---@overload fun(point: 'inventory.item_use', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ItemUseContext): boolean)
---@overload fun(point: 'commerce.shop_purchase', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ShopPurchaseContext): boolean)
---@overload fun(point: 'dungeon.admission', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.DungeonAdmissionContext): boolean)
---@overload fun(point: 'chat.message', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ChatMessageContext): boolean)
---@param point DNF.ExtensionPoint
---@param handler fun(ctx: DNF.Context, plan: table, event: table): boolean
function hooks.before(point, handler) end
---Return a field patch or nil. Mutating input plan/event has no effect.
---@overload fun(point: 'dungeon.clear_announcement', handler: fun(ctx: DNF.Context, plan: DNF.ClearAnnouncementPlan, event: DNF.DungeonClearedEvent): DNF.ClearAnnouncementPatch|nil)
---@overload fun(point: 'progression.clear_experience', handler: fun(ctx: DNF.Context, plan: DNF.ClearExperiencePlan, event: DNF.ClearExperienceContext): DNF.ClearExperiencePatch|nil)
---@overload fun(point: 'inventory.item_use', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ItemUseContext): DNF.OperationDecisionPatch|nil)
---@overload fun(point: 'commerce.shop_purchase', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ShopPurchaseContext): DNF.OperationDecisionPatch|nil)
---@overload fun(point: 'dungeon.admission', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.DungeonAdmissionContext): DNF.OperationDecisionPatch|nil)
---@overload fun(point: 'chat.message', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ChatMessageContext): DNF.OperationDecisionPatch|nil)
---@param point DNF.ExtensionPoint
---@param handler fun(ctx: DNF.Context, plan: table, event: table): table|nil
function hooks.transform(point, handler) end
---Returns detached Hook definitions; modifying the result cannot grant access.
---@return table<DNF.ExtensionPoint, DNF.HookDefinition>
function hooks.catalog() end

---@class DNF.Providers
local providers = {}
---Initialization only. One provider per point across the complete generation.
---@overload fun(point: 'dungeon.clear_announcement', handler: fun(ctx: DNF.Context, plan: DNF.ClearAnnouncementPlan, event: DNF.DungeonClearedEvent): DNF.ClearAnnouncementPatch)
---@overload fun(point: 'progression.clear_experience', handler: fun(ctx: DNF.Context, plan: DNF.ClearExperiencePlan, event: DNF.ClearExperienceContext): DNF.ClearExperiencePatch)
---@overload fun(point: 'inventory.item_use', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ItemUseContext): DNF.OperationDecisionPatch)
---@overload fun(point: 'commerce.shop_purchase', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ShopPurchaseContext): DNF.OperationDecisionPatch)
---@overload fun(point: 'dungeon.admission', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.DungeonAdmissionContext): DNF.OperationDecisionPatch)
---@overload fun(point: 'chat.message', handler: fun(ctx: DNF.Context, plan: DNF.OperationDecision, event: DNF.ChatMessageContext): DNF.OperationDecisionPatch)
---@param point DNF.ExtensionPoint
---@param handler fun(ctx: DNF.Context, plan: table, event: table): table
function providers.register(point, handler) end

---@class DNF.PluginOptions
---@field enabled boolean Explicit enable/disable; framework only
---@field permissions? DNF.Permission[] Also requested in plugin.json
---@field config? table<string, any> Nested tables also require string keys

---@class DNF.PluginManager
local plugins = {}
---Framework only. Declares a candidate; does not mutate the live generation.
---@param path string Relative to runtime/; starts plugins/ or assets/plugins/
---@param options DNF.PluginOptions
function plugins.load(path, options) end
---@param mode DNF.AnnouncementMode Default auto; plugin requires a provider
function plugins.clear_announcement(mode) end

---@class DNF
---@field plugins? DNF.PluginManager Available only inside framework.lua
---@field api_version 'dnf/v1'
---@field config table<string, any> Plugin VM only
---@field events DNF.Events
---@field hooks DNF.Hooks
---@field providers DNF.Providers
---@field notice DNF.NoticeAPI
local dnf = {}
return dnf
