arcane-os 0.15.2 → 0.16.0
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 +22 -0
- package/README.md +9 -1
- package/docs/reference/cli.md +44 -30
- package/docs/reference/mail.md +166 -67
- package/docs/reviews/mail-server-purpose-review.md +350 -0
- package/package.json +1 -1
- package/runtime/arcane/modules/Mail.js +42 -71
- package/runtime/arcane/modules/MailOutbox.mjs +5 -5
- package/runtime/arcane/modules/MailTransport.mjs +12 -21
- package/src/cli/main.mjs +14 -46
- package/src/mail-server.mjs +333 -617
- package/src/mail.mjs +50 -110
|
@@ -7,22 +7,18 @@ import {
|
|
|
7
7
|
sendMailReport,
|
|
8
8
|
} from './MailTransport.mjs';
|
|
9
9
|
|
|
10
|
-
let userInstance=null;
|
|
11
|
-
|
|
12
|
-
function completeResult(value){return value;}
|
|
13
|
-
|
|
14
10
|
const MAIL_TYPES=new Set(['error','report','crisis_detected']);
|
|
15
|
-
const MAIL_OUTBOX_EVENTS=
|
|
11
|
+
const MAIL_OUTBOX_EVENTS=[
|
|
16
12
|
'mail-outbox-state',
|
|
17
13
|
'mail-outbox-delivery',
|
|
18
14
|
'mail-outbox-drain'
|
|
19
|
-
]
|
|
15
|
+
];
|
|
20
16
|
const PENDING_OUTBOX_STATES=new Set(['queued','sending','retry_wait']);
|
|
21
|
-
const NATIVE_MAIL_RESPONSE_STATUS_CODES=
|
|
17
|
+
const NATIVE_MAIL_RESPONSE_STATUS_CODES={
|
|
22
18
|
accepted:202,
|
|
23
19
|
delivery_uncertain:207,
|
|
24
20
|
partially_accepted:207
|
|
25
|
-
}
|
|
21
|
+
};
|
|
26
22
|
const NATIVE_MAIL_REQUEST_ID_PATTERN=/^[A-Za-z0-9-]+$/;
|
|
27
23
|
const NATIVE_MAIL_UNCERTAIN_ERROR_CODES=new Set([
|
|
28
24
|
'ARCANE_REQUEST_TIMEOUT',
|
|
@@ -37,7 +33,6 @@ const NATIVE_MAIL_RETRYABLE_ERROR_CODES=new Set([
|
|
|
37
33
|
'ARCANE_TRANSPORT_UNAVAILABLE'
|
|
38
34
|
]);
|
|
39
35
|
const EMAIL_PATTERN=/^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/i;
|
|
40
|
-
const ARCANE_APP_ID_PATTERN=/^[a-z0-9](?:[a-z0-9-]{0,62})$/;
|
|
41
36
|
|
|
42
37
|
function codedError(message,code,ErrorType=Error){
|
|
43
38
|
const error=new ErrorType(message);
|
|
@@ -71,10 +66,10 @@ function linkedMailSignal(primary,secondary){
|
|
|
71
66
|
if(signal&&!signals.includes(signal)) signals.push(signal);
|
|
72
67
|
}
|
|
73
68
|
if(signals.length===0){
|
|
74
|
-
return
|
|
69
|
+
return {signal:null,dispose:function disposeEmptyMailSignal(){}};
|
|
75
70
|
}
|
|
76
71
|
if(signals.length===1){
|
|
77
|
-
return
|
|
72
|
+
return {signal:signals[0],dispose:function disposeSingleMailSignal(){}};
|
|
78
73
|
}
|
|
79
74
|
const controller=new AbortController();
|
|
80
75
|
const listeners=[];
|
|
@@ -86,14 +81,14 @@ function linkedMailSignal(primary,secondary){
|
|
|
86
81
|
if(signal.aborted) listener();
|
|
87
82
|
else signal.addEventListener('abort',listener,{once:true});
|
|
88
83
|
}
|
|
89
|
-
return
|
|
84
|
+
return {
|
|
90
85
|
signal:controller.signal,
|
|
91
86
|
dispose:function disposeLinkedMailSignal(){
|
|
92
87
|
for(const entry of listeners){
|
|
93
88
|
entry.signal.removeEventListener('abort',entry.listener);
|
|
94
89
|
}
|
|
95
90
|
}
|
|
96
|
-
}
|
|
91
|
+
};
|
|
97
92
|
}
|
|
98
93
|
|
|
99
94
|
function waitForMailOperation(operation,signal){
|
|
@@ -190,58 +185,23 @@ async function loadRequiredMailStorage(){
|
|
|
190
185
|
return storage;
|
|
191
186
|
}
|
|
192
187
|
|
|
193
|
-
async function
|
|
188
|
+
async function resolveMailUserEntity(injectedUser){
|
|
194
189
|
if(injectedUser!==undefined) return injectedUser;
|
|
195
|
-
if(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
return userInstance;
|
|
190
|
+
if(globalThis.window?.user) return globalThis.window.user;
|
|
191
|
+
const {default:UserEntity}=await import('../entities/User.js');
|
|
192
|
+
return new UserEntity();
|
|
200
193
|
}
|
|
201
194
|
|
|
202
195
|
function declaredApplicationId(document=globalThis.document){
|
|
203
|
-
const
|
|
204
|
-
return
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function declaredMailBaseDomain(document=globalThis.document){
|
|
208
|
-
return normalizeBaseDomain(
|
|
209
|
-
document?.querySelector?.('meta[name="arcane-mail-base-domain"]')?.content,
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function normalizeBaseDomain(value){
|
|
214
|
-
const domain=String(value||'').trim().toLowerCase();
|
|
215
|
-
if(!domain||domain.length>253
|
|
216
|
-
|| !/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(domain)){
|
|
217
|
-
return '';
|
|
218
|
-
}
|
|
219
|
-
return domain;
|
|
196
|
+
const appName=document?.querySelector?.('meta[name="arcane-app-id"]')?.content;
|
|
197
|
+
return is.string(appName)?appName:'';
|
|
220
198
|
}
|
|
221
199
|
|
|
222
|
-
function
|
|
223
|
-
const configured=normalizeBaseDomain(configuredBaseDomain);
|
|
224
|
-
return configured&&(hostname===configured||hostname.endsWith(`.${configured}`)) ? configured:'';
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function defaultMailEndpoint(location=globalThis.location,baseDomain=''){
|
|
200
|
+
function defaultMailEndpoint(location=globalThis.location){
|
|
228
201
|
if(!location||!['http:','https:'].includes(location.protocol)){
|
|
229
202
|
return '';
|
|
230
203
|
}
|
|
231
|
-
|
|
232
|
-
const loopback=['localhost','127.0.0.1','::1','[::1]'].includes(hostname);
|
|
233
|
-
if(loopback&&location.protocol==='http:'&&String(location.port||'')!=='8025'){
|
|
234
|
-
const authority=hostname==='::1' ? '[::1]':hostname;
|
|
235
|
-
return `http://${authority}:8025/v1/mail`;
|
|
236
|
-
}
|
|
237
|
-
if(loopback){
|
|
238
|
-
return new URL('/v1/mail',location.origin).href;
|
|
239
|
-
}
|
|
240
|
-
const root=hostedBaseDomain(hostname,baseDomain);
|
|
241
|
-
if(!root){
|
|
242
|
-
return '';
|
|
243
|
-
}
|
|
244
|
-
return `https://mail.${root}/v1/mail`;
|
|
204
|
+
return new URL('/v1/mail',location.origin).href;
|
|
245
205
|
}
|
|
246
206
|
|
|
247
207
|
export function resolveMailConfig(
|
|
@@ -249,19 +209,19 @@ export function resolveMailConfig(
|
|
|
249
209
|
{document=globalThis.document,location=globalThis.location}={}
|
|
250
210
|
){
|
|
251
211
|
const supplied=config&&is.object(config)&&!is.array(config)?config:{};
|
|
252
|
-
const appName=is.string(supplied.appName)
|
|
253
|
-
? supplied.appName
|
|
212
|
+
const appName=is.string(supplied.appName)
|
|
213
|
+
? supplied.appName
|
|
254
214
|
: declaredApplicationId(document);
|
|
255
|
-
return
|
|
256
|
-
appName
|
|
257
|
-
|
|
258
|
-
endpoint:is.string(supplied.endpoint)
|
|
259
|
-
? supplied.endpoint
|
|
260
|
-
: defaultMailEndpoint(location
|
|
215
|
+
return {
|
|
216
|
+
appName,
|
|
217
|
+
subscriptionKey:supplied.subscriptionKey,
|
|
218
|
+
endpoint:is.string(supplied.endpoint)
|
|
219
|
+
? supplied.endpoint
|
|
220
|
+
: defaultMailEndpoint(location),
|
|
261
221
|
requestTimeout:is.finite(supplied.requestTimeout)
|
|
262
222
|
? supplied.requestTimeout
|
|
263
223
|
: null,
|
|
264
|
-
}
|
|
224
|
+
};
|
|
265
225
|
}
|
|
266
226
|
|
|
267
227
|
function escapeHtml(value){
|
|
@@ -384,12 +344,12 @@ function publicSendResult(record){
|
|
|
384
344
|
}
|
|
385
345
|
|
|
386
346
|
function safeDrainDetail(summary){
|
|
387
|
-
return
|
|
347
|
+
return {
|
|
388
348
|
...summary,
|
|
389
349
|
records:[...summary.records],
|
|
390
350
|
invalidRecords:[...summary.invalidRecords],
|
|
391
|
-
states:
|
|
392
|
-
}
|
|
351
|
+
states:{...summary.states}
|
|
352
|
+
};
|
|
393
353
|
}
|
|
394
354
|
|
|
395
355
|
function normalizeMailOptions(options){
|
|
@@ -505,7 +465,7 @@ class Mail {
|
|
|
505
465
|
);
|
|
506
466
|
}
|
|
507
467
|
this.appName=resolved.appName;
|
|
508
|
-
this.
|
|
468
|
+
this.subscriptionKey=resolved.subscriptionKey;
|
|
509
469
|
this.endpoint=resolved.endpoint;
|
|
510
470
|
this.requestTimeout=resolved.requestTimeout;
|
|
511
471
|
this.#storageInjected=options.storageInjected;
|
|
@@ -599,8 +559,19 @@ class Mail {
|
|
|
599
559
|
async #transportDelivery(request){
|
|
600
560
|
if(this.#deliver) return this.#deliver(request);
|
|
601
561
|
if(this.endpoint){
|
|
562
|
+
throwIfMailAborted(request.signal);
|
|
563
|
+
let subscriptionKey=this.subscriptionKey;
|
|
564
|
+
if(subscriptionKey===undefined){
|
|
565
|
+
const user=await resolveMailUserEntity(this.#user);
|
|
566
|
+
throwIfMailAborted(request.signal);
|
|
567
|
+
if(is.function(user?.load)){
|
|
568
|
+
await waitForMailOperation(user.load(),request.signal);
|
|
569
|
+
}
|
|
570
|
+
subscriptionKey=user?.subscription_key;
|
|
571
|
+
}
|
|
572
|
+
throwIfMailAborted(request.signal);
|
|
602
573
|
return sendMailReport({
|
|
603
|
-
|
|
574
|
+
subscriptionKey,
|
|
604
575
|
appName:this.appName,
|
|
605
576
|
endpoint:this.endpoint,
|
|
606
577
|
report:request.report,
|
|
@@ -697,7 +668,7 @@ class Mail {
|
|
|
697
668
|
async #optionalProfile(){
|
|
698
669
|
const fallback={email:'',language:'',phone:'',username:''};
|
|
699
670
|
try{
|
|
700
|
-
const user=await
|
|
671
|
+
const user=await resolveMailUserEntity(this.#user);
|
|
701
672
|
if(!user) return fallback;
|
|
702
673
|
try{
|
|
703
674
|
await user.load?.();
|
|
@@ -176,8 +176,8 @@ function normalizedFailure(value){
|
|
|
176
176
|
if(!isPlainRecord(value)){
|
|
177
177
|
fail('Mail outbox failure record is invalid.','MAIL_OUTBOX_RECORD_INVALID');
|
|
178
178
|
}
|
|
179
|
-
const code=
|
|
180
|
-
if(!code||!is.boolean(value.retryable)||!is.boolean(value.uncertain)){
|
|
179
|
+
const code=value.code;
|
|
180
|
+
if(!is.string(code)||!code||!is.boolean(value.retryable)||!is.boolean(value.uncertain)){
|
|
181
181
|
fail('Mail outbox failure record is invalid.','MAIL_OUTBOX_RECORD_INVALID');
|
|
182
182
|
}
|
|
183
183
|
return {
|
|
@@ -211,12 +211,12 @@ function normalizedResult(value,{invalidCode='MAIL_OUTBOX_RECORD_INVALID'}={}){
|
|
|
211
211
|
classification:safeString(value.classification,SAFE_CODE_PATTERN),
|
|
212
212
|
acceptanceAuthority,
|
|
213
213
|
requestId:safeString(value.requestId,SAFE_ID_PATTERN),
|
|
214
|
-
providerId:
|
|
214
|
+
providerId:is.string(value.providerId)?value.providerId:null,
|
|
215
215
|
providerStatus:is.string(value.providerStatus)
|
|
216
216
|
||is.safeInteger(value.providerStatus)
|
|
217
217
|
?value.providerStatus
|
|
218
218
|
:null,
|
|
219
|
-
providerCode:
|
|
219
|
+
providerCode:is.string(value.providerCode)?value.providerCode:null,
|
|
220
220
|
statusCode:safeStatusCode(value.statusCode),
|
|
221
221
|
retryAfterSeconds:retryAfterSeconds(value.retryAfterSeconds)
|
|
222
222
|
};
|
|
@@ -451,7 +451,7 @@ function deliveryFailure(error){
|
|
|
451
451
|
name:is.string(error?.name)?error.name:'Error',
|
|
452
452
|
message:is.string(error?.message)?error.message:String(error??''),
|
|
453
453
|
...(is.string(error?.stack)?{stack:error.stack}:{}),
|
|
454
|
-
code:
|
|
454
|
+
code:is.string(error?.code)&&error.code?error.code:'MAIL_DELIVERY_FAILED',
|
|
455
455
|
statusCode:safeStatusCode(error?.statusCode),
|
|
456
456
|
retryable,
|
|
457
457
|
uncertain,
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import Is from 'strong-type';
|
|
2
2
|
const is=new Is(false);
|
|
3
3
|
|
|
4
|
-
const REPORT_KEY_PATTERN=/^[a-zA-Z0-9._:-]+$/;
|
|
5
4
|
const REQUEST_ID_PATTERN=/^[a-zA-Z0-9-]+$/;
|
|
6
|
-
const PROVIDER_ID_PATTERN=/^[a-zA-Z0-9._:-]+$/;
|
|
7
|
-
const ERROR_CODE_PATTERN=/^[a-zA-Z0-9._:-]+$/;
|
|
8
5
|
const RETRYABLE_STATUS_CODES=new Set([408,425,429,500,502,503,504]);
|
|
9
6
|
const NON_RETRYABLE_RATE_CODES=new Set(['daily_quota_exceeded','monthly_quota_exceeded']);
|
|
10
7
|
const RESPONSE_CONTRACT={
|
|
@@ -39,12 +36,8 @@ export function normalizeMailEndpoint(endpoint,base=globalThis.location?.href){
|
|
|
39
36
|
}catch{
|
|
40
37
|
throw new Error('Mail endpoint is invalid');
|
|
41
38
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
throw new Error('Mail endpoint must use HTTPS or loopback HTTP');
|
|
45
|
-
}
|
|
46
|
-
if(url.username||url.password||url.search||url.hash){
|
|
47
|
-
throw new Error('Mail endpoint must not contain credentials, a query, or a fragment');
|
|
39
|
+
if(url.protocol!=='https:'&&url.protocol!=='http:'){
|
|
40
|
+
throw new Error('Mail endpoint must use HTTP or HTTPS');
|
|
48
41
|
}
|
|
49
42
|
return url.href;
|
|
50
43
|
}
|
|
@@ -125,7 +118,7 @@ function parseDeliveryResponse(response,responseText){
|
|
|
125
118
|
}
|
|
126
119
|
}
|
|
127
120
|
if(body.providerId!==undefined
|
|
128
|
-
&& (!is.string(body.providerId)||!
|
|
121
|
+
&& (!is.string(body.providerId)||!body.providerId)){
|
|
129
122
|
throw invalidSuccessResponse(response,responseText);
|
|
130
123
|
}
|
|
131
124
|
|
|
@@ -150,7 +143,7 @@ function parseRejection(response,responseText){
|
|
|
150
143
|
? body.error
|
|
151
144
|
: body;
|
|
152
145
|
const rawCode=source?.code;
|
|
153
|
-
const code=is.string(rawCode)
|
|
146
|
+
const code=is.string(rawCode)
|
|
154
147
|
? rawCode
|
|
155
148
|
: `MAIL_HTTP_${String(response.status)}`;
|
|
156
149
|
let retryable=is.boolean(source?.retryable)
|
|
@@ -218,7 +211,7 @@ function requestBodyFrom({report,serializedReport}){
|
|
|
218
211
|
}
|
|
219
212
|
|
|
220
213
|
export async function sendMailReport({
|
|
221
|
-
|
|
214
|
+
subscriptionKey,
|
|
222
215
|
appName,
|
|
223
216
|
endpoint,
|
|
224
217
|
fetchImpl=globalThis.fetch,
|
|
@@ -232,18 +225,18 @@ export async function sendMailReport({
|
|
|
232
225
|
throw new MailTransportError('Mail transport is unavailable',{code:'MAIL_UNAVAILABLE'});
|
|
233
226
|
}
|
|
234
227
|
const resolvedEndpoint=normalizeMailEndpoint(endpoint);
|
|
235
|
-
if(!is.string(appName)
|
|
236
|
-
throw new Error('Mail application
|
|
228
|
+
if(!is.string(appName)||!appName){
|
|
229
|
+
throw new Error('Mail application name is required');
|
|
237
230
|
}
|
|
238
|
-
if(!is.string(reportKey)||!
|
|
239
|
-
throw new Error('Mail report key
|
|
231
|
+
if(!is.string(reportKey)||!reportKey){
|
|
232
|
+
throw new Error('Mail report key is required');
|
|
240
233
|
}
|
|
241
234
|
if(requestTimeout!==null&&requestTimeout!==undefined
|
|
242
235
|
&&(!is.safeInteger(requestTimeout)||requestTimeout<1)){
|
|
243
236
|
throw new Error('Mail request timeout must be a positive integer');
|
|
244
237
|
}
|
|
245
|
-
if(
|
|
246
|
-
throw new
|
|
238
|
+
if(subscriptionKey!==undefined&&subscriptionKey!==null&&!is.string(subscriptionKey)){
|
|
239
|
+
throw new TypeError('Mail subscription key must be a string');
|
|
247
240
|
}
|
|
248
241
|
if(signal!==undefined&&!(signal instanceof AbortSignal)){
|
|
249
242
|
throw new TypeError('Mail signal must be an AbortSignal');
|
|
@@ -255,9 +248,7 @@ export async function sendMailReport({
|
|
|
255
248
|
'Idempotency-Key':reportKey,
|
|
256
249
|
'X-Mail-App':appName,
|
|
257
250
|
};
|
|
258
|
-
if(
|
|
259
|
-
headers['X-Mail-Key']=appKey;
|
|
260
|
-
}
|
|
251
|
+
if(subscriptionKey)headers.Authorization=`Bearer ${subscriptionKey}`;
|
|
261
252
|
|
|
262
253
|
const controller=new AbortController();
|
|
263
254
|
let timedOut=false;
|
package/src/cli/main.mjs
CHANGED
|
@@ -46,7 +46,6 @@ const FLAG_OPTIONS=new Set([
|
|
|
46
46
|
'require-local-ai',
|
|
47
47
|
'overwrite',
|
|
48
48
|
'secret-stdin',
|
|
49
|
-
'app-key-stdin',
|
|
50
49
|
'report-stdin',
|
|
51
50
|
'help',
|
|
52
51
|
'version'
|
|
@@ -85,8 +84,8 @@ Usage:
|
|
|
85
84
|
${CLI_NAME} mail key set <profile> [--secret-stdin]
|
|
86
85
|
${CLI_NAME} mail key status <profile>
|
|
87
86
|
${CLI_NAME} mail key delete <profile>
|
|
88
|
-
${CLI_NAME} mail send --profile <profile> --from <address> --report-key <id> --report-stdin [--request-timeout <ms>]
|
|
89
|
-
${CLI_NAME} mail serve --profile <profile> --from <address> --app <
|
|
87
|
+
${CLI_NAME} mail send --profile <profile> [--from <address>] --report-key <id> --report-stdin [--request-timeout <ms>]
|
|
88
|
+
${CLI_NAME} mail serve --profile <profile> [--from <address>] [--app <label>] [--origin <origin>] [--allow-to <addresses>] [--host 0.0.0.0] [--port 8025] [--request-timeout <ms>]
|
|
90
89
|
|
|
91
90
|
Development:
|
|
92
91
|
--public Bind dev to all IPv4 interfaces (0.0.0.0) and print network URLs.
|
|
@@ -190,7 +189,7 @@ function readPort(value,defaultValue){
|
|
|
190
189
|
return port;
|
|
191
190
|
}
|
|
192
191
|
|
|
193
|
-
function
|
|
192
|
+
function readMailRequestTimeout(value){
|
|
194
193
|
if(value===undefined)return undefined;
|
|
195
194
|
if(!/^\d+$/u.test(value)){
|
|
196
195
|
usage(`Invalid request timeout: ${value}.`);
|
|
@@ -205,7 +204,7 @@ function readRequestTimeout(value){
|
|
|
205
204
|
return timeout;
|
|
206
205
|
}
|
|
207
206
|
|
|
208
|
-
function
|
|
207
|
+
function normalizeMailCredentialInput(value){
|
|
209
208
|
const secret=String(value??'').trim();
|
|
210
209
|
if(!secret){
|
|
211
210
|
usage('Mail credential input must not be empty.');
|
|
@@ -235,7 +234,7 @@ function readPipedMailSecret(input,signal){
|
|
|
235
234
|
};
|
|
236
235
|
const onEnd=function finishPipedMailSecret(){
|
|
237
236
|
try{
|
|
238
|
-
finish(resolve,
|
|
237
|
+
finish(resolve,normalizeMailCredentialInput(Buffer.concat(chunks).toString('utf8')));
|
|
239
238
|
}catch(error){
|
|
240
239
|
finish(reject,error);
|
|
241
240
|
}
|
|
@@ -304,7 +303,7 @@ function readMaskedMailSecret(input,output,signal,label,stdinOption){
|
|
|
304
303
|
}
|
|
305
304
|
if(character==='\r'||character==='\n'){
|
|
306
305
|
try{
|
|
307
|
-
finish(resolve,
|
|
306
|
+
finish(resolve,normalizeMailCredentialInput(secret));
|
|
308
307
|
}catch(error){
|
|
309
308
|
finish(reject,error);
|
|
310
309
|
}
|
|
@@ -500,9 +499,6 @@ function operationOptions(command,parsed,cwd){
|
|
|
500
499
|
if(command!=='mail'&&flags.has('secret-stdin')){
|
|
501
500
|
usage('--secret-stdin is supported only by mail key set.');
|
|
502
501
|
}
|
|
503
|
-
if(command!=='mail'&&flags.has('app-key-stdin')){
|
|
504
|
-
usage('--app-key-stdin is supported only by mail serve.');
|
|
505
|
-
}
|
|
506
502
|
if(command!=='mail'&&flags.has('report-stdin')){
|
|
507
503
|
usage('--report-stdin is supported only by mail send.');
|
|
508
504
|
}
|
|
@@ -674,9 +670,6 @@ function operationOptions(command,parsed,cwd){
|
|
|
674
670
|
if(flags.has('secret-stdin')&&action!=='set'){
|
|
675
671
|
usage('--secret-stdin is supported only by mail key set.');
|
|
676
672
|
}
|
|
677
|
-
if(flags.has('app-key-stdin')){
|
|
678
|
-
usage('--app-key-stdin is supported only by mail serve.');
|
|
679
|
-
}
|
|
680
673
|
if(flags.has('report-stdin')){
|
|
681
674
|
usage('--report-stdin is supported only by mail send.');
|
|
682
675
|
}
|
|
@@ -694,14 +687,7 @@ function operationOptions(command,parsed,cwd){
|
|
|
694
687
|
if(flags.has('report-stdin')||values['report-key']!==undefined){
|
|
695
688
|
usage('--report-stdin and --report-key are supported only by mail send.');
|
|
696
689
|
}
|
|
697
|
-
|
|
698
|
-
profile:values.profile,
|
|
699
|
-
from:values.from,
|
|
700
|
-
app:values.app,
|
|
701
|
-
origin:values.origin
|
|
702
|
-
})){
|
|
703
|
-
if(!value)usage(`mail serve requires --${name} <value>.`);
|
|
704
|
-
}
|
|
690
|
+
if(!values.profile)usage('mail serve requires --profile <value>.');
|
|
705
691
|
return {
|
|
706
692
|
action:'serve',
|
|
707
693
|
profile:values.profile,
|
|
@@ -709,15 +695,14 @@ function operationOptions(command,parsed,cwd){
|
|
|
709
695
|
appId:values.app,
|
|
710
696
|
origin:values.origin,
|
|
711
697
|
allowTo:values['allow-to'],
|
|
712
|
-
|
|
713
|
-
host:values.host??'127.0.0.1',
|
|
698
|
+
host:values.host??'0.0.0.0',
|
|
714
699
|
port:readPort(values.port,8025),
|
|
715
|
-
requestTimeout:
|
|
700
|
+
requestTimeout:readMailRequestTimeout(values['request-timeout']),
|
|
716
701
|
};
|
|
717
702
|
}
|
|
718
703
|
if(area==='send'){
|
|
719
704
|
noExtraPositionals(command,positionals,1);
|
|
720
|
-
if(flags.has('secret-stdin')
|
|
705
|
+
if(flags.has('secret-stdin')){
|
|
721
706
|
usage('mail send accepts report input only through --report-stdin.');
|
|
722
707
|
}
|
|
723
708
|
if(values.app!==undefined||values.origin!==undefined
|
|
@@ -727,7 +712,6 @@ function operationOptions(command,parsed,cwd){
|
|
|
727
712
|
}
|
|
728
713
|
for(const [name,value]of Object.entries({
|
|
729
714
|
profile:values.profile,
|
|
730
|
-
from:values.from,
|
|
731
715
|
'report-key':values['report-key'],
|
|
732
716
|
})){
|
|
733
717
|
if(!value)usage(`mail send requires --${name} <value>.`);
|
|
@@ -741,7 +725,7 @@ function operationOptions(command,parsed,cwd){
|
|
|
741
725
|
from:values.from,
|
|
742
726
|
reportKey:values['report-key'],
|
|
743
727
|
reportStdin:true,
|
|
744
|
-
requestTimeout:
|
|
728
|
+
requestTimeout:readMailRequestTimeout(values['request-timeout']),
|
|
745
729
|
};
|
|
746
730
|
}
|
|
747
731
|
usage('mail requires key set|status|delete <profile>, send, or serve.');
|
|
@@ -879,10 +863,8 @@ function serverSummary(result){
|
|
|
879
863
|
...(result.httpOrigin===undefined?{}:{httpOrigin:result.httpOrigin}),
|
|
880
864
|
...(result.httpUrl===undefined?{}:{httpUrl:result.httpUrl}),
|
|
881
865
|
...(result.protocol===undefined?{}:{protocol:result.protocol}),
|
|
866
|
+
...(result.callerAuthentication===undefined?{}:{callerAuthentication:result.callerAuthentication}),
|
|
882
867
|
...(result.networkUrls===undefined?{}:{networkUrls:result.networkUrls}),
|
|
883
|
-
...(result.callerAuthentication
|
|
884
|
-
?{callerAuthentication:result.callerAuthentication}
|
|
885
|
-
:{}),
|
|
886
868
|
...(result.runtimeMode?{runtimeMode:result.runtimeMode}:{}),
|
|
887
869
|
...(result.runtime?{runtime:result.runtime}:{}),
|
|
888
870
|
...(result.verified?{verified:result.verified}:{})
|
|
@@ -891,7 +873,8 @@ function serverSummary(result){
|
|
|
891
873
|
|
|
892
874
|
async function waitForServer(result,signal,reporter){
|
|
893
875
|
const readyMessage=[
|
|
894
|
-
|
|
876
|
+
`${result.target==='mail'?'Mail':'Development'} server ready at ${result.url}`,
|
|
877
|
+
...(result.target==='mail'?[`Subscription verification: ${result.callerAuthentication==='subscription'?'configured':'disabled'}`]:[]),
|
|
895
878
|
...(result.httpUrl && result.protocol !== 'http:' ? [`HTTP redirect: ${result.httpUrl}`] : []),
|
|
896
879
|
...(result.networkUrls??[]).map(function networkAddress(url){return `Network: ${url}`;})
|
|
897
880
|
].join('\n');
|
|
@@ -984,21 +967,6 @@ export async function runCli(argv=process.argv.slice(2),{
|
|
|
984
967
|
});
|
|
985
968
|
};
|
|
986
969
|
}
|
|
987
|
-
if(command==='mail'&&operation.action==='serve'){
|
|
988
|
-
operation.readAppKey=function readMailGatewayAppKeyForOperation(){
|
|
989
|
-
if(reporter.output!=='human'&&!operation.appKeyStdin){
|
|
990
|
-
usage('Structured output requires mail serve --app-key-stdin.');
|
|
991
|
-
}
|
|
992
|
-
return readMailSecretInput({
|
|
993
|
-
input:stdin,
|
|
994
|
-
output:stderr,
|
|
995
|
-
secretStdin:operation.appKeyStdin,
|
|
996
|
-
signal:controller.signal,
|
|
997
|
-
label:'Mail gateway app key',
|
|
998
|
-
stdinOption:'--app-key-stdin',
|
|
999
|
-
});
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
970
|
if(command==='mail'&&operation.action==='send'){
|
|
1003
971
|
operation.readReport=function readMailReportForOperation(){
|
|
1004
972
|
return readMailReportInput({
|