@bobfrankston/rmfmail 1.2.202 → 1.2.204

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.
@@ -24,6 +24,7 @@ using Windows.ApplicationModel;
24
24
  using Windows.ApplicationModel.Activation;
25
25
  using Windows.ApplicationModel.DataTransfer;
26
26
  using Windows.ApplicationModel.DataTransfer.ShareTarget;
27
+ using WinRT; // CastExtensions.As<T> — AOT-safe WinRT QueryInterface
27
28
  using Windows.Storage;
28
29
 
29
30
  internal static class Program
@@ -37,21 +38,57 @@ internal static class Program
37
38
  private static string RmfmailDir =>
38
39
  Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".rmfmail");
39
40
 
41
+ /// Trace log (~/.rmfmail/logs/rmfshare.log). The first field failure
42
+ /// (Bob 2026-07-30: share restarted the app, no pending file, no error
43
+ /// box) was undiagnosable because this exe wrote nothing anywhere —
44
+ /// every activation now leaves a breadcrumb trail. Append-only, best
45
+ /// effort, never throws.
46
+ private static void Log(string msg)
47
+ {
48
+ try
49
+ {
50
+ var dir = Path.Combine(RmfmailDir, "logs");
51
+ Directory.CreateDirectory(dir);
52
+ File.AppendAllText(Path.Combine(dir, "rmfshare.log"),
53
+ $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {msg}\r\n");
54
+ }
55
+ catch { /* logging must never break the share */ }
56
+ }
57
+
40
58
  [STAThread]
41
59
  private static int Main()
42
60
  {
43
61
  try
44
62
  {
45
63
  IActivatedEventArgs? activation = null;
64
+ string activationError = "";
46
65
  try { activation = AppInstance.GetActivatedEventArgs(); }
47
- catch { /* unpackaged launch (double-click outside the manifest) */ }
66
+ catch (Exception ex) { activationError = ex.Message; }
67
+ Log($"activated: kind={(activation == null ? $"null ({activationError})" : activation.Kind.ToString())}");
48
68
 
49
- if (activation is ShareTargetActivatedEventArgs share)
69
+ // AOT trap (field-diagnosed 2026-07-30 via this very log): the
70
+ // idiomatic `activation is ShareTargetActivatedEventArgs` returns
71
+ // FALSE under NativeAOT — .NET type-identity casts on projected
72
+ // WinRT classes fail when trimming drops the projection metadata,
73
+ // even though Kind reads ShareTarget through the base interface.
74
+ // That silently took the "plain launch" branch: no pending file,
75
+ // no --handoff, bare launch → replace-on-launch restarted the
76
+ // whole app on every share. Branch on Kind and cast via WinRT
77
+ // QueryInterface (`.As<T>()`), which is AOT-safe.
78
+ if (activation != null && activation.Kind == ActivationKind.ShareTarget)
50
79
  {
51
- HandleShare(share).GetAwaiter().GetResult();
52
- // Handoff launch: a RUNNING daemon consumes pending-share.json
53
- // via fs.watch; the spawned mailx.js must exit instead of
54
- // replace-on-launch restarting the whole app (Bob 2026-07-30).
80
+ try
81
+ {
82
+ var share = activation.As<ShareTargetActivatedEventArgs>();
83
+ HandleShare(share).GetAwaiter().GetResult();
84
+ }
85
+ catch (Exception ex)
86
+ {
87
+ Log($"share handling FAILED: {ex}");
88
+ ShowError($"Share to rmfmail failed:\n{ex.Message}");
89
+ }
90
+ // Handoff launch either way — a share was intended; never
91
+ // restart the running daemon out from under the user.
55
92
  LaunchDaemon(handoff: true);
56
93
  }
57
94
  else
@@ -63,6 +100,7 @@ internal static class Program
63
100
  }
64
101
  catch (Exception ex)
65
102
  {
103
+ Log($"FAILED: {ex}");
66
104
  ShowError($"Share to rmfmail failed:\n{ex.Message}");
67
105
  return 1;
68
106
  }
@@ -110,7 +148,9 @@ internal static class Program
110
148
  }
111
149
  }
112
150
 
151
+ Log($"share: title={title.Length}ch text={text.Length}ch url=\"{url}\" files={files.Count}");
113
152
  WritePendingShare(title, text, url, files);
153
+ Log("pending-share.json written");
114
154
 
115
155
  try { op.ReportCompleted(); } catch { /* pane may already be gone */ }
116
156
  }
@@ -215,6 +255,7 @@ internal static class Program
215
255
  // already running (it has the pending file) instead of the default
216
256
  // replace-on-launch, which restarted the whole app mid-share.
217
257
  if (handoff) psi.ArgumentList.Add("--handoff");
258
+ Log($"launching: {node} {mailxJs}{(handoff ? " --handoff" : "")}");
218
259
  Process.Start(psi);
219
260
  }
220
261
 
package/bin/rmfshare.exe CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/rmfmail",
3
- "version": "1.2.202",
3
+ "version": "1.2.204",
4
4
  "description": "Local-first email client with IMAP sync and standalone native app",
5
5
  "type": "module",
6
6
  "main": "bin/mailx.js",