diff --git a/apps/90sclk/metadata.json b/apps/90sclk/metadata.json index bfbb6b080..b4b320a1b 100644 --- a/apps/90sclk/metadata.json +++ b/apps/90sclk/metadata.json @@ -14,5 +14,6 @@ {"name":"90sclk.app.js","url":"app.js"}, {"name":"90sclk.img","url":"app-icon.js","evaluate":true}, {"name":"90sclk.settings.js","url":"settings.js"} - ] + ], + "data": [{"name":"90sclk.setting.json"}] } diff --git a/apps/activepedom/metadata.json b/apps/activepedom/metadata.json index 81bafb573..fa1044d85 100644 --- a/apps/activepedom/metadata.json +++ b/apps/activepedom/metadata.json @@ -14,5 +14,6 @@ {"name":"activepedom.settings.js","url":"settings.js"}, {"name":"activepedom.img","url":"app-icon.js","evaluate":true}, {"name":"activepedom.app.js","url":"app.js"} - ] + ], + "data":[{"name":"activepedom.settings.json"}] } diff --git a/apps/bthrm/metadata.json b/apps/bthrm/metadata.json index fea274ff3..6c31759c9 100644 --- a/apps/bthrm/metadata.json +++ b/apps/bthrm/metadata.json @@ -18,5 +18,6 @@ {"name":"bthrm.settings.js","url":"settings.js"}, {"name":"bthrm","url":"lib.js"}, {"name":"bthrm.default.json","url":"default.json"} - ] + ], + "data": [{"name":"bthrm.json"}] } diff --git a/apps/bwclk/metadata.json b/apps/bwclk/metadata.json index fba759bf0..d4091c2fe 100644 --- a/apps/bwclk/metadata.json +++ b/apps/bwclk/metadata.json @@ -15,5 +15,6 @@ {"name":"bwclk.app.js","url":"app.js"}, {"name":"bwclk.img","url":"app-icon.js","evaluate":true}, {"name":"bwclk.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"bwclk.setting.json"}] } diff --git a/apps/bwclklite/metadata.json b/apps/bwclklite/metadata.json index b073f985e..f8dffdca9 100644 --- a/apps/bwclklite/metadata.json +++ b/apps/bwclklite/metadata.json @@ -39,5 +39,10 @@ "name": "bwclklite.settings.js", "url": "settings.js" } + ], + "data": [ + { + "name": "bwclklite.setting.json" + } ] } diff --git a/apps/cassioWatch/metadata.json b/apps/cassioWatch/metadata.json index 4b9985c82..fb7dfd401 100644 --- a/apps/cassioWatch/metadata.json +++ b/apps/cassioWatch/metadata.json @@ -12,7 +12,10 @@ "readme": "README.md", "storage": [ { "name": "cassioWatch.app.js", "url": "app.js" }, - {"name":"cassioWatch.settings.js","url":"settings.js"}, + { "name": "cassioWatch.settings.js","url": "settings.js" }, { "name": "cassioWatch.img", "url": "icon.js", "evaluate": true } + ], + "data": [ + { "name": "cassioWatch.settings.json" } ] } diff --git a/apps/chargerot/metadata.json b/apps/chargerot/metadata.json index 99c97070e..1b13403d7 100644 --- a/apps/chargerot/metadata.json +++ b/apps/chargerot/metadata.json @@ -11,5 +11,6 @@ "storage": [ {"name":"chargerot.boot.js","url":"boot.js"}, {"name":"chargerot.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"chargerot.settings.json"}] } diff --git a/apps/clkinfostopw/settings.ts b/apps/clkinfostopw/settings.ts deleted file mode 100644 index a7bfce1e5..000000000 --- a/apps/clkinfostopw/settings.ts +++ /dev/null @@ -1,36 +0,0 @@ -const enum StopWatchFormat { - HMS, - Colon, -} -type StopWatchSettings = { - format: StopWatchFormat, -}; - -(back => { - const SETTINGS_FILE = "clkinfostopw.setting.json"; - - const storage = require("Storage"); - const settings: StopWatchSettings = Object.assign( - { format: StopWatchFormat.HMS }, - storage.readJSON(SETTINGS_FILE, true), - ); - - const save = () => { - storage.writeJSON(SETTINGS_FILE, settings) - }; - - E.showMenu({ - "": { "title": "stopwatch" }, - "< Back": back, - "Format": { - value: settings.format, - min: StopWatchFormat.HMS, - max: StopWatchFormat.Colon, - format: v => v === StopWatchFormat.HMS ? "12m34s" : "12:34", - onchange: v => { - settings.format = v; - save(); - }, - }, - }); -}) satisfies SettingsFunc diff --git a/apps/contourclock/metadata.json b/apps/contourclock/metadata.json index d59999c04..ca5ee114f 100644 --- a/apps/contourclock/metadata.json +++ b/apps/contourclock/metadata.json @@ -15,5 +15,6 @@ {"name":"contourclock.settings.js","url":"contourclock.settings.js"}, {"name":"contourclock","url":"lib.js"}, {"name":"contourclock.img","url":"app-icon.js","evaluate":true} - ] + ], + "data": [{"name":"contourclock.json"}] } diff --git a/apps/cprassist/metadata.json b/apps/cprassist/metadata.json index d832e98c5..94ba71d1b 100644 --- a/apps/cprassist/metadata.json +++ b/apps/cprassist/metadata.json @@ -13,5 +13,6 @@ {"name":"cprassist.app.js","url":"cprassist.js"}, {"name":"cprassist.img","url":"cprassist-icon.js","evaluate":true}, {"name":"cprassist.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"cprassist.settings.json"}] } diff --git a/apps/cscsensor/metadata.json b/apps/cscsensor/metadata.json index 87eb5d12f..d7c3add53 100644 --- a/apps/cscsensor/metadata.json +++ b/apps/cscsensor/metadata.json @@ -12,5 +12,8 @@ {"name":"cscsensor.app.js","url":"cscsensor.app.js"}, {"name":"cscsensor.settings.js","url":"settings.js"}, {"name":"cscsensor.img","url":"cscsensor-icon.js","evaluate":true} + ], + "data": [ + {"name":"cscsensor.json"} ] } diff --git a/apps/cycling/metadata.json b/apps/cycling/metadata.json index cb4260bb2..caf93eda3 100644 --- a/apps/cycling/metadata.json +++ b/apps/cycling/metadata.json @@ -13,5 +13,8 @@ {"name":"cycling.settings.js","url":"settings.js"}, {"name":"blecsc","url":"blecsc.js"}, {"name":"cycling.img","url":"cycling.icon.js","evaluate": true} + ], + "data": [ + {"name":"cycling.json"} ] } diff --git a/apps/dragboard/metadata.json b/apps/dragboard/metadata.json index 964ace3a7..58de5153c 100644 --- a/apps/dragboard/metadata.json +++ b/apps/dragboard/metadata.json @@ -6,10 +6,13 @@ "type":"textinput", "tags": "keyboard", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"}], "readme": "README.md", "storage": [ {"name":"textinput","url":"lib.js"}, {"name":"dragboard.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"dragboard.json"} ] } diff --git a/apps/draguboard/metadata.json b/apps/draguboard/metadata.json index 926e36807..dc9b06254 100644 --- a/apps/draguboard/metadata.json +++ b/apps/draguboard/metadata.json @@ -6,10 +6,13 @@ "type":"textinput", "tags": "keyboard", "supports" : ["BANGLEJS2"], - "screenshots": [{"url":"screenshot.png"}], + "screenshots": [{"url":"screenshot.png"}], "readme": "README.md", "storage": [ {"name":"textinput","url":"lib.js"}, {"name":"draguboard.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"draguboard.json"} ] } diff --git a/apps/f9lander/metadata.json b/apps/f9lander/metadata.json index e53805ee0..5a3887c9e 100644 --- a/apps/f9lander/metadata.json +++ b/apps/f9lander/metadata.json @@ -12,5 +12,6 @@ {"name":"f9lander.app.js","url":"app.js"}, {"name":"f9lander.img","url":"app-icon.js","evaluate":true}, {"name":"f9lander.settings.js", "url":"settings.js"} - ] + ], + "data":[{"name":"f9settings.json"}] } diff --git a/apps/game1024/metadata.json b/apps/game1024/metadata.json index f3b72aad3..45d6e3f61 100644 --- a/apps/game1024/metadata.json +++ b/apps/game1024/metadata.json @@ -14,5 +14,6 @@ {"name":"game1024.app.js","url":"app.js"}, {"name":"game1024.settings.js","url":"settings.js"}, {"name":"game1024.img","url":"app-icon.js","evaluate":true} - ] + ], + "data":[{"name":"game1024.settings.json"}] } diff --git a/apps/getup/metadata.json b/apps/getup/metadata.json index 0c5a7cc5b..00bab40be 100644 --- a/apps/getup/metadata.json +++ b/apps/getup/metadata.json @@ -14,5 +14,6 @@ {"name":"getup.app.js","url":"app.js"}, {"name":"getup.settings.js","url":"settings.js"}, {"name":"getup.img","url":"app-icon.js","evaluate":true} - ] + ], + "data":[{"name":"getup.settings.json"}] } diff --git a/apps/happyclk/metadata.json b/apps/happyclk/metadata.json index e5129b0f0..da7bdcd16 100644 --- a/apps/happyclk/metadata.json +++ b/apps/happyclk/metadata.json @@ -20,5 +20,6 @@ {"name":"happyclk.app.js","url":"happyclk.app.js"}, {"name":"happyclk.img","url":"happyclk.icon.js","evaluate":true}, {"name":"happyclk.settings.js","url":"happyclk.settings.js"} - ] + ], + "data":[{"name":"happyclk.setting.json"}] } diff --git a/apps/hralarm/metadata.json b/apps/hralarm/metadata.json index 4c661b3fc..c99cb857f 100644 --- a/apps/hralarm/metadata.json +++ b/apps/hralarm/metadata.json @@ -4,7 +4,7 @@ "shortName":"HR Alarm", "version":"0.02", "description": "This invisible widget vibrates whenever the heart rate gets close to the upper limit or goes over or under the configured limits", - "icon": "widget.png", + "icon": "widget.png", "type": "widget", "tags": "widget", "supports" : ["BANGLEJS2"], @@ -12,5 +12,8 @@ "storage": [ {"name":"hralarm.wid.js","url":"widget.js"}, {"name":"hralarm.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"hralarm.json"} ] } diff --git a/apps/imageclock/metadata.json b/apps/imageclock/metadata.json index b291ab01e..f8a0aa61e 100644 --- a/apps/imageclock/metadata.json +++ b/apps/imageclock/metadata.json @@ -15,5 +15,8 @@ {"name":"imageclock.app.js","url":"app.js"}, {"name":"imageclock.settings.js","url":"settings.js"}, {"name":"imageclock.img","url":"app-icon.js","evaluate":true} + ], + "data": [ + {"name":"imageclock.json"} ] } diff --git a/apps/kbtouch/metadata.json b/apps/kbtouch/metadata.json index 8d7434e44..31dc8c9a8 100644 --- a/apps/kbtouch/metadata.json +++ b/apps/kbtouch/metadata.json @@ -12,5 +12,6 @@ {"name":"textinput","url":"lib.js"}, {"name":"kbtouch.settings.js","url":"settings.js"} ], - "sortorder":-1 + "sortorder":-1, + "data":[{"name":"kbtouch.settings.json"}] } diff --git a/apps/lcars/metadata.json b/apps/lcars/metadata.json index 65c59081f..2cefb544f 100644 --- a/apps/lcars/metadata.json +++ b/apps/lcars/metadata.json @@ -16,5 +16,6 @@ {"name":"lcars.app.js","url":"lcars.app.js"}, {"name":"lcars.img","url":"lcars.icon.js","evaluate":true}, {"name":"lcars.settings.js","url":"lcars.settings.js"} - ] + ], + "data":[{"name":"lcars.setting.json"}] } diff --git a/apps/limelight/metadata.json b/apps/limelight/metadata.json index 0e5dfd565..5c6bcfd76 100644 --- a/apps/limelight/metadata.json +++ b/apps/limelight/metadata.json @@ -13,5 +13,8 @@ {"name":"limelight.app.js","url":"limelight.app.js"}, {"name":"limelight.settings.js","url":"limelight.settings.js"}, {"name":"limelight.img","url":"limelight.icon.js","evaluate":true} + ], + "data": [ + {"name":"limelight.json"} ] } diff --git a/apps/linuxclock/metadata.json b/apps/linuxclock/metadata.json index 2bfe1d51f..ccd9db5e7 100644 --- a/apps/linuxclock/metadata.json +++ b/apps/linuxclock/metadata.json @@ -14,5 +14,6 @@ {"name":"linuxclock.app.js","url":"app.js"}, {"name":"linuxclock.img","url":"app-icon.js","evaluate":true}, {"name":"linuxclock.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"linuxclock.setting.json"}] } diff --git a/apps/loadingscreen/metadata.json b/apps/loadingscreen/metadata.json index 199f4a2b4..1815e4ce8 100644 --- a/apps/loadingscreen/metadata.json +++ b/apps/loadingscreen/metadata.json @@ -10,5 +10,6 @@ "readme": "README.md", "storage": [ {"name":"loadingscreen.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":".loading"}] } diff --git a/apps/metronome/metadata.json b/apps/metronome/metadata.json index 7f8582ca5..8ada5d98c 100644 --- a/apps/metronome/metadata.json +++ b/apps/metronome/metadata.json @@ -13,5 +13,6 @@ {"name":"metronome.app.js","url":"metronome.js"}, {"name":"metronome.img","url":"metronome-icon.js","evaluate":true}, {"name":"metronome.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"metronome.settings.json"}] } diff --git a/apps/mysticclock/metadata.json b/apps/mysticclock/metadata.json index bd2df2f8d..51f44b79b 100644 --- a/apps/mysticclock/metadata.json +++ b/apps/mysticclock/metadata.json @@ -14,5 +14,8 @@ {"name":"mysticclock.app.js","url":"mystic-clock-app.js"}, {"name":"mysticclock.settings.js","url":"mystic-clock-settings.js"}, {"name":"mysticclock.img","url":"mystic-clock-icon.js","evaluate":true} + ], + "data": [ + {"name":"mysticclock.settings.json"} ] } diff --git a/apps/mysticdock/metadata.json b/apps/mysticdock/metadata.json index 2775b0b72..0ebff3b9b 100644 --- a/apps/mysticdock/metadata.json +++ b/apps/mysticdock/metadata.json @@ -13,5 +13,8 @@ {"name":"mysticdock.boot.js","url":"mystic-dock-boot.js"}, {"name":"mysticdock.settings.js","url":"mystic-dock-settings.js"}, {"name":"mysticdock.img","url":"mystic-dock-icon.js","evaluate":true} + ], + "data": [ + {"name":"mysticdock.settings.json"} ] } diff --git a/apps/openwind/metadata.json b/apps/openwind/metadata.json index 01d7ca124..5e0a60972 100644 --- a/apps/openwind/metadata.json +++ b/apps/openwind/metadata.json @@ -6,10 +6,11 @@ "icon": "openwind.png", "readme": "README.md", "tags": "ble,outdoors,gps,sailing", - "supports" : ["BANGLEJS", "BANGLEJS2"], + "supports" : ["BANGLEJS", "BANGLEJS2"], "storage": [ {"name":"openwind.app.js","url":"app.js"}, {"name":"openwind.img","url":"app-icon.js","evaluate":true}, {"name":"openwind.settings.js", "url":"settings.js"} - ] + ], + "data":[{"name":"openwindsettings.json"}] } diff --git a/apps/pebble/metadata.json b/apps/pebble/metadata.json index 0ccb8e2af..49dbcd820 100644 --- a/apps/pebble/metadata.json +++ b/apps/pebble/metadata.json @@ -15,5 +15,8 @@ {"name":"pebble.app.js","url":"pebble.app.js"}, {"name":"pebble.settings.js","url":"pebble.settings.js"}, {"name":"pebble.img","url":"pebble.icon.js","evaluate":true} + ], + "data": [ + {"name":"pebble.settings.json"} ] } diff --git a/apps/pebbled/metadata.json b/apps/pebbled/metadata.json index 62fabc3e7..8924e600a 100644 --- a/apps/pebbled/metadata.json +++ b/apps/pebbled/metadata.json @@ -14,5 +14,6 @@ {"name":"pebbled.app.js","url":"pebbled.app.js"}, {"name":"pebbled.settings.js","url":"pebbled.settings.js"}, {"name":"pebbled.img","url":"pebbled.icon.js","evaluate":true} - ] + ], + "data":[{"name":"pebbleDistance.json"}] } diff --git a/apps/pebblepp/metadata.json b/apps/pebblepp/metadata.json index 6821fdc50..88c1d8fd5 100644 --- a/apps/pebblepp/metadata.json +++ b/apps/pebblepp/metadata.json @@ -15,5 +15,8 @@ {"name":"pebblepp.app.js","url":"app.js"}, {"name":"pebblepp.settings.js","url":"settings.js"}, {"name":"pebblepp.img","url":"icon.js","evaluate":true} + ], + "data": [ + {"name":"pebblepp.settings.json"} ] } diff --git a/apps/pomoplus/metadata.json b/apps/pomoplus/metadata.json index 84a82c0e1..0db15ab4d 100644 --- a/apps/pomoplus/metadata.json +++ b/apps/pomoplus/metadata.json @@ -32,5 +32,8 @@ "name": "pomoplus.settings.js", "url": "settings.js" } + ], + "data": [ + {"name":"pomoplus.settings.json"} ] } diff --git a/apps/rebble/metadata.json b/apps/rebble/metadata.json index c380204a4..6242236c8 100644 --- a/apps/rebble/metadata.json +++ b/apps/rebble/metadata.json @@ -15,5 +15,8 @@ {"name":"rebble.app.js","url":"rebble.app.js"}, {"name":"rebble.settings.js","url":"rebble.settings.js"}, {"name":"rebble.img","url":"rebble.icon.js","evaluate":true} + ], + "data": [ + {"name":"rebble.settings.json"} ] } diff --git a/apps/sensortools/metadata.json b/apps/sensortools/metadata.json index 48b146617..bffffd090 100644 --- a/apps/sensortools/metadata.json +++ b/apps/sensortools/metadata.json @@ -14,5 +14,8 @@ {"name":"sensortools.settings.js","url":"settings.js"}, {"name":"sensortools","url":"lib.js"}, {"name":"sensortools.default.json","url":"default.json"} + ], + "data": [ + {"name":"sensortools.settings.json"} ] } diff --git a/apps/sleeplogalarm/metadata.json b/apps/sleeplogalarm/metadata.json index 30d3dcda7..fd68ce376 100644 --- a/apps/sleeplogalarm/metadata.json +++ b/apps/sleeplogalarm/metadata.json @@ -17,5 +17,6 @@ {"name": "sleeplogalarm", "url": "lib.js"}, {"name": "sleeplogalarm.settings.js", "url": "settings.js"}, {"name": "sleeplogalarm.wid.js", "url": "widget.js"} - ] + ], + "data":[{"name":"sleeplogalarm.settings.json"}] } diff --git a/apps/speedalt/metadata.json b/apps/speedalt/metadata.json index 89bfd4a57..1ecb2b562 100644 --- a/apps/speedalt/metadata.json +++ b/apps/speedalt/metadata.json @@ -15,5 +15,8 @@ {"name":"speedalt.app.js","url":"app.js"}, {"name":"speedalt.img","url":"app-icon.js","evaluate":true}, {"name":"speedalt.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"speedalt.settings.json"} ] } diff --git a/apps/timecal/metadata.json b/apps/timecal/metadata.json index 287dce0ae..9175d92a3 100644 --- a/apps/timecal/metadata.json +++ b/apps/timecal/metadata.json @@ -12,5 +12,6 @@ "storage": [ {"name":"timecal.app.js","url":"timecal.app.js"}, {"name":"timecal.settings.js","url":"timecal.settings.js"} - ] + ], + "data":[{"name":"timecal.settings.json"}] } diff --git a/apps/torch/metadata.json b/apps/torch/metadata.json index 6837dc904..414222587 100644 --- a/apps/torch/metadata.json +++ b/apps/torch/metadata.json @@ -13,5 +13,8 @@ {"name":"torch.wid.js","url":"widget.js","supports": ["BANGLEJS"]}, {"name":"torch.img","url":"app-icon.js","evaluate":true}, {"name":"torch.settings.js","url":"settings.js"} + ], + "data": [ + {"name":"torch.settings.json"} ] } diff --git a/apps/widpedom/metadata.json b/apps/widpedom/metadata.json index f49d3ba5b..480519a29 100644 --- a/apps/widpedom/metadata.json +++ b/apps/widpedom/metadata.json @@ -10,5 +10,6 @@ "storage": [ {"name":"widpedom.wid.js","url":"widget.js"}, {"name":"widpedom.settings.js","url":"settings.js"} - ] + ], + "data":[{"name":"wpedom.json"}] } diff --git a/apps/wohrm/metadata.json b/apps/wohrm/metadata.json index 1e2ac2cb0..a5411c113 100644 --- a/apps/wohrm/metadata.json +++ b/apps/wohrm/metadata.json @@ -14,5 +14,6 @@ {"name":"wohrm.app.js","url":"app.js"}, {"name":"wohrm.settings.js","url":"settings.js"}, {"name":"wohrm.img","url":"app-icon.js","evaluate":true} - ] + ], + "data":[{"name":"wohrm.setting.json"}] } diff --git a/bin/sanitycheck.js b/bin/sanitycheck.js index ecba1876e..d5c755443 100755 --- a/bin/sanitycheck.js +++ b/bin/sanitycheck.js @@ -92,9 +92,12 @@ const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD }; /* These are warnings we know about but don't want in our output */ var KNOWN_WARNINGS = [ -"App gpsrec data file wildcard .gpsrc? does not include app ID", -"App owmweather data file weather.json is also listed as data file for app weather", + "App gpsrec data file wildcard .gpsrc? does not include app ID", + "App owmweather data file weather.json is also listed as data file for app weather", "App messagegui storage file messagegui is also listed as storage file for app messagelist", + "App carcrazy has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"carcrazy.settings.json\"}]`)", + "App loadingscreen has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"loadingscreen.settings.json\"}]`)", + "App trex has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"trex.settings.json\"}]`)", ]; function globToRegex(pattern) { @@ -116,7 +119,7 @@ apps.forEach((app,appIdx) => { if (!app.id) ERROR(`App ${appIdx} has no id`); var appDirRelative = APPSDIR_RELATIVE+app.id+"/"; var appDir = APPSDIR+app.id+"/"; - var metadataFile = appDirRelative+"metadata.json"; + var metadataFile = appDirRelative+"metadata.json"; if (existingApps.includes(app.id)) ERROR(`Duplicate app '${app.id}'`, {file:metadataFile}); existingApps.push(app.id); //console.log(`Checking ${app.id}...`); @@ -164,11 +167,11 @@ apps.forEach((app,appIdx) => { }); } if (app.readme) { - if (!fs.existsSync(appDir+app.readme)) + if (!fs.existsSync(appDir+app.readme)) ERROR(`App ${app.id} README file doesn't exist`, {file:metadataFile}); } else { let readme = fs.readdirSync(appDir).find(f => f.toLowerCase().includes("readme")); - if (readme) + if (readme) ERROR(`App ${app.id} has a README in the directory (${readme}) but it's not linked`, {file:metadataFile}); } if (app.custom && !fs.existsSync(appDir+app.custom)) ERROR(`App ${app.id} custom HTML doesn't exist`, {file:metadataFile}); @@ -253,6 +256,10 @@ apps.forEach((app,appIdx) => { if (a>=0 && b>=0 && a !d.name || !d.name.endsWith(".json")))) { + WARN(`App ${app.id} has a setting file but no corresponding data entry (add \`"data":[{"name":"${app.id}.settings.json"}]\`)`, {file:appDirRelative+file.url}); + } } for (const key in file) { if (!STORAGE_KEYS.includes(key)) ERROR(`App ${app.id} file ${file.name} has unknown key ${key}`, {file:appDirRelative+file.url});