@zogien/native-sdk 0.11.0-fork.3 → 0.11.0-fork.5

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.
Files changed (67) hide show
  1. package/README.md +1 -1
  2. package/build/app.zig +53 -34
  3. package/build/cli.zig +22 -0
  4. package/package.json +10 -10
  5. package/packages/core/package-lock.json +2 -2
  6. package/packages/core/package.json +1 -1
  7. package/schemas/app.schema.json +9 -1
  8. package/skill-data/core/references/bridge-security-native-capabilities.md +4 -0
  9. package/skill-data/ts-core/SKILL.md +2 -0
  10. package/src/app_runner/app_assets.zig +85 -1
  11. package/src/app_runner/root.zig +63 -3
  12. package/src/app_runner/ts_core_main.zig +8 -0
  13. package/src/platform/linux/cef_host.cpp +22 -0
  14. package/src/platform/linux/gtk_host.c +317 -34
  15. package/src/platform/linux/gtk_host.h +37 -0
  16. package/src/platform/linux/root.zig +114 -20
  17. package/src/platform/macos/appkit_host.h +53 -0
  18. package/src/platform/macos/appkit_host.m +667 -67
  19. package/src/platform/macos/cef_host.mm +21 -0
  20. package/src/platform/macos/root.zig +146 -29
  21. package/src/platform/null_platform.zig +136 -0
  22. package/src/platform/root.zig +7 -0
  23. package/src/platform/types.zig +90 -0
  24. package/src/platform/windows/dialog_test.cpp +303 -0
  25. package/src/platform/windows/host_loop_test.cpp +169 -0
  26. package/src/platform/windows/root.zig +262 -39
  27. package/src/platform/windows/session_end_test.cpp +303 -0
  28. package/src/platform/windows/webview2_host.cpp +1435 -306
  29. package/src/primitives/app_manifest/root.zig +1 -0
  30. package/src/primitives/app_manifest/tests.zig +35 -0
  31. package/src/primitives/app_manifest/types.zig +12 -0
  32. package/src/primitives/app_manifest/validation.zig +44 -6
  33. package/src/root.zig +8 -0
  34. package/src/runtime/builtin_bridge.zig +108 -13
  35. package/src/runtime/channel_sources.zig +49 -1
  36. package/src/runtime/core.zig +24 -3
  37. package/src/runtime/dialog_tests.zig +367 -0
  38. package/src/runtime/dialogs.zig +385 -0
  39. package/src/runtime/effects.zig +83 -3
  40. package/src/runtime/effects_host_tests.zig +69 -1
  41. package/src/runtime/flow.zig +20 -6
  42. package/src/runtime/flow_reference.zig +20 -6
  43. package/src/runtime/platform_bridge_tests.zig +1 -0
  44. package/src/runtime/root.zig +9 -0
  45. package/src/runtime/single_instance.zig +893 -0
  46. package/src/runtime/system_services.zig +64 -82
  47. package/src/runtime/ui_app.zig +67 -0
  48. package/src/tooling/manifest.zig +111 -3
  49. package/src/tooling/package.zig +98 -8
  50. package/src/tooling/raw_manifest.zig +7 -0
  51. package/src/tooling/root.zig +2 -0
  52. package/src/tooling/templates.zig +44 -2
  53. package/src/tooling/update.zig +228 -10
  54. package/src/tooling/windows_installer.zig +245 -0
  55. package/src/tooling/zip_writer.zig +211 -0
  56. package/src/updater/engine.zig +936 -0
  57. package/src/updater/feed.zig +261 -12
  58. package/src/updater/macos.zig +187 -0
  59. package/src/updater/root.zig +41 -0
  60. package/src/updater/windows.zig +470 -0
  61. package/src/windows_install/config.zig +247 -0
  62. package/src/windows_install/main.zig +690 -0
  63. package/src/windows_install/payload.zig +146 -0
  64. package/src/windows_install/switch.zig +184 -0
  65. package/src/windows_install/tests.zig +11 -0
  66. package/src/windows_install/win32.zig +248 -0
  67. package/tools/native-sdk/main.zig +10 -9
@@ -30,6 +30,7 @@ const app_manifest = @import("app_manifest");
30
30
  const platform = @import("../platform/root.zig");
31
31
  const host_flow = @import("host_flow_policy.zig");
32
32
  const native_reference = @import("flow_reference.zig");
33
+ const update_engine = @import("../updater/engine.zig");
33
34
  const HostEventPump = @import("host_event_pump.zig").HostEventPump;
34
35
  const security = @import("../security/root.zig");
35
36
 
@@ -381,6 +382,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
381
382
  const state = event_value.window_frame_changed;
