FIX - harden server startup diagnostics

This commit is contained in:
DerEchteAlec
2026-08-17 05:16:10 +02:00
parent d121370159
commit 6a8be4d679
7 changed files with 108 additions and 19 deletions
@@ -0,0 +1,35 @@
import { readFileSync } from 'node:fs'
import { describe, expect, it } from 'vitest'
const manifest = readFileSync(
new URL('../../sky_phone/fxmanifest.lua', import.meta.url),
'utf8',
)
const phoneServer = readFileSync(
new URL('../../sky_phone/source/server/phone.lua', import.meta.url),
'utf8',
)
describe('server startup contracts', () => {
it('registers the development-open callback before the database migration runs', () => {
expect(manifest.indexOf("'source/server/phone.lua'")).toBeLessThan(
manifest.indexOf("'source/server/db_migrate.lua'"),
)
expect(
phoneServer.indexOf(
'Bridge.Callbacks.Register("sky_phone:device:development-open"',
),
).toBeLessThan(
phoneServer.indexOf('Bridge.Database.AfterMigration("sky_phone"'),
)
})
it('queues early development opens until the resource has fully started', () => {
expect(phoneServer).toContain(
'AddEventHandler("onServerResourceStart", function(resource_name)',
)
expect(phoneServer).toContain('pending_development_opens[source] = true')
expect(phoneServer).toContain('development_open_handler = open_phone')
})
})
+2 -2
View File
@@ -65,12 +65,12 @@ server_scripts {
'source/bridge/server/voice.lua',
'source/server/custom_apps.lua',
'source/server/custom_app_compat.lua',
'source/server/db_migrate.lua',
'source/server/lb_phone_migration.lua',
'source/server/media_metadata.lua',
'source/server/companies.lua',
'source/server/sim.lua',
'source/server/phone.lua',
'source/server/db_migrate.lua',
'source/server/lb_phone_migration.lua',
'source/server/custom_app_storage.lua',
'source/server/payphones.lua',
'source/server/calls.lua',
+2 -1
View File
@@ -19,7 +19,8 @@ local password_pepper = tostring(Config.Server.FlipTokPasswordPepper or "")
if password_pepper == "" then
Bridge.Debug(
"warn",
"[sky_phone] Config.Server.FlipTokPasswordPepper is empty; configure it in config/config.lua before production use."
"[sky_phone] Config.Server.FlipTokPasswordPepper is empty. FlipTok passwords still work, but their hashes lack the required server-side secret. Set a stable random value in config/config.lua before production; changing it later invalidates existing FlipTok passwords.",
{ always = true }
)
end
+2 -1
View File
@@ -975,7 +975,8 @@ end)
if not api_configured() then
Bridge.Debug(
"warn",
"[sky_phone] Camera uploads and FiveManage imports are disabled until Config.Media.FiveManage.ApiKey is set in config/media.lua."
"[sky_phone] FiveManage media integration is disabled because Config.Media.FiveManage.ApiKey is empty in config/media.lua. Camera photo and video uploads, Voice Memo uploads, remote Gallery deletion, and FiveManage imports are unavailable. Add a FiveManage V3 token with Media access and restart sky_phone.",
{ always = true }
)
end
end)
+17 -6
View File
@@ -251,12 +251,23 @@ local function build_registry()
end
websites[website.Id] = website
else
Bridge.Debug(
"warn",
"[sky_phone] Media import website at index %s was disabled: %s.",
tostring(index),
tostring(website_error)
)
local source_name = type(definition) == "table" and definition.Id or nil
if website_error == "missing_api_key" then
Bridge.Debug(
"warn",
"[sky_phone] Media import source '%s' at index %s is disabled because Config.Media.FiveManage.ApiKey is empty in server-only config/media.lua. Add a FiveManage V3 token with Media access and restart sky_phone.",
tostring(source_name or "unknown"),
tostring(index)
)
else
Bridge.Debug(
"warn",
"[sky_phone] Media import source '%s' at index %s is disabled because its configuration is invalid: %s.",
tostring(source_name or "unknown"),
tostring(index),
tostring(website_error)
)
end
end
end
end
+48 -8
View File
@@ -1,3 +1,47 @@
local development_open_handler
local pending_development_opens = {}
local server_started = false
Bridge.Callbacks.Register("sky_phone:device:development-open", function(source)
if not Config.Phone.DevelopmentCommand then
return { success = false, error = "disabled" }
end
if not server_started or not development_open_handler then
pending_development_opens[source] = true
return { success = true, data = { queued = true } }
end
return { success = development_open_handler(source, nil) }
end)
AddEventHandler("playerDropped", function()
pending_development_opens[source] = nil
end)
AddEventHandler("onServerResourceStart", function(resource_name)
if resource_name ~= GetCurrentResourceName() then
return
end
server_started = true
if not development_open_handler then
Bridge.Debug("error", "[sky_phone] Server initialization did not register the development phone handler.")
return
end
for player_source in pairs(pending_development_opens) do
pending_development_opens[player_source] = nil
local success, opened = pcall(development_open_handler, player_source, nil)
if not success then
Bridge.Debug(
"error",
"[sky_phone] Queued development phone open failed for source %s: %s",
tostring(player_source),
tostring(opened)
)
end
end
end)
Bridge.Database.AfterMigration("sky_phone", function()
Bridge.Debug("debug", "[sky_phone] Server initialization started after database migration.", { always = true })
@@ -14,7 +58,8 @@ local passcode_pepper = tostring(Config.Server.PasscodePepper or "")
if passcode_pepper == "" then
Bridge.Debug(
"warn",
"[sky_phone] Config.Server.PasscodePepper is empty; configure it in config/config.lua before production use."
"[sky_phone] Config.Server.PasscodePepper is empty. Device passcodes still work, but their hashes lack the required server-side secret. Set a stable random value in config/config.lua before production; changing it later invalidates existing device passcodes.",
{ always = true }
)
end
local allowed_device_namespaces = {
@@ -965,6 +1010,8 @@ local function open_phone(source, used_item)
return true
end
development_open_handler = open_phone
function SkyPhone.OpenDeviceForCall(source, imei)
local matches = find_device_slots(source, imei)
if not matches[1] then
@@ -1123,13 +1170,6 @@ Bridge.Callbacks.Register("sky_phone:security:disable-passcode", function(source
return { success = true, data = { security = security_status(session.imei) } }
end)
Bridge.Callbacks.Register("sky_phone:device:development-open", function(source)
if not Config.Phone.DevelopmentCommand then
return { success = false, error = "disabled" }
end
return { success = open_phone(source, nil) }
end)
Bridge.Callbacks.Register("sky_phone:device:save", function(source, data)
if not SkyPhone.AllowOperation(source, "device_save", 120, 60) then
return { success = false, error = "rate_limited" }
+2 -1
View File
@@ -5,7 +5,8 @@ local password_pepper = tostring(Config.Server.PicstagramPasswordPepper or "")
if password_pepper == "" then
Bridge.Debug(
"warn",
"[sky_phone] Config.Server.PicstagramPasswordPepper is empty; configure it in config/config.lua before production use."
"[sky_phone] Config.Server.PicstagramPasswordPepper is empty. Picstagram passwords still work, but their hashes lack the required server-side secret. Set a stable random value in config/config.lua before production; changing it later invalidates existing Picstagram passwords.",
{ always = true }
)
end