From 64a6e58577917c6538d6ea88c91ef6335eefe17a Mon Sep 17 00:00:00 2001 From: Dominik Date: Thu, 13 Aug 2026 03:14:50 +0200 Subject: [PATCH] Add SendNotification export for LB compatibility Implement SendNotification compatibility for lb-phone: validate app IDs, normalize and validate title/content, check provider/registered apps and reserved IDs, and dispatch a notification NUI message. Register the export and a compatibility alias. Update client tests to assert successful delivery to bundled apps and proper rejection for unknown app IDs. --- sky_phone/source/client/custom_app_compat.lua | 71 +++++++++++++++++++ tests/custom_app_compat_client.lua | 20 ++++++ 2 files changed, 91 insertions(+) diff --git a/sky_phone/source/client/custom_app_compat.lua b/sky_phone/source/client/custom_app_compat.lua index 57ec252..1d5a89f 100644 --- a/sky_phone/source/client/custom_app_compat.lua +++ b/sky_phone/source/client/custom_app_compat.lua @@ -388,6 +388,75 @@ local function close_phone_app(options) return core.CloseActive(owner_resource) end +local function normalize_lb_notification_text(value, maximum_length, error_code) + if type(value) ~= "string" then + return nil, error_code + end + + local normalized = value:match("^%s*(.-)%s*$") + if normalized == "" or #normalized > maximum_length then + return nil, error_code + end + return normalized +end + +local function send_lb_notification(data) + local owner_resource, owner_error = get_calling_resource("SendNotification") + if not owner_resource then + return false, owner_error + end + if type(data) ~= "table" then + return false, "invalid_notification" + end + + local app_id = data.app or data.identifier + local valid_app_id, app_id_error = SkyPhoneApps.ValidateAppId(app_id) + if not valid_app_id then + return false, app_id_error + end + + local registered_record = provider_apps[app_id] + if registered_record then + local record, record_error = get_provider_app(owner_resource, app_id, { + [providers.lb] = true, + }) + if not record then + return false, record_error + end + elseif not SkyPhoneApps.ReservedAppIds[app_id] then + return false, "app_not_found" + end + + local title, title_error = normalize_lb_notification_text( + data.title, + 128, + "invalid_notification_title" + ) + if not title then + return false, title_error + end + + local content, content_error = normalize_lb_notification_text( + data.content or data.message or data.text, + 512, + "invalid_notification_text" + ) + if not content then + return false, content_error + end + + SendNUIMessage({ + type = "notification:show", + data = { + appId = app_id, + route = "/apps/" .. app_id, + text = content, + title = title, + }, + }) + return true +end + local function register_high_server_app(owner_resource, definition, revision) if type(owner_resource) ~= "string" or type(definition) ~= "table" @@ -570,9 +639,11 @@ exports("getCustomApps", get_quasar_apps) exports("OpenPhoneApp", open_quasar_app) exports("OpenApp", open_phone_app) exports("CloseApp", close_phone_app) +exports("SendNotification", send_lb_notification) SkyPhoneCompatibility.RegisterExportAlias("lb-phone", "OpenApp", open_phone_app) SkyPhoneCompatibility.RegisterExportAlias("lb-phone", "CloseApp", close_phone_app) +SkyPhoneCompatibility.RegisterExportAlias("lb-phone", "SendNotification", send_lb_notification) SkyPhoneCompatibility.RegisterExportAlias("17mov_Phone", "AddApplication", add_17mov_application) SkyPhoneCompatibility.RegisterExportAlias("17mov_Phone", "RemoveApplication", remove_17mov_application) diff --git a/tests/custom_app_compat_client.lua b/tests/custom_app_compat_client.lua index cd548fb..2b45a36 100644 --- a/tests/custom_app_compat_client.lua +++ b/tests/custom_app_compat_client.lua @@ -121,6 +121,7 @@ local lb_remove_custom_app = get_alias_export("lb-phone", "RemoveCustomApp") local lb_send_custom_app_message = get_alias_export("lb-phone", "SendCustomAppMessage") local lb_open_app = get_alias_export("lb-phone", "OpenApp") local lb_close_app = get_alias_export("lb-phone", "CloseApp") +local lb_send_notification = get_alias_export("lb-phone", "SendNotification") local mov_add_application = get_alias_export("17mov_Phone", "AddApplication") local mov_remove_application = get_alias_export("17mov_Phone", "RemoveApplication") local mov_send_app_message = get_alias_export("17mov_Phone", "SendAppMessage") @@ -158,6 +159,25 @@ for resource_name in pairs(expected_provider_resources) do end assert(yseries_get_data_loaded(), "YSeries must see the compatibility provider as loaded") +invoking_resource = "sky_base" +assert(lb_send_notification({ + app = "calendar", + title = "Hospital", + content = "Your appointment has been confirmed.", +}), "LB notifications for bundled phone apps must be accepted") +local lb_notification_message = nui_messages[#nui_messages] +assert(lb_notification_message.type == "notification:show", "LB notifications must reach the phone notification UI") +assert(lb_notification_message.data.appId == "calendar", "LB notifications must preserve the target app") +assert(lb_notification_message.data.route == "/apps/calendar", "LB notifications must link to the target app") +assert(lb_notification_message.data.text == "Your appointment has been confirmed.", "LB notification content must be preserved") + +local unknown_notification_success, unknown_notification_error = lb_send_notification({ + app = "unknown-provider-app", + title = "Hospital", + content = "Unknown target", +}) +assert(not unknown_notification_success and unknown_notification_error == "app_not_found", "LB notifications must reject unknown app IDs") + invoking_resource = "lb_app" local lifecycle_response_delivered = false local install_hook_after_response = false