382
383
  if (host_flow.gate(policy, 1, @intFromBool(was_open), @intFromBool(state.open)) != 0) {
383
384
  const label = if (WindowViewMethods().findWindowIndexById(self, state.id)) |index| self.windows[index].info.label else state.label;
385
+ self.cancelDialogsForWindow(state.id);
384
386
  try dispatchEvent(self, app, .{ .window_closed = .{ .window_id = state.id, .label = label } });
385
387
  }
386
388
  },
@@ -448,6 +450,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
448
450
  emitFileDropEvent(self, drop) catch |err| log(self, "drop.files.emit_failed", @errorName(err), &.{trace.uint("window_id", drop.window_id)});
449
451
  },
450
452
  .lifecycle_stop => {
453
+ self.abandonDialogs();
451
454
  try dispatchEvent(self, app, .{ .lifecycle = .stop });
452
455
  },
453
456
  .extensions_stop => {
@@ -455,6 +458,11 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
455
458
  },
456
459
  .mark_stop => {
457
460
  self.app_stop_delivered = true;
461
+ // A release the app staged but did not restart into
462
+ // installs as the app quits, where the platform
463
+ // installs on exit (macOS); hosts may exit the process
464
+ // right after this event, so it cannot wait for run().
465
+ update_engine.finish();
458
466
  },
459
467
  .stop => {
460
468
  try app.stop(self);
@@ -523,6 +531,10 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
523
531
  try dispatchEvent(self, app, .{ .video = event_value.video });
524
532
  },
525
533
  .event_wake => {
534
+ // Finished dialogs ride the same nudge the effects
535
+ // channel uses; their completions run before the app
536
+ // drains its own work.
537
+ self.adoptDialogResults();
526
538
  try dispatchEvent(self, app, .effects_wake);
527
539
  },
528
540
  .capability_gpu_surface_frame => {
@@ -1200,19 +1212,20 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1200
1212
  self.invalidateFor(.command, null);
1201
1213
  return true;
1202
1214
  }
1203
- const response = switch (plan.family()) {
1215
+ const response: ?[]const u8 = switch (plan.family()) {
1204
1216
  .none => unreachable,
1205
1217
  .command => dispatchCommandBridgeCommand(self, app, request, message.window_id, message.webview_label, &result_buffer, &response_buffer),
1206
1218
  .window => dispatchWindowBridgeCommand(self, request, &result_buffer, &response_buffer),
1207
1219
  .view => dispatchViewBridgeCommand(self, request, message.window_id, &result_buffer, &response_buffer),
1208
1220
  .webview => dispatchWebViewBridgeCommand(self, request, message.window_id, &result_buffer, &response_buffer),
1209
1221
  .platform => dispatchPlatformBridgeCommand(self, request, &result_buffer, &response_buffer),
1210
- .dialog => dispatchDialogBridgeCommand(self, request, &result_buffer, &response_buffer),
1222
+ .dialog => dispatchDialogBridgeCommand(self, request, message, &result_buffer, &response_buffer),
1211
1223
  .os => dispatchOsBridgeCommand(self, request, message.origin, &result_buffer, &response_buffer),
1212
1224
  .clipboard => dispatchClipboardBridgeCommand(self, request, &result_buffer, &response_buffer),
1213
1225
  .credentials => dispatchCredentialBridgeCommand(self, request, &result_buffer, &response_buffer),
1214
1226
  };
1215
- try completeBridgeResponse(self, message.window_id, message.webview_label, response);
1227
+ // Dialogs answer later, when they finish.
1228
+ if (response) |bytes| try completeBridgeResponse(self, message.window_id, message.webview_label, bytes);
1216
1229
  self.invalidateFor(.command, null);
1217
1230
  return true;
1218
1231
  }
@@ -1265,7 +1278,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1265
1278
  self.invalidateFor(.command, null);
1266
1279
  return true;
1267
1280
  }
1268
- const result = if (is_command)
1281
+ const result: ?[]const u8 = if (is_command)
1269
1282
  dispatchCommandBridgeCommand(self, app, request, message.window_id, message.webview_label, &result_buffer, &response_buffer)
1270
1283
  else if (is_window)
1271
1284
  dispatchWindowBridgeCommand(self, request, &result_buffer, &response_buffer)
@@ -1276,7 +1289,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1276
1289
  else if (is_platform)
1277
1290
  dispatchPlatformBridgeCommand(self, request, &result_buffer, &response_buffer)
1278
1291
  else if (is_dialog)
1279
- dispatchDialogBridgeCommand(self, request, &result_buffer, &response_buffer)
1292
+ dispatchDialogBridgeCommand(self, request, message, &result_buffer, &response_buffer)
1280
1293
  else if (is_clipboard)
