@aptre/bldr-saucer 0.3.1 → 0.4.2

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/package.json CHANGED
@@ -1,29 +1,34 @@
1
1
  {
2
2
  "name": "@aptre/bldr-saucer",
3
- "version": "0.3.1",
3
+ "version": "0.4.2",
4
4
  "description": "Native webview bridge for Bldr using Saucer",
5
5
  "main": "index.js",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/aperturerobotics/bldr-saucer.git"
9
- },
6
+ "license": "MIT",
10
7
  "keywords": [
11
8
  "webview",
12
9
  "saucer",
13
10
  "native",
14
11
  "bldr"
15
12
  ],
16
- "author": "Aptre",
17
- "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/aperturerobotics/bldr-saucer.git"
16
+ },
18
17
  "bugs": {
19
18
  "url": "https://github.com/aperturerobotics/bldr-saucer/issues"
20
19
  },
21
20
  "homepage": "https://github.com/aperturerobotics/bldr-saucer#readme",
21
+ "author": {
22
+ "name": "Aperture Robotics LLC.",
23
+ "email": "support@aperture.us",
24
+ "url": "http://aperture.us"
25
+ },
22
26
  "scripts": {
23
27
  "postinstall": "node install.js",
24
28
  "gen": "bun run go:aptre -- generate",
25
29
  "gen:force": "bun run go:aptre -- generate --force",
26
30
  "go:aptre": "go run -mod=mod github.com/aperturerobotics/common/cmd/aptre",
31
+ "build": "go mod vendor && cmake -G Ninja -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build --parallel",
27
32
  "release": "npm run release:version && npm run release:sync && npm run release:commit",
28
33
  "release:minor": "npm run release:version:minor && npm run release:sync && npm run release:commit",
29
34
  "release:version": "npm version patch --no-git-tag-version",
@@ -33,11 +38,11 @@
33
38
  "release:publish": "git push && git push --tags"
34
39
  },
35
40
  "optionalDependencies": {
36
- "@aptre/bldr-saucer-darwin-arm64": "0.3.1",
37
- "@aptre/bldr-saucer-darwin-x64": "0.3.1",
38
- "@aptre/bldr-saucer-linux-x64": "0.3.1",
39
- "@aptre/bldr-saucer-linux-arm64": "0.3.1",
40
- "@aptre/bldr-saucer-win32-x64": "0.3.1"
41
+ "@aptre/bldr-saucer-darwin-arm64": "0.4.2",
42
+ "@aptre/bldr-saucer-darwin-x64": "0.4.2",
43
+ "@aptre/bldr-saucer-linux-x64": "0.4.2",
44
+ "@aptre/bldr-saucer-linux-arm64": "0.4.2",
45
+ "@aptre/bldr-saucer-win32-x64": "0.4.2"
41
46
  },
42
47
  "files": [
43
48
  "index.js",
@@ -46,7 +51,7 @@
46
51
  "CMakeLists.txt"
47
52
  ],
48
53
  "devDependencies": {
49
- "@aptre/common": "^0.30.3"
54
+ "@aptre/common": "^0.32.0"
50
55
  },
