arcane-os 0.15.0 → 0.15.1
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/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/docs/reference/mail.md +6 -0
- package/package.json +1 -1
- package/src/mail-server.mjs +20 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.15.1
|
|
4
|
+
|
|
5
|
+
- Use the published `node-http-server` public lifecycle for the mail gateway.
|
|
6
|
+
Pass original requests and responses through its raw-request hook to the
|
|
7
|
+
existing mail handler, preserving complete content, provider results,
|
|
8
|
+
cancellation, and the returned native listener. Retain the disabled socket
|
|
9
|
+
inactivity timeout and use the module's listener shutdown and malformed-client
|
|
10
|
+
response handling.
|
|
11
|
+
|
|
3
12
|
## 0.15.0
|
|
4
13
|
|
|
5
14
|
- Add explicit `arcane dev --http` and source API `http:true` for HTTP
|
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ version-locked SDK runtime, while an integrated Arcane checkout uses its live
|
|
|
19
19
|
`arcane/` runtime. Both profiles preserve the same app URLs, theme, packaging,
|
|
20
20
|
event, cancellation, and browser run contracts.
|
|
21
21
|
|
|
22
|
-
This checkout defines the `0.
|
|
22
|
+
This checkout defines the `0.15.1` SDK contract. Applications pin one exact npm
|
|
23
23
|
version and lockfile; registry state is deliberately not baked into application
|
|
24
24
|
artifacts.
|
|
25
25
|
|
package/docs/reference/mail.md
CHANGED
|
@@ -283,6 +283,12 @@ Non-interactive structured output requires `--app-key-stdin` and redirected
|
|
|
283
283
|
stdin. The server binds numeric loopback only; the default is
|
|
284
284
|
`127.0.0.1:8025/v1/mail`.
|
|
285
285
|
|
|
286
|
+
The gateway uses the published `node-http-server` instance lifecycle. Its raw
|
|
287
|
+
request hook hands the original request and response directly to the mail
|
|
288
|
+
handler before body parsing or static routing. Socket inactivity timeout remains
|
|
289
|
+
disabled; caller-selected mail deadlines, cancellation, and complete responses
|
|
290
|
+
remain owned by the mail handler.
|
|
291
|
+
|
|
286
292
|
The gateway protects the provider credential by requiring:
|
|
287
293
|
|
|
288
294
|
- its exact numeric-loopback `Host` authority and `/v1/mail` route;
|
package/package.json
CHANGED
package/src/mail-server.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Is from 'strong-type';
|
|
2
2
|
import {createHash,randomUUID,timingSafeEqual} from 'node:crypto';
|
|
3
|
-
import
|
|
3
|
+
import {Server} from 'node-http-server';
|
|
4
4
|
|
|
5
5
|
const is = new Is(false);
|
|
6
6
|
|
|
@@ -1283,40 +1283,16 @@ export function createResendMailRequestHandler(options={}){
|
|
|
1283
1283
|
};
|
|
1284
1284
|
}
|
|
1285
1285
|
|
|
1286
|
-
function
|
|
1286
|
+
function deployMailServer(mailServer){
|
|
1287
1287
|
return new Promise(function waitForMailListener(resolve,reject){
|
|
1288
|
-
function cleanup(){
|
|
1289
|
-
server.removeListener('error',onError);
|
|
1290
|
-
server.removeListener('listening',onListening);
|
|
1291
|
-
}
|
|
1292
1288
|
function onError(error){
|
|
1293
|
-
cleanup();
|
|
1294
1289
|
reject(error);
|
|
1295
1290
|
}
|
|
1296
|
-
function onListening(){
|
|
1297
|
-
|
|
1298
|
-
resolve();
|
|
1299
|
-
}
|
|
1300
|
-
server.once('error',onError);
|
|
1301
|
-
server.once('listening',onListening);
|
|
1302
|
-
server.listen({exclusive:true,host,port});
|
|
1303
|
-
});
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
function closeHttpServer(server){
|
|
1307
|
-
return new Promise(function waitForHttpServerClose(resolve,reject){
|
|
1308
|
-
if(!server.listening){
|
|
1309
|
-
resolve();
|
|
1310
|
-
return;
|
|
1311
|
-
}
|
|
1312
|
-
server.close(function finishHttpServerClose(error){
|
|
1313
|
-
if(error){
|
|
1314
|
-
reject(error);
|
|
1315
|
-
}else{
|
|
1316
|
-
resolve();
|
|
1317
|
-
}
|
|
1291
|
+
mailServer.deploy(function onListening(instance,server){
|
|
1292
|
+
server.removeListener('error',onError);
|
|
1293
|
+
resolve(server);
|
|
1318
1294
|
});
|
|
1319
|
-
server.
|
|
1295
|
+
mailServer.server.once('error',onError);
|
|
1320
1296
|
});
|
|
1321
1297
|
}
|
|
1322
1298
|
|
|
@@ -1325,29 +1301,27 @@ export async function startResendMailServer(options={}){
|
|
|
1325
1301
|
if(configuration.signal?.aborted){
|
|
1326
1302
|
throw configuration.signal.reason??new Error('Mail server start was cancelled.');
|
|
1327
1303
|
}
|
|
1328
|
-
const
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
return;
|
|
1333
|
-
}
|
|
1334
|
-
socket.end(
|
|
1335
|
-
'HTTP/1.1 400 Bad Request\r\n'
|
|
1336
|
-
+'Connection: close\r\n'
|
|
1337
|
-
+'Content-Length: 0\r\n'
|
|
1338
|
-
+'\r\n'
|
|
1339
|
-
);
|
|
1304
|
+
const mailServer=new Server({
|
|
1305
|
+
host:configuration.host,
|
|
1306
|
+
port:configuration.port,
|
|
1307
|
+
server:{timeout:0}
|
|
1340
1308
|
});
|
|
1309
|
+
const requestHandler=createResendMailRequestHandler(options);
|
|
1310
|
+
mailServer.onRawRequest=function handleMailRequest(request,response){
|
|
1311
|
+
requestHandler.handle(request,response);
|
|
1312
|
+
return true;
|
|
1313
|
+
};
|
|
1341
1314
|
|
|
1315
|
+
let server;
|
|
1342
1316
|
try{
|
|
1343
|
-
await
|
|
1317
|
+
server=await deployMailServer(mailServer);
|
|
1344
1318
|
}catch(error){
|
|
1345
|
-
await requestHandler.close();
|
|
1319
|
+
await Promise.allSettled([mailServer.close(),requestHandler.close()]);
|
|
1346
1320
|
throw error;
|
|
1347
1321
|
}
|
|
1348
1322
|
const address=server.address();
|
|
1349
1323
|
if(!address||is.string(address)||!isNumericLoopback(address.address)){
|
|
1350
|
-
await Promise.allSettled([
|
|
1324
|
+
await Promise.allSettled([mailServer.close(),requestHandler.close()]);
|
|
1351
1325
|
throw configurationError('Mail server did not bind to a numeric loopback address.');
|
|
1352
1326
|
}
|
|
1353
1327
|
const displayHost=address.address.includes(':')?`[${address.address}]`:address.address;
|
|
@@ -1365,7 +1339,7 @@ export async function startResendMailServer(options={}){
|
|
|
1365
1339
|
configuration.signal?.removeEventListener('abort',closeFromSignal);
|
|
1366
1340
|
const handlerClosing=requestHandler.close();
|
|
1367
1341
|
try{
|
|
1368
|
-
await Promise.all([
|
|
1342
|
+
await Promise.all([mailServer.close(),handlerClosing]);
|
|
1369
1343
|
resolveLifecycle();
|
|
1370
1344
|
}catch(error){
|
|
1371
1345
|
rejectLifecycle(error);
|