@bobfrankston/rmfmail 1.0.634 → 1.0.643
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +4 -1
- package/client/app.js +22 -0
- package/client/app.js.map +1 -1
- package/client/app.ts +15 -0
- package/client/components/alarms.js +17 -7
- package/client/components/alarms.js.map +1 -1
- package/client/components/alarms.ts +17 -6
- package/client/compose/compose.css +14 -1
- package/client/compose/compose.html +1 -0
- package/client/compose/compose.js +34 -15
- package/client/compose/compose.js.map +1 -1
- package/client/compose/compose.ts +37 -8
- package/client/compose/editor.js +44 -3
- package/client/compose/editor.js.map +1 -1
- package/client/compose/editor.ts +49 -3
- package/client/index.html +273 -15
- package/client/styles/components.css +14 -0
- package/docs/prod-android.md +55 -69
- package/docs/rmf-tiny.md +156 -0
- package/package.json +7 -1
- package/packages/mailx-store-web/package.json +1 -1
package/client/index.html
CHANGED
|
@@ -56,23 +56,279 @@
|
|
|
56
56
|
include because nothing else imports those specifiers on the
|
|
57
57
|
desktop side. Single HTML for both shells; CSS handles narrow vs
|
|
58
58
|
wide layout, runtime detect handles bootstrap, no html fork. -->
|
|
59
|
+
<!-- TODO: regenerate via importgen once it scans dynamic `await import()`
|
|
60
|
+
calls (currently it only follows static imports, so it drops every
|
|
61
|
+
@bobfrankston/* entry our index.html and editor.ts dynamic-import).
|
|
62
|
+
Until then this map is hand-restored (entries from prior importgen run
|
|
63
|
+
+ the @bobfrankston ones it missed). See programming.md for the rule. -->
|
|
64
|
+
<!-- Generated by importgen 0.1.35 on May 10, 2026, 1:26:13 AM EDT -->
|
|
59
65
|
<script type="importmap">
|
|
60
66
|
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
"imports": {
|
|
68
|
+
"@bobfrankston/iflow-direct": "../node_modules/@bobfrankston/iflow-direct/index.js",
|
|
69
|
+
"@bobfrankston/tcp-transport": "../node_modules/@bobfrankston/tcp-transport/index.js",
|
|
70
|
+
"@bobfrankston/mailx-host": "../node_modules/@bobfrankston/mailx-host/index.js",
|
|
71
|
+
"@bobfrankston/msger": "../node_modules/@bobfrankston/msger/index.js",
|
|
72
|
+
"@bobfrankston/msgcommon": "../node_modules/@bobfrankston/msger/node_modules/@bobfrankston/msgcommon/index.js",
|
|
73
|
+
"json5": "../node_modules/@bobfrankston/msger/node_modules/@bobfrankston/msgcommon/node_modules/json5/dist/index.mjs",
|
|
74
|
+
"marked": "../node_modules/@bobfrankston/msger/node_modules/@bobfrankston/msgcommon/node_modules/marked/lib/marked.esm.js",
|
|
75
|
+
"windows-shortcuts": "../node_modules/@bobfrankston/msger/node_modules/@bobfrankston/msgcommon/node_modules/windows-shortcuts/lib/windows-shortcuts",
|
|
76
|
+
"@bobfrankston/rust-builder": "../node_modules/@bobfrankston/msger/node_modules/@bobfrankston/rust-builder/index.js",
|
|
77
|
+
"ansi-to-html": "../node_modules/@bobfrankston/msger/node_modules/ansi-to-html/lib/ansi_to_html.js",
|
|
78
|
+
"entities": "../node_modules/entities/lib/index.js",
|
|
79
|
+
"@bobfrankston/mailx-imap": "../node_modules/@bobfrankston/mailx-imap/index.js",
|
|
80
|
+
"@bobfrankston/mailx-types": "../node_modules/@bobfrankston/mailx-types/index.js",
|
|
81
|
+
"@bobfrankston/mailx-settings": "../node_modules/@bobfrankston/mailx-settings/index.js",
|
|
82
|
+
"jsonc-parser": "../node_modules/jsonc-parser/lib/esm/main.js",
|
|
83
|
+
"@bobfrankston/mailx-store": "../node_modules/@bobfrankston/mailx-store/index.js",
|
|
84
|
+
"@bobfrankston/smtp-direct": "../node_modules/@bobfrankston/smtp-direct/index.js",
|
|
85
|
+
"@bobfrankston/mailx-sync": "../node_modules/@bobfrankston/mailx-sync/index.js",
|
|
86
|
+
"@bobfrankston/oauthsupport": "../node_modules/@bobfrankston/oauthsupport/index.js",
|
|
87
|
+
"@bobfrankston/mailx-store-web": "../node_modules/@bobfrankston/mailx-store-web/index.js",
|
|
88
|
+
"sql.js": "../node_modules/sql.js/dist/sql-wasm-browser.js",
|
|
89
|
+
"@bobfrankston/miscinfo": "../node_modules/@bobfrankston/miscinfo/index.js",
|
|
90
|
+
"@bobfrankston/node-tcp-transport": "../node_modules/@bobfrankston/node-tcp-transport/index.js",
|
|
91
|
+
"@bobfrankston/rmf-tiny": "../node_modules/@bobfrankston/rmf-tiny/src/adapter.js",
|
|
92
|
+
"@capacitor/android": "../node_modules/@capacitor/android/index.js",
|
|
93
|
+
"@capacitor/cli": "../node_modules/@capacitor/cli/dist/index.js",
|
|
94
|
+
"@ionic/cli-framework-output": "../node_modules/@ionic/cli-framework-output/dist/index.js",
|
|
95
|
+
"@ionic/utils-terminal": "../node_modules/@ionic/utils-terminal/dist/index.js",
|
|
96
|
+
"@types/slice-ansi": "../node_modules/@types/slice-ansi/",
|
|
97
|
+
"debug": "../node_modules/debug/src/index.js",
|
|
98
|
+
"ms": "../node_modules/ms/index",
|
|
99
|
+
"signal-exit": "../node_modules/signal-exit/index.js",
|
|
100
|
+
"slice-ansi": "../node_modules/slice-ansi/index.js",
|
|
101
|
+
"ansi-styles": "../node_modules/ansi-styles/index.js",
|
|
102
|
+
"color-convert": "../node_modules/color-convert/index.js",
|
|
103
|
+
"color-name": "../node_modules/color-name/index.js",
|
|
104
|
+
"astral-regex": "../node_modules/astral-regex/index.js",
|
|
105
|
+
"is-fullwidth-code-point": "../node_modules/is-fullwidth-code-point/index.js",
|
|
106
|
+
"string-width": "../node_modules/string-width/index.js",
|
|
107
|
+
"emoji-regex": "../node_modules/emoji-regex/index.js",
|
|
108
|
+
"strip-ansi": "../node_modules/strip-ansi/index.js",
|
|
109
|
+
"ansi-regex": "../node_modules/ansi-regex/index.js",
|
|
110
|
+
"tslib": "../node_modules/tslib/tslib.es6.mjs",
|
|
111
|
+
"untildify": "../node_modules/untildify/index.js",
|
|
112
|
+
"wrap-ansi": "../node_modules/wrap-ansi/index.js",
|
|
113
|
+
"@ionic/utils-subprocess": "../node_modules/@ionic/utils-subprocess/dist/index.js",
|
|
114
|
+
"@ionic/utils-array": "../node_modules/@ionic/utils-array/dist/index.js",
|
|
115
|
+
"@ionic/utils-fs": "../node_modules/@ionic/utils-fs/dist/index.js",
|
|
116
|
+
"@types/fs-extra": "../node_modules/@types/fs-extra/",
|
|
117
|
+
"@types/node": "../node_modules/@types/node/",
|
|
118
|
+
"undici-types": "../node_modules/undici-types/index.js",
|
|
119
|
+
"fs-extra": "../node_modules/fs-extra/lib/index.js",
|
|
120
|
+
"at-least-node": "../node_modules/at-least-node/index.js",
|
|
121
|
+
"graceful-fs": "../node_modules/graceful-fs/graceful-fs.js",
|
|
122
|
+
"jsonfile": "../node_modules/jsonfile/index.js",
|
|
123
|
+
"universalify": "../node_modules/universalify/index.js",
|
|
124
|
+
"@ionic/utils-process": "../node_modules/@ionic/utils-process/dist/index.js",
|
|
125
|
+
"@ionic/utils-object": "../node_modules/@ionic/utils-object/dist/index.js",
|
|
126
|
+
"tree-kill": "../node_modules/tree-kill/index.js",
|
|
127
|
+
"@ionic/utils-stream": "../node_modules/@ionic/utils-stream/dist/index.js",
|
|
128
|
+
"cross-spawn": "../node_modules/cross-spawn/index.js",
|
|
129
|
+
"path-key": "../node_modules/path-key/index.js",
|
|
130
|
+
"shebang-command": "../node_modules/shebang-command/index.js",
|
|
131
|
+
"shebang-regex": "../node_modules/shebang-regex/index.js",
|
|
132
|
+
"which": "../node_modules/which/which.js",
|
|
133
|
+
"isexe": "../node_modules/isexe/index.js",
|
|
134
|
+
"commander": "../node_modules/commander/esm.mjs",
|
|
135
|
+
"env-paths": "../node_modules/env-paths/index.js",
|
|
136
|
+
"kleur": "../node_modules/kleur/index.mjs",
|
|
137
|
+
"native-run": "../node_modules/native-run/dist/index.js",
|
|
138
|
+
"bplist-parser": "../node_modules/bplist-parser/bplistParser.js",
|
|
139
|
+
"big-integer": "../node_modules/big-integer/BigInteger",
|
|
140
|
+
"elementtree": "../node_modules/elementtree/lib/elementtree.js",
|
|
141
|
+
"sax": "../node_modules/sax/lib/sax.js",
|
|
142
|
+
"ini": "../node_modules/ini/lib/ini.js",
|
|
143
|
+
"plist": "../node_modules/plist/index.js",
|
|
144
|
+
"@xmldom/xmldom": "../node_modules/@xmldom/xmldom/lib/index.js",
|
|
145
|
+
"base64-js": "../node_modules/base64-js/index.js",
|
|
146
|
+
"xmlbuilder": "../node_modules/xmlbuilder/lib/index",
|
|
147
|
+
"split2": "../node_modules/split2/index.js",
|
|
148
|
+
"through2": "../node_modules/through2/through2.js",
|
|
149
|
+
"readable-stream": "../node_modules/readable-stream/readable.js",
|
|
150
|
+
"inherits": "../node_modules/inherits/inherits.js",
|
|
151
|
+
"string_decoder": "../node_modules/string_decoder/lib/string_decoder.js",
|
|
152
|
+
"safe-buffer": "../node_modules/safe-buffer/index.js",
|
|
153
|
+
"util-deprecate": "../node_modules/util-deprecate/node.js",
|
|
154
|
+
"yauzl": "../node_modules/yauzl/index.js",
|
|
155
|
+
"fd-slicer": "../node_modules/fd-slicer/index.js",
|
|
156
|
+
"pend": "../node_modules/pend/index.js",
|
|
157
|
+
"buffer-crc32": "../node_modules/buffer-crc32/index.js",
|
|
158
|
+
"open": "../node_modules/open/index.js",
|
|
159
|
+
"define-lazy-prop": "../node_modules/define-lazy-prop/index.js",
|
|
160
|
+
"is-docker": "../node_modules/is-docker/index.js",
|
|
161
|
+
"is-wsl": "../node_modules/is-wsl/index.js",
|
|
162
|
+
"prompts": "../node_modules/prompts/index.js",
|
|
163
|
+
"sisteransi": "../node_modules/sisteransi/src/index.js",
|
|
164
|
+
"rimraf": "../node_modules/rimraf/dist/esm/index.js",
|
|
165
|
+
"glob": "../node_modules/glob/dist/esm/index.min.js",
|
|
166
|
+
"minimatch": "../node_modules/minimatch/dist/esm/index.js",
|
|
167
|
+
"brace-expansion": "../node_modules/brace-expansion/dist/esm/index.js",
|
|
168
|
+
"balanced-match": "../node_modules/balanced-match/dist/esm/index.js",
|
|
169
|
+
"minipass": "../node_modules/minipass/dist/esm/index.js",
|
|
170
|
+
"path-scurry": "../node_modules/path-scurry/dist/esm/index.js",
|
|
171
|
+
"lru-cache": "../node_modules/lru-cache/dist/esm/browser/index.min.js",
|
|
172
|
+
"package-json-from-dist": "../node_modules/package-json-from-dist/dist/esm/index.js",
|
|
173
|
+
"semver": "../node_modules/semver/index.js",
|
|
174
|
+
"tar": "../node_modules/tar/dist/esm/index.min.js",
|
|
175
|
+
"@isaacs/fs-minipass": "../node_modules/@isaacs/fs-minipass/dist/esm/index.js",
|
|
176
|
+
"chownr": "../node_modules/chownr/dist/esm/index.js",
|
|
177
|
+
"minizlib": "../node_modules/minizlib/dist/esm/index.js",
|
|
178
|
+
"yallist": "../node_modules/yallist/dist/esm/index.js",
|
|
179
|
+
"xml2js": "../node_modules/xml2js/lib/xml2js",
|
|
180
|
+
"@capacitor/core": "../node_modules/@capacitor/core/dist/index.js",
|
|
181
|
+
"express": "../node_modules/express/index.js",
|
|
182
|
+
"accepts": "../node_modules/accepts/index.js",
|
|
183
|
+
"mime-types": "../node_modules/mime-types/index.js",
|
|
184
|
+
"mime-db": "../node_modules/mime-db/index.js",
|
|
185
|
+
"negotiator": "../node_modules/negotiator/index.js",
|
|
186
|
+
"array-flatten": "../node_modules/array-flatten/array-flatten.js",
|
|
187
|
+
"body-parser": "../node_modules/body-parser/index.js",
|
|
188
|
+
"bytes": "../node_modules/bytes/index.js",
|
|
189
|
+
"content-type": "../node_modules/content-type/index.js",
|
|
190
|
+
"depd": "../node_modules/depd/index.js",
|
|
191
|
+
"destroy": "../node_modules/destroy/index.js",
|
|
192
|
+
"http-errors": "../node_modules/http-errors/index.js",
|
|
193
|
+
"setprototypeof": "../node_modules/setprototypeof/index.js",
|
|
194
|
+
"statuses": "../node_modules/statuses/index.js",
|
|
195
|
+
"toidentifier": "../node_modules/toidentifier/index.js",
|
|
196
|
+
"iconv-lite": "../node_modules/iconv-lite/lib/index.js",
|
|
197
|
+
"safer-buffer": "../node_modules/safer-buffer/safer.js",
|
|
198
|
+
"on-finished": "../node_modules/on-finished/index.js",
|
|
199
|
+
"ee-first": "../node_modules/ee-first/index.js",
|
|
200
|
+
"qs": "../node_modules/qs/lib/index.js",
|
|
201
|
+
"side-channel": "../node_modules/side-channel/index.js",
|
|
202
|
+
"es-errors": "../node_modules/es-errors/index.js",
|
|
203
|
+
"object-inspect": "../node_modules/object-inspect/index.js",
|
|
204
|
+
"side-channel-list": "../node_modules/side-channel-list/index.js",
|
|
205
|
+
"side-channel-map": "../node_modules/side-channel-map/index.js",
|
|
206
|
+
"call-bound": "../node_modules/call-bound/index.js",
|
|
207
|
+
"call-bind-apply-helpers": "../node_modules/call-bind-apply-helpers/index.js",
|
|
208
|
+
"function-bind": "../node_modules/function-bind/index",
|
|
209
|
+
"get-intrinsic": "../node_modules/get-intrinsic/index.js",
|
|
210
|
+
"es-define-property": "../node_modules/es-define-property/index.js",
|
|
211
|
+
"es-object-atoms": "../node_modules/es-object-atoms/index.js",
|
|
212
|
+
"get-proto": "../node_modules/get-proto/index.js",
|
|
213
|
+
"dunder-proto": "../node_modules/dunder-proto/get.js",
|
|
214
|
+
"gopd": "../node_modules/gopd/index.js",
|
|
215
|
+
"has-symbols": "../node_modules/has-symbols/index.js",
|
|
216
|
+
"hasown": "../node_modules/hasown/index.js",
|
|
217
|
+
"math-intrinsics": "../node_modules/math-intrinsics/abs.js",
|
|
218
|
+
"side-channel-weakmap": "../node_modules/side-channel-weakmap/index.js",
|
|
219
|
+
"raw-body": "../node_modules/raw-body/index.js",
|
|
220
|
+
"unpipe": "../node_modules/unpipe/index.js",
|
|
221
|
+
"type-is": "../node_modules/type-is/index.js",
|
|
222
|
+
"media-typer": "../node_modules/media-typer/index.js",
|
|
223
|
+
"content-disposition": "../node_modules/content-disposition/index.js",
|
|
224
|
+
"cookie": "../node_modules/cookie/index.js",
|
|
225
|
+
"cookie-signature": "../node_modules/cookie-signature/index",
|
|
226
|
+
"encodeurl": "../node_modules/encodeurl/index.js",
|
|
227
|
+
"escape-html": "../node_modules/escape-html/index.js",
|
|
228
|
+
"etag": "../node_modules/etag/index.js",
|
|
229
|
+
"finalhandler": "../node_modules/finalhandler/index.js",
|
|
230
|
+
"parseurl": "../node_modules/parseurl/index.js",
|
|
231
|
+
"fresh": "../node_modules/fresh/index.js",
|
|
232
|
+
"merge-descriptors": "../node_modules/merge-descriptors/index.js",
|
|
233
|
+
"methods": "../node_modules/methods/index.js",
|
|
234
|
+
"path-to-regexp": "../node_modules/path-to-regexp/index.js",
|
|
235
|
+
"proxy-addr": "../node_modules/proxy-addr/index.js",
|
|
236
|
+
"forwarded": "../node_modules/forwarded/index.js",
|
|
237
|
+
"ipaddr.js": "../node_modules/ipaddr.js/lib/ipaddr.js",
|
|
238
|
+
"range-parser": "../node_modules/range-parser/index.js",
|
|
239
|
+
"send": "../node_modules/send/index.js",
|
|
240
|
+
"mime": "../node_modules/mime/mime.js",
|
|
241
|
+
"serve-static": "../node_modules/serve-static/index.js",
|
|
242
|
+
"utils-merge": "../node_modules/utils-merge/index",
|
|
243
|
+
"vary": "../node_modules/vary/index.js",
|
|
244
|
+
"html-to-docx": "../node_modules/html-to-docx/dist/html-to-docx.esm.js",
|
|
245
|
+
"@oozcitak/util": "../node_modules/@oozcitak/util/lib/index",
|
|
246
|
+
"@oozcitak/dom": "../node_modules/@oozcitak/dom/lib/index",
|
|
247
|
+
"@oozcitak/infra": "../node_modules/@oozcitak/infra/lib/index",
|
|
248
|
+
"@oozcitak/url": "../node_modules/@oozcitak/url/lib/index",
|
|
249
|
+
"html-entities": "../node_modules/html-entities/dist/esm/index.js",
|
|
250
|
+
"html-to-vdom": "../node_modules/html-to-vdom/index.js",
|
|
251
|
+
"ent": "../node_modules/ent/index.js",
|
|
252
|
+
"punycode": "../node_modules/punycode/punycode.js",
|
|
253
|
+
"safe-regex-test": "../node_modules/safe-regex-test/index.js",
|
|
254
|
+
"is-regex": "../node_modules/is-regex/index.js",
|
|
255
|
+
"has-tostringtag": "../node_modules/has-tostringtag/index.js",
|
|
256
|
+
"htmlparser2": "../node_modules/htmlparser2/lib/index.js",
|
|
257
|
+
"domelementtype": "../node_modules/domelementtype/index.js",
|
|
258
|
+
"domhandler": "../node_modules/domhandler/index.js",
|
|
259
|
+
"domutils": "../node_modules/domutils/index.js",
|
|
260
|
+
"dom-serializer": "../node_modules/dom-serializer/index.js",
|
|
261
|
+
"image-size": "../node_modules/image-size/dist/index.js",
|
|
262
|
+
"queue": "../node_modules/queue/index.js",
|
|
263
|
+
"image-to-base64": "../node_modules/image-to-base64/image-to-base64.min.js",
|
|
264
|
+
"node-fetch": "../node_modules/node-fetch/lib/index.mjs",
|
|
265
|
+
"whatwg-url": "../node_modules/whatwg-url/lib/public-api.js",
|
|
266
|
+
"tr46": "../node_modules/tr46/index.js",
|
|
267
|
+
"webidl-conversions": "../node_modules/webidl-conversions/lib/index.js",
|
|
268
|
+
"jszip": "../node_modules/jszip/lib/index",
|
|
269
|
+
"lie": "../node_modules/lie/lib/index.js",
|
|
270
|
+
"immediate": "../node_modules/immediate/lib/index.js",
|
|
271
|
+
"pako": "../node_modules/pako/index.js",
|
|
272
|
+
"setimmediate": "../node_modules/setimmediate/setImmediate.js",
|
|
273
|
+
"lodash": "../node_modules/lodash/lodash.js",
|
|
274
|
+
"nanoid": "../node_modules/nanoid/index.js",
|
|
275
|
+
"virtual-dom": "../node_modules/virtual-dom/index",
|
|
276
|
+
"browser-split": "../node_modules/browser-split/index.js",
|
|
277
|
+
"error": "../node_modules/error/index",
|
|
278
|
+
"camelize": "../node_modules/camelize/index.js",
|
|
279
|
+
"string-template": "../node_modules/string-template/index",
|
|
280
|
+
"xtend": "../node_modules/xtend/immutable",
|
|
281
|
+
"ev-store": "../node_modules/ev-store/index",
|
|
282
|
+
"individual": "../node_modules/individual/index",
|
|
283
|
+
"global": "../node_modules/global/window.js",
|
|
284
|
+
"min-document": "../node_modules/min-document/index.js",
|
|
285
|
+
"dom-walk": "../node_modules/dom-walk/index",
|
|
286
|
+
"process": "../node_modules/process/index.js",
|
|
287
|
+
"is-object": "../node_modules/is-object/index",
|
|
288
|
+
"next-tick": "../node_modules/next-tick/index.js",
|
|
289
|
+
"x-is-array": "../node_modules/x-is-array/index",
|
|
290
|
+
"x-is-string": "../node_modules/x-is-string/index",
|
|
291
|
+
"xmlbuilder2": "../node_modules/xmlbuilder2/lib/index",
|
|
292
|
+
"mailparser": "../node_modules/mailparser/index.js",
|
|
293
|
+
"encoding-japanese": "../node_modules/encoding-japanese/src/index.js",
|
|
294
|
+
"he": "../node_modules/he/he.js",
|
|
295
|
+
"html-to-text": "../node_modules/html-to-text/lib/html-to-text.mjs",
|
|
296
|
+
"@selderee/plugin-htmlparser2": "../node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs",
|
|
297
|
+
"selderee": "../node_modules/selderee/lib/selderee.mjs",
|
|
298
|
+
"parseley": "../node_modules/parseley/lib/parseley.mjs",
|
|
299
|
+
"leac": "../node_modules/leac/lib/leac.mjs",
|
|
300
|
+
"peberminta": "../node_modules/peberminta/lib/core.mjs",
|
|
301
|
+
"deepmerge": "../node_modules/deepmerge/dist/cjs.js",
|
|
302
|
+
"libmime": "../node_modules/libmime/lib/libmime.js",
|
|
303
|
+
"libbase64": "../node_modules/libbase64/lib/libbase64.js",
|
|
304
|
+
"libqp": "../node_modules/libqp/lib/libqp.js",
|
|
305
|
+
"linkify-it": "../node_modules/linkify-it/index.mjs",
|
|
306
|
+
"uc.micro": "../node_modules/uc.micro/index.mjs",
|
|
307
|
+
"@zone-eu/mailsplit": "../node_modules/@zone-eu/mailsplit/index.js",
|
|
308
|
+
"nodemailer": "../node_modules/nodemailer/lib/nodemailer.js",
|
|
309
|
+
"punycode.js": "../node_modules/punycode.js/punycode.es6.js",
|
|
310
|
+
"tlds": "../node_modules/tlds/index.json",
|
|
311
|
+
"mammoth": "../node_modules/mammoth/lib/index.js",
|
|
312
|
+
"argparse": "../node_modules/argparse/index.js",
|
|
313
|
+
"sprintf-js": "../node_modules/sprintf-js/src/sprintf.js",
|
|
314
|
+
"bluebird": "../node_modules/bluebird/js/release/bluebird.js",
|
|
315
|
+
"dingbat-to-unicode": "../node_modules/dingbat-to-unicode/dist/index.js",
|
|
316
|
+
"lop": "../node_modules/lop/index.js",
|
|
317
|
+
"duck": "../node_modules/duck/index.js",
|
|
318
|
+
"underscore": "../node_modules/underscore/underscore-esm.js",
|
|
319
|
+
"option": "../node_modules/option/index.js",
|
|
320
|
+
"path-is-absolute": "../node_modules/path-is-absolute/index.js",
|
|
321
|
+
"quill": "../node_modules/quill/quill.js",
|
|
322
|
+
"eventemitter3": "../node_modules/eventemitter3/index.mjs",
|
|
323
|
+
"lodash-es": "../node_modules/lodash-es/lodash.js",
|
|
324
|
+
"parchment": "../node_modules/parchment/dist/parchment.js",
|
|
325
|
+
"quill-delta": "../node_modules/quill-delta/dist/Delta.js",
|
|
326
|
+
"fast-diff": "../node_modules/fast-diff/diff.js",
|
|
327
|
+
"lodash.clonedeep": "../node_modules/lodash.clonedeep/index.js",
|
|
328
|
+
"lodash.isequal": "../node_modules/lodash.isequal/index.js",
|
|
329
|
+
"ws": "../node_modules/ws/wrapper.mjs"
|
|
330
|
+
}
|
|
331
|
+
}
|
|
76
332
|
</script>
|
|
77
333
|
<!-- Early error handlers — ship problems to logit when running in
|
|
78
334
|
a context that can reach the network (Android shell). msger
|
|
@@ -169,6 +425,8 @@
|
|
|
169
425
|
<span class="tb-menu-label">Editor</span>
|
|
170
426
|
<label class="tb-menu-item"><input type="radio" name="opt-editor" value="quill" id="opt-editor-quill" checked> Quill</label>
|
|
171
427
|
<label class="tb-menu-item"><input type="radio" name="opt-editor" value="tiptap" id="opt-editor-tiptap"> tiptap</label>
|
|
428
|
+
<label class="tb-menu-item" title="Best Word-paste fidelity. TinyMCE itself is fetched at runtime from the CDN URL below."><input type="radio" name="opt-editor" value="tinymce" id="opt-editor-tinymce"> TinyMCE</label>
|
|
429
|
+
<label class="tb-menu-item tb-menu-subitem" title="TinyMCE CDN URL. Default (jsDelivr) needs no API key. Override for Tiny Cloud or self-hosted."><input type="text" id="opt-tinymce-cdn" placeholder="https://cdn.jsdelivr.net/npm/tinymce@6/tinymce.min.js" style="width:90%;font-size:0.85em"></label>
|
|
172
430
|
<hr class="tb-menu-sep">
|
|
173
431
|
<span class="tb-menu-label" title="Which app the compose 'Edit in Word' button hands the body off to. Auto = Word first, then LibreOffice, then OS default.">External editor</span>
|
|
174
432
|
<label class="tb-menu-item"><input type="radio" name="opt-extedit" value="auto" id="opt-extedit-auto" checked> Auto (Word → LibreOffice → default)</label>
|
|
@@ -2186,3 +2186,17 @@ body.calendar-sidebar-on .calendar-sidebar { display: flex; }
|
|
|
2186
2186
|
transition: transform 200ms ease-out;
|
|
2187
2187
|
}
|
|
2188
2188
|
.ml-body { position: relative; overflow-anchor: none; }
|
|
2189
|
+
|
|
2190
|
+
/* Quill snow theme zeros out paragraph margins, so a Word paste with
|
|
2191
|
+
distinct paragraphs LOOKS like line breaks while composing — even
|
|
2192
|
+
though q.root.innerHTML has proper <p> tags and the recipient
|
|
2193
|
+
renders them with their own UA defaults. Restore visual spacing in
|
|
2194
|
+
the editor body so the sender sees the paragraphs they pasted.
|
|
2195
|
+
:first-child / :last-child trim the outer margin so the editor
|
|
2196
|
+
doesn't get phantom whitespace at the boundaries. */
|
|
2197
|
+
.ql-editor p {
|
|
2198
|
+
margin: 0 0 0.6em 0;
|
|
2199
|
+
}
|
|
2200
|
+
.ql-editor p:last-child {
|
|
2201
|
+
margin-bottom: 0;
|
|
2202
|
+
}
|
package/docs/prod-android.md
CHANGED
|
@@ -1,102 +1,88 @@
|
|
|
1
1
|
# prod / dev release workflow — Android (MAUI APK)
|
|
2
2
|
|
|
3
|
-
Status: design only.
|
|
3
|
+
Status: design only. Same intent as `prod.md` (npm side); the APK is a complete, self-contained binary so the unit of promotion is a *file*, not a dependency or dist-tag.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Simpler approach (Bob 2026-05-09)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
No separate MAUI project. Same source tree produces both flavors; the difference is purely in the OUTPUT filename, and "what's currently prod" is decided by which file lives at the canonical prod URL.
|
|
8
8
|
|
|
9
|
-
Today
|
|
9
|
+
### Today
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
```
|
|
11
|
+
- One build target: `mailx-maui.apk` at `https://rmf39.aaz.lt/mailx/mailx-maui.apk`.
|
|
12
|
+
- `versions.json` carries the version string; updater compares to running.
|
|
13
|
+
- Every build overwrites the single APK. No history, no channels.
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
### Phase 1 — start producing dev.apk too
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
While there's no formal "production release" yet, every build produces:
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
- `rmfmaildev.apk` (or `dev.apk`) — the just-built, latest dev tip. Updater on dev devices points here.
|
|
20
|
+
- `mailx-maui.apk` — unchanged for now (current production behavior). Updater on prod devices points here.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
The build script writes both. Same APK contents initially — the dual output is just renamed copies. Devices on different channels read different filenames.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
### Phase 2 — once a release is declared
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
https://rmf39.aaz.lt/mailx/dev/manifest.json
|
|
28
|
-
https://rmf39.aaz.lt/mailx/dev/mailx-maui-1.0.NNN.apk
|
|
29
|
-
https://rmf39.aaz.lt/mailx/prod/manifest.json
|
|
30
|
-
https://rmf39.aaz.lt/mailx/prod/mailx-maui-1.0.MMM.apk
|
|
31
|
-
```
|
|
26
|
+
Build outputs:
|
|
32
27
|
|
|
33
|
-
`
|
|
28
|
+
- `rmfmaildev.apk` — every build. Always the freshest.
|
|
29
|
+
- `rmfmail-<version>.apk` — versioned filename, never overwritten. One file per build.
|
|
34
30
|
|
|
35
|
-
|
|
36
|
-
{ "version": "1.0.NNN", "apk": "mailx-maui-1.0.NNN.apk", "released": "2026-05-09T17:00:00Z", "minDesktop": "1.0.500" }
|
|
37
|
-
```
|
|
31
|
+
"Promoting" a known-good dev build to production = `cp rmfmail-1.0.NNN.apk rmfmail.apk` (or web-server-side: update a redirect / symlink / manifest pointer at `rmfmail.apk` to name the chosen versioned file).
|
|
38
32
|
|
|
39
|
-
The
|
|
33
|
+
The canonical URLs:
|
|
40
34
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- Read version from `package.json` (already does).
|
|
48
|
-
- Build APK, copy to `download/apks/mailx-maui-<version>.apk` (versioned filename, never overwritten).
|
|
49
|
-
- Update local `download/dev/manifest.json` to point at the new APK.
|
|
50
|
-
- Sync `download/dev/` to the rmf39.aaz.lt webroot.
|
|
51
|
-
|
|
52
|
-
The dev channel always tracks the most recent build.
|
|
53
|
-
|
|
54
|
-
### 2. `prod-android.cmd` — promote dev → prod
|
|
55
|
-
|
|
56
|
-
Mirror of `prod.cmd`. Reads `download/dev/manifest.json`, copies it to `download/prod/manifest.json`, syncs prod/ to webroot. No new APK file uploaded — the prod-channel manifest now points at the same APK that's already in `dev/` (or copy it under `prod/` for symmetry; cheap).
|
|
35
|
+
```
|
|
36
|
+
https://rmf39.aaz.lt/mailx/rmfmail.apk ← prod pointer (chosen versioned APK)
|
|
37
|
+
https://rmf39.aaz.lt/mailx/rmfmaildev.apk ← latest dev build
|
|
38
|
+
https://rmf39.aaz.lt/mailx/rmfmail-1.0.NNN.apk ← every released version, immutable
|
|
39
|
+
```
|
|
57
40
|
|
|
58
|
-
|
|
41
|
+
Roll back = re-point `rmfmail.apk` to a prior versioned APK.
|
|
59
42
|
|
|
60
|
-
|
|
43
|
+
## What changes from the current build
|
|
61
44
|
|
|
62
|
-
|
|
45
|
+
`build-apk.cmd` / `build-apk.ts`:
|
|
63
46
|
|
|
64
|
-
-
|
|
65
|
-
-
|
|
47
|
+
- Read version from `package.json` (already does).
|
|
48
|
+
- Build APK once.
|
|
49
|
+
- Phase 1: write to `rmfmaildev.apk` AND `mailx-maui.apk` (mirror).
|
|
50
|
+
- Phase 2: write to `rmfmail-<version>.apk` (versioned, never overwritten) AND `rmfmaildev.apk` (latest dev mirror).
|
|
51
|
+
- Sync to web root.
|
|
66
52
|
|
|
67
|
-
|
|
53
|
+
Promotion script (`prod-android.ps1`?) — Phase 2 only:
|
|
68
54
|
|
|
69
|
-
|
|
55
|
+
- Take a version arg (or default to current dev build).
|
|
56
|
+
- Copy / point `rmfmail.apk` at that version's APK.
|
|
57
|
+
- Update `versions.json` so the updater on prod devices sees a newer version available.
|
|
70
58
|
|
|
71
|
-
|
|
59
|
+
`AppUpdater.cs` — channel awareness:
|
|
72
60
|
|
|
73
|
-
|
|
61
|
+
- Reads from configurable URL based on channel setting.
|
|
62
|
+
- Default: prod URL (`rmfmail.apk` / corresponding `versions.json`).
|
|
63
|
+
- Dev mode: dev URL.
|
|
64
|
+
- Channel toggle in Settings (or build-time constant in a separate flavor — but per Bob's preference, NO separate MAUI project; channel is a runtime setting).
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
2. Daily testing on the dev phone/tablet.
|
|
77
|
-
3. `prod-android.cmd` — copies the current dev manifest to prod. Devices on prod-channel pick up the new build on next poll.
|
|
78
|
-
4. Rolling back prod: re-run `prod-android.cmd <specific-version>` (need a version arg to override "current dev").
|
|
66
|
+
## What this does NOT need
|
|
79
67
|
|
|
80
|
-
|
|
68
|
+
- **No separate MAUI project**. The APK is the same binary regardless of which channel it serves; users with the dev URL configured get latest builds, users with the prod URL get whatever was last promoted. Source tree is single.
|
|
69
|
+
- **No dist-tag analog**. The "tag" is just the filename / URL the updater polls.
|
|
70
|
+
- **No flavor build**. Same package id, same signing key, same APK bytes — just two distribution endpoints (or, with Phase 2, two distinct files referenced from the manifests).
|
|
81
71
|
|
|
82
|
-
|
|
83
|
-
- **Force-update / minimum-version** — manifest already supports a `minDesktop` field; an Android equivalent (`minSupported`: refuse to run older client) can refuse to run a stale APK after a breaking server change. Not needed today; cheap to add later.
|
|
84
|
-
- **APK signing** — same key for dev and prod, otherwise users can't upgrade between them without uninstall. (Different package id flavor build IS a separate app and can have a separate key — but that's the coexistence model anyway.)
|
|
85
|
-
- **`download/apks/mailx-maui.apk` (current single filename)** — keep as-is for back-compat until devices move off it; or symlink it to the current prod APK.
|
|
72
|
+
## Coexistence on a single device
|
|
86
73
|
|
|
87
|
-
|
|
74
|
+
Single MAUI project means a single Android package id. Two builds CAN'T be installed side-by-side without diverging package ids (Android refuses). If side-by-side becomes a real need later, reintroduce the separate-MAUI-project idea — but that's the orthogonal "I want both versions on the same phone" design, not the prod/dev release flow.
|
|
88
75
|
|
|
89
|
-
|
|
90
|
-
- `prod-android.cmd` — manifest copy + sync. ~10 lines.
|
|
91
|
-
- `AppUpdater.cs` channel awareness + Settings toggle UI — ~50 lines including the storage pref.
|
|
92
|
-
- Webroot layout setup on rmf39.aaz.lt — one-time directory creation.
|
|
93
|
-
- Test cycle: build dev, verify prod APK on phone unchanged. Promote, verify next poll picks up new prod APK.
|
|
76
|
+
## Order
|
|
94
77
|
|
|
95
|
-
|
|
78
|
+
1. **Phase 1 first**: build script outputs `rmfmaildev.apk` alongside today's `mailx-maui.apk`. Zero behavior change for prod users; dev users (on the dev channel) get latest. ~10 lines in `build-apk.ts`.
|
|
79
|
+
2. **AppUpdater channel toggle**: Settings checkbox + persisted preference + URL switch. ~50 lines.
|
|
80
|
+
3. **Phase 2 when ready**: switch to versioned filenames + `rmfmail.apk` pointer + promotion script. Done when there's a real first "production release" to designate.
|
|
96
81
|
|
|
97
|
-
##
|
|
82
|
+
## Effort
|
|
98
83
|
|
|
99
|
-
|
|
100
|
-
|
|
84
|
+
- Phase 1: ~30 minutes (build script + manifest output).
|
|
85
|
+
- AppUpdater channel: ~1 hour (Settings UI + storage + URL plumbing).
|
|
86
|
+
- Phase 2: ~1 hour when activated (promotion script + versioned filenames + pointer mechanism on web root).
|
|
101
87
|
|
|
102
|
-
|
|
88
|
+
Total ~2.5 hours wall-clock when fully wired. Phase 1 alone gets you the "always-have-a-fresh-dev-build" benefit without any commitment to the formal release flow.
|