51
56
  "dependencies": {
52
57
  "@aptre/protobuf-es-lite": "^1.0.0"
package/src/main.cpp CHANGED
@@ -120,7 +120,6 @@ coco::stray start(saucer::application* app) {
120
120
  auto window = saucer::window::create(app).value();
121
121
  auto webview = saucer::smartview::create({
122
122
  .window = window,
123
- .non_persistent_data_store = true,
124
123
  .storage_path = storage,
125
124
  });
126
125
 
@@ -128,9 +127,9 @@ coco::stray start(saucer::application* app) {
128
127
  window->set_size({1024, 768});
129
128
 
130
129
  // Handle bldr:// scheme: forward all requests to Go over yamux.
131
- webview->handle_stream_scheme("bldr", [forwarder](saucer::scheme::request req, saucer::scheme::stream_writer writer) {
132
- std::thread([forwarder, req = std::move(req), writer = std::move(writer)]() mutable {
133
- forwarder->forward(req, writer);
130
+ webview->handle_scheme("bldr", [forwarder](saucer::scheme::request req, saucer::scheme::executor executor) {
131
+ std::thread([forwarder, req = std::move(req), executor = std::move(executor)]() mutable {
132
+ forwarder->forward(req, executor);
134
133
  }).detach();
135
134
  });
136
135
 
@@ -23,25 +23,33 @@ static const std::map<std::string, std::string> corsHeaders = {
23
23
  {"Access-Control-Allow-Headers", "*"},
24
24
  };
25
25
 
26
- // sendError sends an error response to the saucer writer.
27
- static void sendError(saucer::scheme::stream_writer& writer, int status) {
28
- writer.start({.mime = "text/plain", .headers = corsHeaders, .status = status});
29
- writer.finish();
26
+ // sendError resolves the executor with an error status response.
27
+ static void sendError(saucer::scheme::executor& executor, int status) {
28
+ executor.resolve({
29
+ .data = saucer::stash::empty(),
30
+ .mime = "text/plain",
31
+ .headers = corsHeaders,
32
+ .status = status,
33
+ });
30
34
  }
31
35
 
32
36
  void SchemeForwarder::forward(const saucer::scheme::request& req,
33
- saucer::scheme::stream_writer& writer) {
37
+ saucer::scheme::executor& executor) {
34
38
  // Handle CORS preflight directly without forwarding to Go.
35
39
  if (toLower(req.method()) == "options") {
36
- writer.start({.mime = "text/plain", .headers = corsHeaders, .status = 204});
37
- writer.finish();
40
+ executor.resolve({
41
+ .data = saucer::stash::empty(),
42
+ .mime = "text/plain",
43
+ .headers = corsHeaders,
44
+ .status = 204,
45
+ });
38
46
  return;
39
47
  }
40
48
 
41
49
  // Open a new yamux stream.
42
50
  auto [stream, err] = session_->OpenStream();
43
51
  if (err != yamux::Error::OK || !stream) {
44
- sendError(writer, 502);
52
+ sendError(executor, 502);
45
53
  return;
46
54
  }
47
55
 
@@ -56,58 +64,64 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
56
64
  }
57
65
 
58
66
  // Check if request has a body.
59
- auto content = req.content();
67
+ auto content = req.content().data();
60
68
  info.has_body = (content.size() > 0);
61
69
 
62
70
  // Serialize and send FetchRequestInfo frame.
63
71
  auto reqInfoMsg = proto::EncodeFetchRequest_Info(info);
64
72
  if (!writeFrame(stream.get(), reqInfoMsg)) {
65
73
  stream->Close();
66
- sendError(writer, 502);
74
+ sendError(executor, 502);
67
75
  return;
68
76
  }
69
77
 
70
78
  // Send body if present.
71
79
  if (info.has_body) {
72
80
  proto::FetchRequestData bodyData;
73
- bodyData.data.assign(
74
- static_cast<const uint8_t*>(content.data()),
75
- static_cast<const uint8_t*>(content.data()) + content.size()
76
- );
81
+ bodyData.data.assign(content.data(), content.data() + content.size());
77
82
  bodyData.done = true;
78
83
 
79
84
  auto reqDataMsg = proto::EncodeFetchRequest_Data(bodyData);
80
85
  if (!writeFrame(stream.get(), reqDataMsg)) {
81
86
  stream->Close();
82
- sendError(writer, 502);
87
+ sendError(executor, 502);
83
88
  return;
84
89
  }
85
90
  }
86
91
 
92
+ // Create streaming stash for incremental response delivery.
93
+ auto result = saucer::scheme::response::stream();
94
+ if (!result) {
95
+ executor.reject(saucer::scheme::error::failed);
96
+ stream->Close();
97
+ return;
98
+ }
99
+ auto [stash, write] = std::move(*result);
100
+
87
101
  // Read response frames from Go.
88
- bool started = false;
102
+ bool resolved = false;
89
103
  bool done = false;
90
104
 
91
105
  while (!done) {
92
106
  std::vector<uint8_t> frame;
93
107
  if (!readFrame(stream.get(), frame)) {
94
- if (!started) {
95
- sendError(writer, 502);
108
+ if (!resolved) {
109
+ executor.reject(saucer::scheme::error::failed);
96
110
  }
97
111
  break;
98
112
  }
99
113
 
100
114
  proto::FetchResponse resp;
101
115
  if (!proto::DecodeFetchResponse(frame.data(), frame.size(), resp)) {
102
- if (!started) {
103
- sendError(writer, 502);
116
+ if (!resolved) {
117
+ executor.reject(saucer::scheme::error::failed);
104
118
  }
105
119
  break;
106
120
  }
107
121
 
108
- // Process ResponseInfo (first frame).
109
- if (resp.has_info && !started) {
110
- started = true;
122
+ // Process ResponseInfo (first frame): resolve executor with headers and streaming stash.
123
+ if (resp.has_info && !resolved) {
124
+ resolved = true;
111
125
 
112
126
  // Extract Content-Type header (case-insensitive) and merge CORS headers.
113
127
  std::string mime = "application/octet-stream";
@@ -120,22 +134,29 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
120
134
  }
121
135
  }
122
136
 
123
- writer.start({
137
+ executor.resolve({
138
+ .data = std::move(stash),
124
139
  .mime = mime,
125
140
  .headers = hdrs,
126
141
  .status = static_cast<int>(resp.info.status),
127
142
  });
128
143
  }
129
144
 
130
- // Process ResponseData.
145
+ // Process ResponseData: push body chunks via streaming write callback.
131
146
  if (resp.has_data) {
132
- if (!started) {
133
- started = true;
134
- writer.start({.mime = "application/octet-stream", .status = 200});
147
+ if (!resolved) {
148
+ resolved = true;
149
+ executor.resolve({
150
+ .data = std::move(stash),
151
+ .mime = "application/octet-stream",
152
+ .status = 200,
153
+ });
135
154
  }
136
155
 
137
- if (!resp.data.data.empty() && writer.valid()) {
138
- writer.write(saucer::stash::from(std::move(resp.data.data)));
156
+ if (!resp.data.data.empty()) {
157
+ if (!write({resp.data.data.data(), resp.data.data.size()})) {
158
+ break;
159
+ }
139
160
  }
140
161
 
141
162
  if (resp.data.done) {
@@ -144,9 +165,7 @@ void SchemeForwarder::forward(const saucer::scheme::request& req,
144
165
  }
145
166
  }
146
167
 
147
- if (started) {
148
- writer.finish();
149
- }
168
+ // Destroying write closes the streaming stash.
150
169
  stream->Close();
151
170
  }
152
171
 
@@ -3,6 +3,7 @@
3
3
  #include "fetch_proto.h"
4
4
  #include "yamux/session.hpp"
5
5
 
6
+ #include <saucer/scheme.hpp>
6
7
  #include <saucer/smartview.hpp>
7
8
 
8
9
  #include <cstdint>
@@ -21,7 +22,7 @@ public:
21
22
  explicit SchemeForwarder(yamux::Session* session) : session_(session) {}
22
23
 
23
24
  // forward handles a single scheme request by forwarding it to Go.
24
- void forward(const saucer::scheme::request& req, saucer::scheme::stream_writer& writer);
25
+ void forward(const saucer::scheme::request& req, saucer::scheme::executor& executor);
25
26
 
26
27
  private:
27
28
  // writeFrame writes a length-prefixed frame to a yamux stream.