@inflector/aura 0.6.2 → 0.6.3

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/dist/bin.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAmLA,wBAAgB,KAAK,CAAC,MAAM,UAAQ,QAgDnC;AA0aD,wBAAsB,GAAG,kBAsExB"}
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAmLA,wBAAgB,KAAK,CAAC,MAAM,UAAQ,QAgDnC;AA0aD,wBAAsB,GAAG,kBAyFxB"}
package/dist/bin.js CHANGED
@@ -582,11 +582,25 @@ export async function dev() {
582
582
  changeOrigin: true,
583
583
  secure: false,
584
584
  configure(proxy, _options) {
585
- proxy.on("proxyReq", (proxyReq, req, res) => {
585
+ proxy.on("proxyReq", (proxyReq, _req, _res) => {
586
586
  if (AURA_KEY) {
587
587
  proxyReq.setHeader("Authorization", `Bearer ${AURA_KEY}`);
588
588
  }
589
589
  });
590
+ // Handle proxy errors so requests don't stay pending forever
591
+ proxy.on("error", (err, _req, res) => {
592
+ if (res && !res.headersSent) {
593
+ const isTimeout = err.code === "ECONNRESET" ||
594
+ err.code === "ETIMEDOUT" ||
595
+ err.code === "ESOCKETTIMEDOUT";
596
+ const statusCode = isTimeout ? 504 : 502;
597
+ const message = isTimeout
598
+ ? "Upstream request timed out"
599
+ : "Upstream proxy failed";
600
+ res.writeHead(statusCode, { "Content-Type": "application/json" });
601
+ res.end(JSON.stringify({ error: message }));
602
+ }
603
+ });
590
604
  },
591
605
  },
592
606
  },
@@ -1 +1 @@
1
- {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../src/function.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,GACvB,GAAG,CAkJL"}
1
+ {"version":3,"file":"function.d.ts","sourceRoot":"","sources":["../src/function.ts"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,eAAe,CAAC,EAAE,MAAM,GACvB,GAAG,CAuHL"}
package/dist/function.js CHANGED
@@ -10,7 +10,6 @@ export function createFunctionHandler(workspace, functionsFolder) {
10
10
  get(_, prop) {
11
11
  return createNestedProxy([...path, prop]);
12
12
  },
13
- // 1. Remove 'async' here to prevent native Promise wrapping
14
13
  apply(_, __, args) {
15
14
  const url = [window.location.origin, "api", "fn", workspace, ...path].join("/");
16
15
  const isFormData = args != null && args.length === 1 && args[0] instanceof FormData;
@@ -20,109 +19,86 @@ export function createFunctionHandler(workspace, functionsFolder) {
20
19
  };
21
20
  if (!isFormData)
22
21
  headers["Content-Type"] = "application/json";
23
- // 2. Start the fetch properly (without await)
24
- const requestPromise = fetch(url, {
22
+ // Return a real Promise created once, settled once.
23
+ // This prevents the re-triggering bug where the old thenable
24
+ // would re-execute fetch on every .then()/.await call.
25
+ const resultPromise = fetch(url, {
25
26
  method: "POST",
26
27
  body,
27
28
  headers,
28
29
  credentials: "include",
29
- });
30
- // 3. Return a custom "Thenable" object with full Promise interface
31
- const thenable = {
32
- then(onFulfilled, onRejected) {
33
- requestPromise
34
- .then(async (response) => {
35
- const contentType = response.headers.get("Content-Type") || "";
36
- // ─────────────────────────────────────────────
37
- // SSE PATH
38
- // ─────────────────────────────────────────────
39
- if (contentType.includes("text/event-stream")) {
40
- if (!response.body) {
41
- if (onRejected)
42
- onRejected(new Error("Response body is null"));
43
- return;
44
- }
45
- const reader = response.body.getReader();
46
- const decoder = new TextDecoder("utf-8");
47
- let buffer = "";
48
- try {
49
- while (true) {
50
- const { value, done } = await reader.read();
51
- if (done)
52
- break;
53
- buffer += decoder.decode(value, { stream: true });
54
- // Split by SSE message delimiter
55
- const parts = buffer.split("\n\n");
56
- buffer = parts.pop() || ""; // Keep incomplete chunk
57
- for (const part of parts) {
58
- if (!part.trim())
59
- continue;
60
- const lines = part.split("\n");
61
- let eventName = "message"; // Default SSE event type
62
- const dataLines = [];
63
- for (const line of lines) {
64
- if (line.startsWith("event: ")) {
65
- eventName = line.replace(/^event: /, "").trim();
66
- }
67
- else if (line.startsWith("data: ")) {
68
- dataLines.push(line.replace(/^data: /, ""));
69
- }
70
- }
71
- const message = dataLines.join("\n");
72
- if (message) {
73
- try {
74
- // Emit parsed JSON along with the event name
75
- const parsedData = JSON.parse(message);
76
- onFulfilled({
77
- event: eventName,
78
- data: parsedData,
79
- });
80
- }
81
- catch {
82
- // Or emit raw string if parsing fails
83
- onFulfilled({
84
- event: eventName,
85
- data: message,
86
- });
87
- }
88
- }
89
- }
30
+ })
31
+ .then(async (response) => {
32
+ const contentType = response.headers.get("Content-Type") || "";
33
+ // ─────────────────────────────────────────────
34
+ // Reject on HTTP errors before processing body
35
+ // ─────────────────────────────────────────────
36
+ if (!response.ok) {
37
+ let errorMessage = `Request failed with status ${response.status}`;
38
+ try {
39
+ const errorBody = await response.text();
40
+ if (errorBody)
41
+ errorMessage += `: ${errorBody}`;
42
+ }
43
+ catch {
44
+ // ignore body read errors
45
+ }
46
+ throw new Error(errorMessage);
47
+ }
48
+ // ─────────────────────────────────────────────
49
+ // SSE PATH
50
+ // ─────────────────────────────────────────────
51
+ if (contentType.includes("text/event-stream")) {
52
+ if (!response.body) {
53
+ throw new Error("SSE response body is null");
54
+ }
55
+ const reader = response.body.getReader();
56
+ const decoder = new TextDecoder("utf-8");
57
+ let buffer = "";
58
+ const events = [];
59
+ while (true) {
60
+ const { value, done } = await reader.read();
61
+ if (done)
62
+ break;
63
+ buffer += decoder.decode(value, { stream: true });
64
+ // Split by SSE message delimiter
65
+ const parts = buffer.split("\n\n");
66
+ buffer = parts.pop() || ""; // Keep incomplete chunk
67
+ for (const part of parts) {
68
+ if (!part.trim())
69
+ continue;
70
+ const lines = part.split("\n");
71
+ let eventName = "message"; // Default SSE event type
72
+ const dataLines = [];
73
+ for (const line of lines) {
74
+ if (line.startsWith("event: ")) {
75
+ eventName = line.replace(/^event: /, "").trim();
76
+ }
77
+ else if (line.startsWith("data: ")) {
78
+ dataLines.push(line.replace(/^data: /, ""));
90
79
  }
91
80
  }
92
- catch (err) {
93
- if (onRejected)
94
- onRejected(err);
81
+ const message = dataLines.join("\n");
82
+ if (message) {
83
+ try {
84
+ const parsedData = JSON.parse(message);
85
+ events.push({ event: eventName, data: parsedData });
86
+ }
87
+ catch {
88
+ events.push({ event: eventName, data: message });
89
+ }
95
90
  }
96
91
  }
97
- // ─────────────────────────────────────────────
98
- // NORMAL JSON PATH
99
- // ─────────────────────────────────────────────
100
- else {
101
- const data = await response.json();
102
- onFulfilled(data.data ?? data);
103
- }
104
- })
105
- .catch((err) => {
106
- if (onRejected)
107
- onRejected(err);
108
- });
109
- // Return 'this' to allow chaining
110
- return thenable;
111
- },
112
- catch(onRejected) {
113
- return thenable.then(() => { }, onRejected);
114
- },
115
- finally(onFinally) {
116
- return thenable.then((value) => {
117
- onFinally?.();
118
- return value;
119
- }, (err) => {
120
- onFinally?.();
121
- throw err;
122
- });
123
- },
124
- };
125
- return thenable;
92
+ }
93
+ return events.length === 1 ? events[0] : events;
94
+ }
95
+ // ─────────────────────────────────────────────
96
+ // NORMAL JSON PATH
97
+ // ─────────────────────────────────────────────
98
+ const data = await response.json();
99
+ return data.data ?? data;
100
+ });
101
+ return resultPromise;
126
102
  },
127
103
  });
128
104
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inflector/aura",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",