1281
1294
  dispatchClipboardBridgeCommand(self, request, &result_buffer, &response_buffer)
1282
1295
  else if (is_credentials)
@@ -1284,7 +1297,8 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1284
1297
  else
1285
1298
  dispatchOsBridgeCommand(self, request, message.origin, &result_buffer, &response_buffer);
1286
1299
 
1287
- try completeBridgeResponse(self, message.window_id, message.webview_label, result);
1300
+ // Dialogs answer later, when they finish.
1301
+ if (result) |bytes| try completeBridgeResponse(self, message.window_id, message.webview_label, bytes);
1288
1302
  self.invalidateFor(.command, null);
1289
1303
  return true;
1290
1304
  }
@@ -12,6 +12,7 @@ const runtime_automation_snapshot = @import("automation_snapshot.zig");
12
12
  const runtime_automation_widget_dispatch = @import("automation_widget_dispatch.zig");
13
13
  const automation_commands = @import("automation_command_policy.zig");
14
14
  const launch_timing = @import("launch_timing.zig");
15
+ const update_engine = @import("../updater/engine.zig");
15
16
  const runtime_clock = @import("clock.zig");
16
17
  const runtime_state = @import("state.zig");
17
18
  const shell_layout = @import("shell_layout.zig");
@@ -368,6 +369,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
368
369
  // comes from runtime storage, which outlives the
369
370
  // event's transient slices.
370
371
  const label = if (WindowViewMethods().findWindowIndexById(self, state.id)) |index| self.windows[index].info.label else state.label;
372
+ self.cancelDialogsForWindow(state.id);
371
373
  try dispatchEvent(self, app, .{ .window_closed = .{ .window_id = state.id, .label = label } });
372
374
  }
373
375
  },
@@ -504,6 +506,10 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
504
506
  try dispatchEvent(self, app, .{ .video = video_event });
505
507
  },
506
508
  .wake => {
509
+ // Finished dialogs ride the same nudge the effects
510
+ // channel uses; their completions run before the app
511
+ // drains its own work.
512
+ self.adoptDialogResults();
507
513
  try dispatchEvent(self, app, .effects_wake);
508
514
  },
509
515
  .files_dropped => |drop| {
@@ -522,8 +528,14 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
522
528
  self.invalidateFor(.command, null);
523
529
  },
524
530
  .app_shutdown => {
531
+ self.abandonDialogs();
525
532
  try dispatchEvent(self, app, .{ .lifecycle = .stop });
526
533
  if (self.options.extensions) |registry| try registry.stopAll(extensionContext(self));
534
+ // A release the app staged but did not restart into
535
+ // installs as the app quits, where the platform
536
+ // installs on exit (macOS); hosts may exit the process
537
+ // right after this event, so it cannot wait for run().
538
+ update_engine.finish();
527
539
  // Marked delivered BEFORE the call: if the hook itself
528
540
  // errors, the run loop's exit path must not invoke it a
529
541
  // second time (the hook contract is exactly-once).
@@ -1208,19 +1220,20 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1208
1220
  self.invalidateFor(.command, null);
1209
1221
  return true;
1210
1222
  }
1211
- const response = switch (plan.family()) {
1223
+ const response: ?[]const u8 = switch (plan.family()) {
1212
1224
  .none => unreachable,
1213
1225
  .command => dispatchCommandBridgeCommand(self, app, request, message.window_id, message.webview_label, &result_buffer, &response_buffer),
1214
1226
  .window => dispatchWindowBridgeCommand(self, request, &result_buffer, &response_buffer),
1215
1227
  .view => dispatchViewBridgeCommand(self, request, message.window_id, &result_buffer, &response_buffer),
1216
1228
  .webview => dispatchWebViewBridgeCommand(self, request, message.window_id, &result_buffer, &response_buffer),
1217
1229
  .platform => dispatchPlatformBridgeCommand(self, request, &result_buffer, &response_buffer),
1218
- .dialog => dispatchDialogBridgeCommand(self, request, &result_buffer, &response_buffer),
1230
+ .dialog => dispatchDialogBridgeCommand(self, request, message, &result_buffer, &response_buffer),
1219
1231
  .os => dispatchOsBridgeCommand(self, request, message.origin, &result_buffer, &response_buffer),
1220
1232
  .clipboard => dispatchClipboardBridgeCommand(self, request, &result_buffer, &response_buffer),
1221
1233
  .credentials => dispatchCredentialBridgeCommand(self, request, &result_buffer, &response_buffer),
1222
1234
  };
1223
- try completeBridgeResponse(self, message.window_id, message.webview_label, response);
1235
+ // Dialogs answer later, when they finish.
1236
+ if (response) |bytes| try completeBridgeResponse(self, message.window_id, message.webview_label, bytes);
1224
1237
  self.invalidateFor(.command, null);
1225
1238
  return true;
1226
1239
  }
