diff --git a/proto/wizard/wizard_structs.proto b/proto/wizard/wizard_structs.proto index 1ed37aff..160eb02f 100644 --- a/proto/wizard/wizard_structs.proto +++ b/proto/wizard/wizard_structs.proto @@ -15,6 +15,7 @@ message ConfigRequest { string relay_url = 2; bool automate_liquidity = 3; bool push_backups_to_nostr = 4; + string avatar_url = 5; } message AdminConnectInfoResponse { string nprofile = 1; @@ -41,4 +42,6 @@ message ServiceStateResponse { string relay_url = 10; bool automate_liquidity = 11; bool push_backups_to_nostr = 12; + string avatar_url = 13; + string app_id = 14; } \ No newline at end of file diff --git a/proto/wizard_service/autogenerated/client.md b/proto/wizard_service/autogenerated/client.md index 9cc712f7..c3d4e77c 100644 --- a/proto/wizard_service/autogenerated/client.md +++ b/proto/wizard_service/autogenerated/client.md @@ -63,6 +63,7 @@ The nostr server will send back a message response, and inside the body there wi ### ConfigRequest - __automate_liquidity__: _boolean_ + - __avatar_url__: _string_ - __push_backups_to_nostr__: _boolean_ - __relay_url__: _string_ - __source_name__: _string_ @@ -71,7 +72,9 @@ The nostr server will send back a message response, and inside the body there wi ### ServiceStateResponse - __admin_npub__: _string_ + - __app_id__: _string_ - __automate_liquidity__: _boolean_ + - __avatar_url__: _string_ - __http_url__: _string_ - __lnd_state__: _[LndState](#LndState)_ - __nprofile__: _string_ diff --git a/proto/wizard_service/autogenerated/debug.txt b/proto/wizard_service/autogenerated/debug.txt index 8df23fda..ca3d129c 100644 --- a/proto/wizard_service/autogenerated/debug.txt +++ b/proto/wizard_service/autogenerated/debug.txt @@ -1,5 +1,5 @@ ([]*main.Method) (len=4 cap=4) { - (*main.Method)(0xc0000d80f0)({ + (*main.Method)(0xc0002b00f0)({ in: (main.MethodMessage) { name: (string) (len=5) "Empty", hasZeroFields: (bool) true @@ -9,8 +9,8 @@ name: (string) (len=24) "AdminConnectInfoResponse", hasZeroFields: (bool) false }, - opts: (*main.methodOptions)(0xc0000cc7e0)({ - authType: (*main.supportedAuth)(0xc0003552c0)({ + opts: (*main.methodOptions)(0xc0006907e0)({ + authType: (*main.supportedAuth)(0xc000347380)({ id: (string) (len=5) "guest", name: (string) (len=5) "Guest", context: ([]*main.authContext) @@ -26,7 +26,7 @@ }), serverStream: (bool) false }), - (*main.Method)(0xc0000d8140)({ + (*main.Method)(0xc0002b0140)({ in: (main.MethodMessage) { name: (string) (len=5) "Empty", hasZeroFields: (bool) true @@ -36,8 +36,8 @@ name: (string) (len=20) "ServiceStateResponse", hasZeroFields: (bool) false }, - opts: (*main.methodOptions)(0xc0000cc960)({ - authType: (*main.supportedAuth)(0xc000355380)({ + opts: (*main.methodOptions)(0xc000690960)({ + authType: (*main.supportedAuth)(0xc000347440)({ id: (string) (len=5) "guest", name: (string) (len=5) "Guest", context: ([]*main.authContext) @@ -53,7 +53,7 @@ }), serverStream: (bool) false }), - (*main.Method)(0xc0000d80a0)({ + (*main.Method)(0xc0002b00a0)({ in: (main.MethodMessage) { name: (string) (len=13) "ConfigRequest", hasZeroFields: (bool) false @@ -63,8 +63,8 @@ name: (string) (len=5) "Empty", hasZeroFields: (bool) true }, - opts: (*main.methodOptions)(0xc0000cc660)({ - authType: (*main.supportedAuth)(0xc000355200)({ + opts: (*main.methodOptions)(0xc000690660)({ + authType: (*main.supportedAuth)(0xc0003472c0)({ id: (string) (len=5) "guest", name: (string) (len=5) "Guest", context: ([]*main.authContext) @@ -80,7 +80,7 @@ }), serverStream: (bool) false }), - (*main.Method)(0xc0000d8050)({ + (*main.Method)(0xc0002b0050)({ in: (main.MethodMessage) { name: (string) (len=5) "Empty", hasZeroFields: (bool) true @@ -90,8 +90,8 @@ name: (string) (len=13) "StateResponse", hasZeroFields: (bool) false }, - opts: (*main.methodOptions)(0xc0000cc4e0)({ - authType: (*main.supportedAuth)(0xc000355140)({ + opts: (*main.methodOptions)(0xc0006904e0)({ + authType: (*main.supportedAuth)(0xc000347200)({ id: (string) (len=5) "guest", name: (string) (len=5) "Guest", context: ([]*main.authContext) @@ -110,7 +110,7 @@ } ([]*main.Enum) (len=1 cap=1) { - (*main.Enum)(0xc000447d40)({ + (*main.Enum)(0xc000443d40)({ name: (string) (len=8) "LndState", values: ([]main.EnumValue) (len=3 cap=4) { (main.EnumValue) { @@ -130,11 +130,11 @@ } ([]*main.SortableMessage) (len=5 cap=8) { - (*main.SortableMessage)(0xc0003554c0)({ + (*main.SortableMessage)(0xc0003475c0)({ fullName: (string) (len=24) "AdminConnectInfoResponse", name: (string) (len=24) "AdminConnectInfoResponse", fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc0003553c0)({ + (*main.Field)(0xc000347480)({ name: (string) (len=12) "connect_info", kind: (string) (len=37) "AdminConnectInfoResponse_connect_info", isMap: (bool) false, @@ -144,7 +144,7 @@ isOptional: (bool) false, oneOfName: (string) (len=12) "connect_info" }), - (*main.Field)(0xc000354b80)({ + (*main.Field)(0xc000346bc0)({ name: (string) (len=8) "nprofile", kind: (string) (len=6) "string", isMap: (bool) false, @@ -156,11 +156,11 @@ }) } }), - (*main.SortableMessage)(0xc000355480)({ + (*main.SortableMessage)(0xc000347580)({ fullName: (string) (len=13) "ConfigRequest", name: (string) (len=13) "ConfigRequest", - fields: ([]*main.Field) (len=4 cap=4) { - (*main.Field)(0xc000354b00)({ + fields: ([]*main.Field) (len=5 cap=8) { + (*main.Field)(0xc000346b00)({ name: (string) (len=18) "automate_liquidity", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -170,7 +170,17 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354b40)({ + (*main.Field)(0xc000346b80)({ + name: (string) (len=10) "avatar_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (*main.Field)(0xc000346b40)({ name: (string) (len=21) "push_backups_to_nostr", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -180,7 +190,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354ac0)({ + (*main.Field)(0xc000346ac0)({ name: (string) (len=9) "relay_url", kind: (string) (len=6) "string", isMap: (bool) false, @@ -190,7 +200,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354a80)({ + (*main.Field)(0xc000346a80)({ name: (string) (len=11) "source_name", kind: (string) (len=6) "string", isMap: (bool) false, @@ -202,16 +212,16 @@ }) } }), - (*main.SortableMessage)(0xc000355400)({ + (*main.SortableMessage)(0xc0003474c0)({ fullName: (string) (len=5) "Empty", name: (string) (len=5) "Empty", fields: ([]*main.Field) }), - (*main.SortableMessage)(0xc000355540)({ + (*main.SortableMessage)(0xc000347640)({ fullName: (string) (len=20) "ServiceStateResponse", name: (string) (len=20) "ServiceStateResponse", - fields: ([]*main.Field) (len=12 cap=16) { - (*main.Field)(0xc000354cc0)({ + fields: ([]*main.Field) (len=14 cap=16) { + (*main.Field)(0xc000346d00)({ name: (string) (len=10) "admin_npub", kind: (string) (len=6) "string", isMap: (bool) false, @@ -221,7 +231,17 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354ec0)({ + (*main.Field)(0xc000346fc0)({ + name: (string) (len=6) "app_id", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (*main.Field)(0xc000346f00)({ name: (string) (len=18) "automate_liquidity", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -231,7 +251,17 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354dc0)({ + (*main.Field)(0xc000346f80)({ + name: (string) (len=10) "avatar_url", + kind: (string) (len=6) "string", + isMap: (bool) false, + isArray: (bool) false, + isEnum: (bool) false, + isMessage: (bool) false, + isOptional: (bool) false, + oneOfName: (string) "" + }), + (*main.Field)(0xc000346e00)({ name: (string) (len=8) "http_url", kind: (string) (len=6) "string", isMap: (bool) false, @@ -241,7 +271,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354d40)({ + (*main.Field)(0xc000346d80)({ name: (string) (len=9) "lnd_state", kind: (string) (len=8) "LndState", isMap: (bool) false, @@ -251,7 +281,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354e00)({ + (*main.Field)(0xc000346e40)({ name: (string) (len=8) "nprofile", kind: (string) (len=6) "string", isMap: (bool) false, @@ -261,7 +291,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354c40)({ + (*main.Field)(0xc000346c80)({ name: (string) (len=13) "provider_name", kind: (string) (len=6) "string", isMap: (bool) false, @@ -271,7 +301,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354f00)({ + (*main.Field)(0xc000346f40)({ name: (string) (len=21) "push_backups_to_nostr", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -281,7 +311,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354d00)({ + (*main.Field)(0xc000346d40)({ name: (string) (len=15) "relay_connected", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -291,7 +321,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354e80)({ + (*main.Field)(0xc000346ec0)({ name: (string) (len=9) "relay_url", kind: (string) (len=6) "string", isMap: (bool) false, @@ -301,7 +331,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354c80)({ + (*main.Field)(0xc000346cc0)({ name: (string) (len=6) "relays", kind: (string) (len=6) "string", isMap: (bool) false, @@ -311,7 +341,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354e40)({ + (*main.Field)(0xc000346e80)({ name: (string) (len=11) "source_name", kind: (string) (len=6) "string", isMap: (bool) false, @@ -321,7 +351,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354d80)({ + (*main.Field)(0xc000346dc0)({ name: (string) (len=11) "watchdog_ok", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -333,11 +363,11 @@ }) } }), - (*main.SortableMessage)(0xc000355440)({ + (*main.SortableMessage)(0xc000347500)({ fullName: (string) (len=13) "StateResponse", name: (string) (len=13) "StateResponse", fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc000354a40)({ + (*main.Field)(0xc000346a40)({ name: (string) (len=12) "admin_linked", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -347,7 +377,7 @@ isOptional: (bool) false, oneOfName: (string) "" }), - (*main.Field)(0xc000354a00)({ + (*main.Field)(0xc000346a00)({ name: (string) (len=11) "config_sent", kind: (string) (len=4) "bool", isMap: (bool) false, @@ -362,10 +392,10 @@ } ([]*main.OneOf) (len=1 cap=1) { - (*main.OneOf)(0xc00012b1a0)({ + (*main.OneOf)(0xc0000e31a0)({ kind: (string) (len=37) "AdminConnectInfoResponse_connect_info", fields: ([]*main.Field) (len=2 cap=2) { - (*main.Field)(0xc000354bc0)({ + (*main.Field)(0xc000346c00)({ name: (string) (len=11) "admin_token", kind: (string) (len=6) "string", isMap: (bool) false, @@ -375,7 +405,7 @@ isOptional: (bool) false, oneOfName: (string) (len=12) "connect_info" }), - (*main.Field)(0xc000354c00)({ + (*main.Field)(0xc000346c40)({ name: (string) (len=13) "enrolled_npub", kind: (string) (len=6) "string", isMap: (bool) false, diff --git a/proto/wizard_service/autogenerated/go/types.go b/proto/wizard_service/autogenerated/go/types.go index 93ecd50e..c35bfc9c 100644 --- a/proto/wizard_service/autogenerated/go/types.go +++ b/proto/wizard_service/autogenerated/go/types.go @@ -22,6 +22,7 @@ type AdminConnectInfoResponse struct { } type ConfigRequest struct { Automate_liquidity bool `json:"automate_liquidity"` + Avatar_url string `json:"avatar_url"` Push_backups_to_nostr bool `json:"push_backups_to_nostr"` Relay_url string `json:"relay_url"` Source_name string `json:"source_name"` @@ -30,7 +31,9 @@ type Empty struct { } type ServiceStateResponse struct { Admin_npub string `json:"admin_npub"` + App_id string `json:"app_id"` Automate_liquidity bool `json:"automate_liquidity"` + Avatar_url string `json:"avatar_url"` Http_url string `json:"http_url"` Lnd_state LndState `json:"lnd_state"` Nprofile string `json:"nprofile"` diff --git a/proto/wizard_service/autogenerated/ts/types.ts b/proto/wizard_service/autogenerated/ts/types.ts index 948b7b9f..80026099 100644 --- a/proto/wizard_service/autogenerated/ts/types.ts +++ b/proto/wizard_service/autogenerated/ts/types.ts @@ -69,6 +69,7 @@ export const AdminConnectInfoResponseValidate = (o?: AdminConnectInfoResponse, o export type ConfigRequest = { automate_liquidity: boolean + avatar_url: string push_backups_to_nostr: boolean relay_url: string source_name: string @@ -77,6 +78,7 @@ export const ConfigRequestOptionalFields: [] = [] export type ConfigRequestOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] automate_liquidity_CustomCheck?: (v: boolean) => boolean + avatar_url_CustomCheck?: (v: string) => boolean push_backups_to_nostr_CustomCheck?: (v: boolean) => boolean relay_url_CustomCheck?: (v: string) => boolean source_name_CustomCheck?: (v: string) => boolean @@ -88,6 +90,9 @@ export const ConfigRequestValidate = (o?: ConfigRequest, opts: ConfigRequestOpti if (typeof o.automate_liquidity !== 'boolean') return new Error(`${path}.automate_liquidity: is not a boolean`) if (opts.automate_liquidity_CustomCheck && !opts.automate_liquidity_CustomCheck(o.automate_liquidity)) return new Error(`${path}.automate_liquidity: custom check failed`) + if (typeof o.avatar_url !== 'string') return new Error(`${path}.avatar_url: is not a string`) + if (opts.avatar_url_CustomCheck && !opts.avatar_url_CustomCheck(o.avatar_url)) return new Error(`${path}.avatar_url: custom check failed`) + if (typeof o.push_backups_to_nostr !== 'boolean') return new Error(`${path}.push_backups_to_nostr: is not a boolean`) if (opts.push_backups_to_nostr_CustomCheck && !opts.push_backups_to_nostr_CustomCheck(o.push_backups_to_nostr)) return new Error(`${path}.push_backups_to_nostr: custom check failed`) @@ -115,7 +120,9 @@ export const EmptyValidate = (o?: Empty, opts: EmptyOptions = {}, path: string = export type ServiceStateResponse = { admin_npub: string + app_id: string automate_liquidity: boolean + avatar_url: string http_url: string lnd_state: LndState nprofile: string @@ -131,7 +138,9 @@ export const ServiceStateResponseOptionalFields: [] = [] export type ServiceStateResponseOptions = OptionsBaseMessage & { checkOptionalsAreSet?: [] admin_npub_CustomCheck?: (v: string) => boolean + app_id_CustomCheck?: (v: string) => boolean automate_liquidity_CustomCheck?: (v: boolean) => boolean + avatar_url_CustomCheck?: (v: string) => boolean http_url_CustomCheck?: (v: string) => boolean lnd_state_CustomCheck?: (v: LndState) => boolean nprofile_CustomCheck?: (v: string) => boolean @@ -150,9 +159,15 @@ export const ServiceStateResponseValidate = (o?: ServiceStateResponse, opts: Ser if (typeof o.admin_npub !== 'string') return new Error(`${path}.admin_npub: is not a string`) if (opts.admin_npub_CustomCheck && !opts.admin_npub_CustomCheck(o.admin_npub)) return new Error(`${path}.admin_npub: custom check failed`) + if (typeof o.app_id !== 'string') return new Error(`${path}.app_id: is not a string`) + if (opts.app_id_CustomCheck && !opts.app_id_CustomCheck(o.app_id)) return new Error(`${path}.app_id: custom check failed`) + if (typeof o.automate_liquidity !== 'boolean') return new Error(`${path}.automate_liquidity: is not a boolean`) if (opts.automate_liquidity_CustomCheck && !opts.automate_liquidity_CustomCheck(o.automate_liquidity)) return new Error(`${path}.automate_liquidity: custom check failed`) + if (typeof o.avatar_url !== 'string') return new Error(`${path}.avatar_url: is not a string`) + if (opts.avatar_url_CustomCheck && !opts.avatar_url_CustomCheck(o.avatar_url)) return new Error(`${path}.avatar_url: custom check failed`) + if (typeof o.http_url !== 'string') return new Error(`${path}.http_url: is not a string`) if (opts.http_url_CustomCheck && !opts.http_url_CustomCheck(o.http_url)) return new Error(`${path}.http_url: custom check failed`) diff --git a/src/services/main/index.ts b/src/services/main/index.ts index 3b98603c..71c64592 100644 --- a/src/services/main/index.ts +++ b/src/services/main/index.ts @@ -99,7 +99,7 @@ export default class { StartBeacons() { this.applicationManager.StartAppsServiceBeacon(app => { - this.UpdateBeacon(app, { type: 'service', name: app.name }) + this.UpdateBeacon(app, { type: 'service', name: app.name, avatarUrl: (app as any).avatar_url }) }) } @@ -386,7 +386,7 @@ export default class { }) } - async UpdateBeacon(app: Application, content: { type: 'service', name: string }) { + async UpdateBeacon(app: Application, content: { type: 'service', name: string, avatarUrl?: string }) { if (!app.nostr_public_key) { getLogger({ appName: app.name })("cannot update beacon, public key not set") return diff --git a/src/services/storage/entity/Application.ts b/src/services/storage/entity/Application.ts index e4367c07..637a2f41 100644 --- a/src/services/storage/entity/Application.ts +++ b/src/services/storage/entity/Application.ts @@ -27,6 +27,9 @@ export class Application { @Column({ nullable: true, unique: true }) nostr_public_key?: string + @Column({ nullable: true }) + avatar_url?: string + @CreateDateColumn() created_at: Date diff --git a/src/services/storage/migrations/1761000001000-application_avatar_url.ts b/src/services/storage/migrations/1761000001000-application_avatar_url.ts new file mode 100644 index 00000000..9c16a5ee --- /dev/null +++ b/src/services/storage/migrations/1761000001000-application_avatar_url.ts @@ -0,0 +1,16 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class ApplicationAvatarUrl1761000001000 implements MigrationInterface { + name = 'ApplicationAvatarUrl1761000001000' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "application" ADD COLUMN "avatar_url" varchar`); + } + + public async down(queryRunner: QueryRunner): Promise { + // SQLite has limited ALTER TABLE support; we can recreate table if needed, but for now just keep it simple + // No-op: dropping a column is non-trivial; leave column in place on downgrade + } +} + + diff --git a/src/services/storage/migrations/runner.ts b/src/services/storage/migrations/runner.ts index f22ce37e..37f89b0a 100644 --- a/src/services/storage/migrations/runner.ts +++ b/src/services/storage/migrations/runner.ts @@ -25,12 +25,13 @@ import { OldSomethingLeftover1753106599604 } from './1753106599604-old_something import { UserReceivingInvoiceIdx1753109184611 } from './1753109184611-user_receiving_invoice_idx.js' import { UserAccess1759426050669 } from './1759426050669-user_access.js' import { AddBlindToUserOffer1760000000000 } from './1760000000000-add_blind_to_user_offer.js' +import { ApplicationAvatarUrl1761000001000 } from './1761000001000-application_avatar_url.js' export const allMigrations = [Initial1703170309875, LspOrder1718387847693, LiquidityProvider1719335699480, LndNodeInfo1720187506189, TrackedProvider1720814323679, CreateInviteTokenTable1721751414878, PaymentIndex1721760297610, DebitAccess1726496225078, DebitAccessFixes1726685229264, DebitToPub1727105758354, UserCbUrl1727112281043, UserOffer1733502626042, ManagementGrant1751307732346, ManagementGrantBanned1751989251513, - InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000] + InvoiceCallbackUrls1752425992291, OldSomethingLeftover1753106599604, UserReceivingInvoiceIdx1753109184611, AppUserDevice1753285173175, UserAccess1759426050669, AddBlindToUserOffer1760000000000, ApplicationAvatarUrl1761000001000] export const allMetricsMigrations = [LndMetrics1703170330183, ChannelRouting1709316653538, HtlcCount1724266887195, BalanceEvents1724860966825, RootOps1732566440447, RootOpsTime1745428134124, ChannelEvents1750777346411] /* export const TypeOrmMigrationRunner = async (log: PubLogger, storageManager: Storage, settings: DbSettings, arg: string | undefined): Promise => { diff --git a/src/services/wizard/index.ts b/src/services/wizard/index.ts index 6cb7f218..ce44bb3d 100644 --- a/src/services/wizard/index.ts +++ b/src/services/wizard/index.ts @@ -45,6 +45,7 @@ export class Wizard { const appNamesList = apps.map(app => app.name).join(', ') const relays = this.settings.nostrRelaySettings ? this.settings.nostrRelaySettings.relays : []; const relayUrl = (relays && relays.length > 0) ? relays[0] : ''; + const defaultApp = apps.find(a => a.name === this.settings.defaultAppName) || apps[0] return { admin_npub: this.adminManager.GetAdminNpub(), http_url: this.settings.serviceUrl, @@ -58,6 +59,8 @@ export class Wizard { relay_url: relayUrl, automate_liquidity: this.settings.liquiditySettings.liquidityProviderPub !== 'null', push_backups_to_nostr: this.settings.pushBackupsToNostr, + avatar_url: (defaultApp as any)?.avatar_url || '', + app_id: defaultApp?.app_id || '' } } catch (e) { this.log(`Error in GetServiceState: ${(e as Error).message}`) @@ -75,6 +78,8 @@ export class Wizard { relay_url: '', automate_liquidity: false, push_backups_to_nostr: false, + avatar_url: '', + app_id: '' } } } @@ -154,7 +159,7 @@ export class Wizard { const defaultNames = ['wallet', 'wallet-test', this.settings.defaultAppName] const existingDefaultApp = appsList.find(app => defaultNames.includes(app.name)) if (existingDefaultApp) { - await this.storage.applicationStorage.UpdateApplication(existingDefaultApp, { name: req.source_name }) + await this.storage.applicationStorage.UpdateApplication(existingDefaultApp, { name: req.source_name, avatar_url: (req as any).avatar_url || existingDefaultApp.avatar_url }) } } catch (e) { this.log(`Error updating app name: ${(e as Error).message}`) diff --git a/static/index.html b/static/index.html index 40778249..4b684f1e 100644 --- a/static/index.html +++ b/static/index.html @@ -19,7 +19,7 @@
Lightning Pub logo - Lightning Pub logo + Lightning Pub logo
@@ -43,6 +43,11 @@ +
+ Avatar URL (shown in wallet): + +
+
diff --git a/static/js/wizard.js b/static/js/wizard.js index 37d90795..c9717150 100644 --- a/static/js/wizard.js +++ b/static/js/wizard.js @@ -9,6 +9,7 @@ $(() => { // Inputs const nodeNameInput = $("#nodeName"); const relayUrlInput = $("#relayUrl"); + const avatarUrlInput = $("#avatarUrl"); const customCheckbox = $("#customCheckbox"); const automateLiquidityRadio = $("#automate"); const manualLiquidityRadio = $("#manual"); @@ -80,6 +81,7 @@ $(() => { relay_url: relayUrl, automate_liquidity: automateLiquidityRadio.prop('checked'), push_backups_to_nostr: backupNostrRadio.prop('checked'), + avatar_url: avatarUrlInput.val() }; try { @@ -128,6 +130,11 @@ $(() => { } else { relayUrlInput.val(state.relay_url); } + const robo = state.app_id ? `https://robohash.org/${encodeURIComponent(state.app_id)}.png?size=256x256&set=set3` : '' + avatarUrlInput.attr('placeholder', robo || 'https://example.com/avatar.png') + if (state.avatar_url) { + avatarUrlInput.val(state.avatar_url); + } syncRelayState(); if (state.automate_liquidity) {