{ "name": "INBUXA", "short_name": "INBUXA", "description": "INBUXA webmail", "_comment": "JSON has no comments, so: every URL below is relative on purpose. Manifest members resolve against the manifest's own address, so these follow BASE_PATH with nothing substituted into them at build time. Root-absolute values pinned the installed app, its scope and its shortcuts to the domain root whatever the mount was.", "_comment_id": "There is deliberately no `id`. It is the one member NOT resolved against this file's address -- the spec resolves it against the origin of start_url, so `./`, `mail` and `/mail` all mean the same thing at the domain root and none of them can name a subpath mount. Adding one would therefore break the same thing the note above describes. Worse, the default id IS start_url, which is already mount-correct: writing an id now would give every installed copy a new identity and orphan it as a second app rather than updating it. If one is ever wanted it has to be substituted at build time from BASE_PATH, and the changeover costs everybody their install.", "start_url": "mail", "scope": "./", "categories": ["productivity", "utilities"], "_comment_launch": "One window, not one per launch. A `mailto:` link, a manifest shortcut or a notification tapped while ihasmail is already open should arrive in the copy that is running rather than beside it -- two windows on the same inbox disagree about what has been read. `navigate-existing` rather than `focus-existing` because the latter only focuses and leaves the app to handle the target URL through launchQueue, which nothing here consumes: it would swallow the mailto entirely. The navigation goes through the same beforeunload guard as a reload, so an unsent draft still stops it and asks.", "launch_handler": { "client_mode": "navigate-existing" }, "_comment_share_target": "Being in the operating system's share sheet, which is the other half of the Share this app now offers. `action` is relative like everything else here, so it follows the mount; it has to sit inside `scope`, and `./` covers it. POST with multipart because a share can carry files, and a POST to a page is not something the app can answer -- the service worker intercepts it, puts the payload where a tab can collect it, and redirects. `accept` names wildcard families AND explicit types and extensions on purpose: a mail client attaches anything, but wildcard support is not in the specification and operating systems differ over which form they match on, so the explicit list is what holds if the families are ignored. Android and Chromium only -- iOS does not implement share targets at all.", "share_target": { "action": "share", "method": "POST", "enctype": "multipart/form-data", "params": { "title": "title", "text": "text", "url": "url", "files": [ { "name": "files", "accept": [ "image/*", "video/*", "audio/*", "text/*", "application/pdf", "application/zip", "application/json", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.oasis.opendocument.text", "application/vnd.oasis.opendocument.spreadsheet", "message/rfc822", "text/calendar", "text/vcard", ".pdf", ".zip", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".odt", ".ods", ".csv", ".txt", ".md", ".eml", ".ics", ".vcf", ".jpg", ".jpeg", ".png", ".gif", ".webp", ".heic", ".mp4", ".mp3" ] } ] } }, "protocol_handlers": [ { "protocol": "mailto", "url": "mail?mailto=%s" } ], "display": "standalone", "orientation": "any", "background_color": "#ffffff", "theme_color": "#0f766e", "icons": [ { "src": "img/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "img/icon-512.png", "sizes": "512x512", "type": "image/png" }, { "src": "img/icon-maskable.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" } ], "shortcuts": [ { "name": "Compose", "url": "mail?compose=new", "description": "Write a new message" }, { "name": "Calendar", "url": "calendar" }, { "name": "Contacts", "url": "contacts" } ] }