@@ -1273,7 +1286,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1273
1286
  self.invalidateFor(.command, null);
1274
1287
  return true;
1275
1288
  }
1276
- const result = if (is_command)
1289
+ const result: ?[]const u8 = if (is_command)
1277
1290
  dispatchCommandBridgeCommand(self, app, request, message.window_id, message.webview_label, &result_buffer, &response_buffer)
1278
1291
  else if (is_window)
1279
1292
  dispatchWindowBridgeCommand(self, request, &result_buffer, &response_buffer)
@@ -1284,7 +1297,7 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1284
1297
  else if (is_platform)
1285
1298
  dispatchPlatformBridgeCommand(self, request, &result_buffer, &response_buffer)
1286
1299
  else if (is_dialog)
1287
- dispatchDialogBridgeCommand(self, request, &result_buffer, &response_buffer)
1300
+ dispatchDialogBridgeCommand(self, request, message, &result_buffer, &response_buffer)
1288
1301
  else if (is_clipboard)
1289
1302
  dispatchClipboardBridgeCommand(self, request, &result_buffer, &response_buffer)
1290
1303
  else if (is_credentials)
@@ -1292,7 +1305,8 @@ pub fn RuntimeFlow(comptime Runtime: type) type {
1292
1305
  else
1293
1306
  dispatchOsBridgeCommand(self, request, message.origin, &result_buffer, &response_buffer);
1294
1307
 
1295
- try completeBridgeResponse(self, message.window_id, message.webview_label, result);
1308
+ // Dialogs answer later, when they finish.
1309
+ if (result) |bytes| try completeBridgeResponse(self, message.window_id, message.webview_label, bytes);
1296
1310
  self.invalidateFor(.command, null);
1297
1311
  return true;
1298
1312
  }
@@ -6,4 +6,5 @@ test {
6
6
  _ = @import("webview_view_bridge_tests.zig");
7
7
  _ = @import("web_layer_gate_tests.zig");
8
8
  _ = @import("bridge_permission_tests.zig");
9
+ _ = @import("dialog_tests.zig");
9
10
  }
@@ -40,6 +40,10 @@ pub const Event = core.Event;
40
40
  pub const App = core.App;
41
41
  pub const Options = core.Options;
42
42
  pub const Runtime = core.Runtime;
43
+ pub const DialogCompletion = core.DialogCompletion;
44
+ pub const DialogRequestOptions = core.DialogRequestOptions;
45
+ pub const max_dialog_requests = core.max_dialog_requests;
46
+ pub const max_dialog_tag_bytes = core.max_dialog_tag_bytes;
43
47
  pub const TestHarness = core.TestHarness;
44
48
  pub const DispatchError = core.DispatchError;
45
49
  pub const max_dispatch_errors = core.max_dispatch_errors;
@@ -165,6 +169,7 @@ pub const max_effect_pty_chunk_bytes = runtime_effects.max_effect_pty_chunk_byte
165
169
  pub const max_effect_pty_write_bytes = runtime_effects.max_effect_pty_write_bytes;
166
170
  pub const max_effect_pty_term_bytes = runtime_effects.max_effect_pty_term_bytes;
167
171
  pub const EffectHostResult = runtime_effects.EffectHostResult;
172
+ pub const DesktopCapabilityCompletion = runtime_effects.DesktopCapabilityCompletion;
168
173
  pub const HostCallBinding = runtime_effects.HostCallBinding;
169
174
  pub const HostCallCompletion = runtime_effects.HostCallCompletion;
170
175
  pub const ServiceHost = @import("service_host.zig").ServiceHost;
@@ -241,6 +246,10 @@ pub const max_session_journal_bytes = runtime_session_journal.max_session_journa
241
246
  pub const max_session_record_bytes = runtime_session_journal.max_session_record_bytes;
242
247
  pub const max_session_event_bytes = runtime_session_journal.max_session_event_bytes;
243
248
 
249
+ /// Manifest `single_instance` ownership; the launcher claims it before
250
+ /// startup and the `native-sdk.app.launches` source delivers launches.
251
+ pub const single_instance = @import("single_instance.zig");
252
+
244
253
  const runtime_clock = @import("clock.zig");
245
254
  pub const Clock = runtime_clock.Clock;
246
255
  pub const TestClock = runtime_clock.TestClock;