w-web-api 1.0.52 → 1.0.53

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 (84) hide show
  1. package/_gh-pages-deploy/.nojekyll +0 -0
  2. package/_gh-pages-deploy/WWebApi.html +898 -0
  3. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  4. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  5. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  6. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  7. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  8. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  9. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  10. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  11. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  12. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  13. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  14. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  15. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  16. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  17. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  18. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  19. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  20. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  21. package/_gh-pages-deploy/index.html +84 -0
  22. package/_gh-pages-deploy/scripts/collapse.js +39 -0
  23. package/_gh-pages-deploy/scripts/commonNav.js +28 -0
  24. package/_gh-pages-deploy/scripts/linenumber.js +25 -0
  25. package/_gh-pages-deploy/scripts/nav.js +12 -0
  26. package/_gh-pages-deploy/scripts/polyfill.js +4 -0
  27. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
  28. package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
  29. package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
  30. package/_gh-pages-deploy/scripts/search.js +99 -0
  31. package/{docs/WWebApi.mjs.html → _gh-pages-deploy/server_WWebApi.mjs.html} +96 -39
  32. package/_gh-pages-deploy/src_components_Common_CheckYesNo.vue.html +187 -0
  33. package/_gh-pages-deploy/styles/jsdoc.css +776 -0
  34. package/_gh-pages-deploy/styles/prettify.css +80 -0
  35. package/dist/css/app.fe69497a.css +1 -0
  36. package/dist/index.tmp +4 -2
  37. package/dist/js/app-legacy.15819aa7.js +1 -0
  38. package/dist/js/app.15819aa7.js +1 -0
  39. package/dist/js/chunk-vendors-legacy.c1a32dd1.js +15 -0
  40. package/dist/js/chunk-vendors.c1a32dd1.js +15 -0
  41. package/dist/w-web-api.umd.js +2 -2
  42. package/dist/w-web-api.umd.js.map +1 -1
  43. package/docs/WWebApi.html +2 -2
  44. package/docs/index.html +1 -1
  45. package/docs/server_WWebApi.mjs.html +1012 -0
  46. package/docs/src_components_Common_CheckYesNo.vue.html +187 -0
  47. package/g.getSettings.mjs +3 -0
  48. package/package.json +15 -11
  49. package/public/index.html +9 -2
  50. package/server/WWebApi.mjs +93 -36
  51. package/server/procApis.mjs +62 -0
  52. package/server/procLang.mjs +386 -0
  53. package/server/procProxy.mjs +120 -0
  54. package/server/srLog.mjs +30 -0
  55. package/server/staLogs/staEvent.mjs +129 -0
  56. package/server/staLogs/test_staEvent.mjs +132 -0
  57. package/settings.json +14 -0
  58. package/src/App.vue +11 -7
  59. package/src/assets/scalar-ui.css +113 -0
  60. package/src/components/Common/CheckYes.vue +102 -0
  61. package/src/components/Common/CheckYesNo.vue +115 -0
  62. package/src/components/Common/LoadingWinBar.vue +114 -0
  63. package/src/components/Layout.vue +8 -7
  64. package/src/components/LayoutContent.vue +308 -333
  65. package/src/components/LayoutContentEdit.vue +577 -0
  66. package/src/components/LayoutContentStats.vue +485 -0
  67. package/src/components/LayoutContentTest.vue +799 -0
  68. package/src/components/MdPanel.vue +80 -58
  69. package/src/main.js +8 -0
  70. package/src/plugins/mUI.mjs +19 -4
  71. package/src/schema/tables/apis.mjs +30 -0
  72. package/srv.mjs +47 -19
  73. package/tableTags.json +1 -1
  74. package/.github/workflows/ci-test.yml +0 -24
  75. package/.vscode/launch.json +0 -18
  76. package/db/wapis/apis/data.mdb +0 -0
  77. package/db/wapis/apis/lock.mdb +0 -0
  78. package/dist/css/app.b5cf2ef5.css +0 -1
  79. package/dist/js/app-legacy.927b5679.js +0 -1
  80. package/dist/js/app.927b5679.js +0 -1
  81. package/dist/js/chunk-vendors-legacy.ffb0c6c5.js +0 -13
  82. package/dist/js/chunk-vendors.ffb0c6c5.js +0 -13
  83. package/tableTags-web-api.json +0 -1
  84. package/test/all.test.mjs +0 -10
@@ -0,0 +1,62 @@
1
+ import iseobj from 'wsemi/src/iseobj.mjs'
2
+ import isestr from 'wsemi/src/isestr.mjs'
3
+
4
+
5
+ function procApis(deps = {}) {
6
+
7
+ //deps
8
+ let { woItems, procOrm, ds } = deps
9
+
10
+
11
+ let getApisList = async (userId) => {
12
+ return await woItems.apis.select({})
13
+ }
14
+
15
+
16
+ let saveApi = async (userId, row) => {
17
+
18
+ //check(reject err-key,由前端依 lang 反查顯示;邊界 kpFunExt 會 srLog 此 key)
19
+ if (!iseobj(row)) {
20
+ return Promise.reject('errApiRowInvalid')
21
+ }
22
+
23
+ //正規化:funNew 配 id/時間/預設並過濾欄位
24
+ let o = ds.apis.funNew(row)
25
+
26
+ //保留原 id 與創建時間(既有筆)
27
+ if (isestr(row.id)) {
28
+ o.id = row.id
29
+ if (isestr(row.timeCreate)) {
30
+ o.timeCreate = row.timeCreate
31
+ }
32
+ }
33
+
34
+ //save
35
+ let r = await procOrm(userId, 'apis', 'save', [o])
36
+
37
+ return r
38
+ }
39
+
40
+
41
+ let deleteApi = async (userId, id) => {
42
+
43
+ //check(reject err-key,由前端依 lang 反查顯示)
44
+ if (!isestr(id)) {
45
+ return Promise.reject('errApiIdInvalid')
46
+ }
47
+
48
+ let r = await procOrm(userId, 'apis', 'del', { id })
49
+
50
+ return r
51
+ }
52
+
53
+
54
+ return {
55
+ getApisList,
56
+ saveApi,
57
+ deleteApi,
58
+ }
59
+ }
60
+
61
+
62
+ export default procApis
@@ -247,6 +247,392 @@ let kpLang = {
247
247
  cht: '原始數據',
248
248
  },
249
249
 
250
+ //--- API 管理(展示/編輯/測試)---
251
+
252
+ docInput: {
253
+ eng: 'Input',
254
+ cht: '輸入參數',
255
+ },
256
+ docOutputFields: {
257
+ eng: 'Output fields',
258
+ cht: '回傳欄位',
259
+ },
260
+ docRequest: {
261
+ eng: 'Request',
262
+ cht: '請求',
263
+ },
264
+
265
+ tabDocs: {
266
+ eng: 'Docs',
267
+ cht: '文件',
268
+ },
269
+ tabEdit: {
270
+ eng: 'Edit',
271
+ cht: '編輯',
272
+ },
273
+ tabTest: {
274
+ eng: 'Test',
275
+ cht: '測試',
276
+ },
277
+
278
+ //左側垂直主選單
279
+ mmApi: {
280
+ eng: 'API',
281
+ cht: 'API',
282
+ },
283
+ mmStaInfor: {
284
+ eng: 'Statistics',
285
+ cht: '統計資訊',
286
+ },
287
+
288
+ //統計資訊頁
289
+ statisticsInformation: {
290
+ eng: 'Statistics Information',
291
+ cht: '統計資訊',
292
+ },
293
+ statisticsInformationDescription: {
294
+ eng: 'Frequency of backend logged events (APIs, kpFunExt, connection verification).',
295
+ cht: '後端各事件(API、kpFunExt、連線驗證)之發生頻率統計。',
296
+ },
297
+ eventFrequency: {
298
+ eng: 'Event Frequency',
299
+ cht: '事件發生頻率',
300
+ },
301
+ showIndividually: {
302
+ eng: 'Show individually',
303
+ cht: '個別顯示',
304
+ },
305
+ selectEvents: {
306
+ eng: 'Select events',
307
+ cht: '選擇事件',
308
+ },
309
+ selectAll: {
310
+ eng: 'All',
311
+ cht: '全選',
312
+ },
313
+ selectNone: {
314
+ eng: 'Clear',
315
+ cht: '清除',
316
+ },
317
+ eventStatsTable: {
318
+ eng: 'Event Statistics',
319
+ cht: '事件統計表',
320
+ },
321
+ colEvent: {
322
+ eng: 'Event',
323
+ cht: '事件',
324
+ },
325
+ colRecent1day: {
326
+ eng: 'Last 1 day',
327
+ cht: '最近1日',
328
+ },
329
+ colRecent8hr: {
330
+ eng: 'Last 8 hr',
331
+ cht: '最近8時',
332
+ },
333
+ colRecent4hr: {
334
+ eng: 'Last 4 hr',
335
+ cht: '最近4時',
336
+ },
337
+ colRecent1hr: {
338
+ eng: 'Last 1 hr',
339
+ cht: '最近1時',
340
+ },
341
+ countTotal: {
342
+ eng: 'Total',
343
+ cht: '總次數',
344
+ },
345
+ timeRange: {
346
+ eng: 'Time range',
347
+ cht: '時間範圍',
348
+ },
349
+ selectItem1hr: {
350
+ eng: '1 hour',
351
+ cht: '1小時',
352
+ },
353
+ selectItem4hr: {
354
+ eng: '4 hours',
355
+ cht: '4小時',
356
+ },
357
+ selectItem8hr: {
358
+ eng: '8 hours',
359
+ cht: '8小時',
360
+ },
361
+ selectItem1day: {
362
+ eng: '1 day',
363
+ cht: '1天',
364
+ },
365
+ noStaData: {
366
+ eng: 'No statistics data',
367
+ cht: '尚無統計資料',
368
+ },
369
+ getDataError: {
370
+ eng: 'Failed to get data',
371
+ cht: '取得資料失敗',
372
+ },
373
+
374
+ addApi: {
375
+ eng: 'New API',
376
+ cht: '新增API',
377
+ },
378
+ editApiTitle: {
379
+ eng: 'Edit API',
380
+ cht: '編輯API',
381
+ },
382
+ confirmDeleteApi: {
383
+ eng: 'Are you sure you want to delete this API?',
384
+ cht: '確定要刪除此API?',
385
+ },
386
+ saveSuccess: {
387
+ eng: 'Saved',
388
+ cht: '已儲存',
389
+ },
390
+ deleteSuccess: {
391
+ eng: 'Deleted',
392
+ cht: '已刪除',
393
+ },
394
+ searchApiPlaceholder: {
395
+ eng: 'Search API...',
396
+ cht: '搜尋API...',
397
+ },
398
+
399
+ fieldMethod: {
400
+ eng: 'Method',
401
+ cht: '方法',
402
+ },
403
+ fieldGroup: {
404
+ eng: 'Group',
405
+ cht: '群組',
406
+ },
407
+ fieldOrder: {
408
+ eng: 'Order',
409
+ cht: '順序',
410
+ },
411
+ fieldTestBaseUrl: {
412
+ eng: 'Test base URL',
413
+ cht: '測試基底網址',
414
+ },
415
+ fieldAuthType: {
416
+ eng: 'Auth type',
417
+ cht: '認證類型',
418
+ },
419
+ fieldAuthConfigJson: {
420
+ eng: 'Auth config (JSON)',
421
+ cht: '認證設定(JSON)',
422
+ },
423
+ fieldDefaultHeadersJson: {
424
+ eng: 'Default headers (JSON)',
425
+ cht: '預設標頭(JSON)',
426
+ },
427
+ fieldDefaultQueryJson: {
428
+ eng: 'Default query (JSON)',
429
+ cht: '預設查詢參數(JSON)',
430
+ },
431
+ fieldDefaultBodyJson: {
432
+ eng: 'Default body (JSON)',
433
+ cht: '預設請求內容(JSON)',
434
+ },
435
+ fieldContentType: {
436
+ eng: 'Content type',
437
+ cht: '內容類型',
438
+ },
439
+
440
+ hintTestBaseUrl: {
441
+ eng: 'Fallback request URL, used only when API url is empty. e.g. https://api.example.com',
442
+ cht: '送請求的後備網址:「API url」有填則優先,留空時才用此值。範例:https://api.example.com',
443
+ },
444
+ hintAuthType: {
445
+ eng: 'Auth auto-applied when sending. none = none; bearer / apikey / basic are built from the Auth config below.',
446
+ cht: '送出時自動帶入的認證方式。none=不帶;bearer / apikey / basic 依下方「認證設定(JSON)」組出。',
447
+ },
448
+ hintAuthConfigJson: {
449
+ eng: 'JSON by auth type:\nbearer → {"token":"your-token"}\napikey → {"name":"X-API-Key","value":"your-key","in":"header"} (in: header or query)\nbasic → {"username":"user","password":"pass"}',
450
+ cht: '依認證類型填 JSON:\nbearer → {"token":"你的token"}(留空則退用上方 tokens 欄第一個)\napikey → {"name":"X-API-Key","value":"你的key","in":"header"}(in 可為 header 或 query)\nbasic → {"username":"帳號","password":"密碼"}',
451
+ },
452
+ hintDefaultHeadersJson: {
453
+ eng: 'Default request headers, a JSON object. e.g. {"Accept":"application/json"}',
454
+ cht: '預設請求標頭,JSON 物件。範例:{"Accept":"application/json"}',
455
+ },
456
+ hintDefaultQueryJson: {
457
+ eng: 'Default query params, a JSON object. e.g. {"page":"1","size":"20"}',
458
+ cht: '預設查詢參數,JSON 物件。範例:{"page":"1","size":"20"}',
459
+ },
460
+ hintDefaultBodyJson: {
461
+ eng: 'Default request body (for POST/PUT); falls back to Input example if empty. e.g. {"name":"foo"}',
462
+ cht: '預設請求內容(POST/PUT 用),留空則退用「輸入範例」。範例:{"name":"小明"}',
463
+ },
464
+ hintContentType: {
465
+ eng: 'Request content type, added as a Content-Type header. e.g. application/json',
466
+ cht: '請求內容類型,會帶成 Content-Type 標頭。範例:application/json',
467
+ },
468
+
469
+ authNone: {
470
+ eng: 'None',
471
+ cht: '無',
472
+ },
473
+ authBearer: {
474
+ eng: 'Bearer token',
475
+ cht: 'Bearer token',
476
+ },
477
+ authApikey: {
478
+ eng: 'API key',
479
+ cht: 'API key',
480
+ },
481
+ authBasic: {
482
+ eng: 'Basic',
483
+ cht: 'Basic',
484
+ },
485
+
486
+ secBasic: {
487
+ eng: 'Basic',
488
+ cht: '基本資訊',
489
+ },
490
+ secDocs: {
491
+ eng: 'Documentation',
492
+ cht: '文件說明',
493
+ },
494
+ secTest: {
495
+ eng: 'Test settings',
496
+ cht: '測試設定',
497
+ },
498
+
499
+ reqSend: {
500
+ eng: 'Send',
501
+ cht: '送出請求',
502
+ },
503
+ reqUrlPlaceholder: {
504
+ eng: 'Request URL',
505
+ cht: '請求網址',
506
+ },
507
+ reqQuery: {
508
+ eng: 'Query params',
509
+ cht: '查詢參數',
510
+ },
511
+ reqHeaders: {
512
+ eng: 'Headers',
513
+ cht: '標頭',
514
+ },
515
+ reqBody: {
516
+ eng: 'Body',
517
+ cht: '請求內容',
518
+ },
519
+ reqAddRow: {
520
+ eng: 'Add',
521
+ cht: '新增一列',
522
+ },
523
+ colKey: {
524
+ eng: 'Key',
525
+ cht: '鍵',
526
+ },
527
+ colValue: {
528
+ eng: 'Value',
529
+ cht: '值',
530
+ },
531
+ colOn: {
532
+ eng: 'On',
533
+ cht: '啟用',
534
+ },
535
+
536
+ resTitle: {
537
+ eng: 'Response',
538
+ cht: '回應',
539
+ },
540
+ resStatus: {
541
+ eng: 'Status',
542
+ cht: '狀態碼',
543
+ },
544
+ resTime: {
545
+ eng: 'Time',
546
+ cht: '耗時',
547
+ },
548
+ resHeaders: {
549
+ eng: 'Response headers',
550
+ cht: '回應標頭',
551
+ },
552
+ resBody: {
553
+ eng: 'Response body',
554
+ cht: '回應內容',
555
+ },
556
+ resEmpty: {
557
+ eng: 'No response yet. Click Send to test.',
558
+ cht: '尚無回應,點擊送出請求進行測試。',
559
+ },
560
+
561
+ valRequired: {
562
+ eng: 'This field is required',
563
+ cht: '此欄位必填',
564
+ },
565
+ valInvalidJson: {
566
+ eng: 'Invalid JSON format',
567
+ cht: 'JSON格式錯誤',
568
+ },
569
+
570
+ //後端錯誤 err-key(後端 reject 此 key、srLog 此 key;前端依當前 lang 反查下列文字顯示)
571
+ errReqUrlInvalid: {
572
+ eng: 'The request URL is invalid (must start with http:// or https://)',
573
+ cht: '請求網址無效(須以 http:// 或 https:// 開頭)',
574
+ },
575
+ errReqTargetNotAllowed: {
576
+ eng: 'The target address is not allowed',
577
+ cht: '目標位址不被允許',
578
+ },
579
+ errProxyRequestFailed: {
580
+ eng: 'The request failed to send',
581
+ cht: '請求發送失敗',
582
+ },
583
+ errApiRowInvalid: {
584
+ eng: 'Invalid API data',
585
+ cht: 'API 資料無效',
586
+ },
587
+ errApiIdInvalid: {
588
+ eng: 'Invalid API id',
589
+ cht: 'API id 無效',
590
+ },
591
+ errUserIdMissing: {
592
+ eng: 'Unable to get user id',
593
+ cht: '無法取得使用者 id',
594
+ },
595
+ errUserEmailMissing: {
596
+ eng: 'Unable to get user email',
597
+ cht: '無法取得使用者 email',
598
+ },
599
+ errUserNameMissing: {
600
+ eng: 'Unable to get user name',
601
+ cht: '無法取得使用者名稱',
602
+ },
603
+ errUserRoleMissing: {
604
+ eng: 'Unable to get user role',
605
+ cht: '無法取得使用者權限',
606
+ },
607
+ errUserNoPermission: {
608
+ eng: 'User does not have permission',
609
+ cht: '使用者沒有權限',
610
+ },
611
+ errUserNotFound: {
612
+ eng: 'Unable to find user from token',
613
+ cht: '無法依 token 找到使用者',
614
+ },
615
+ errPayloadInvalid: {
616
+ eng: 'Invalid request payload',
617
+ cht: '請求內容無效',
618
+ },
619
+ errGroupInvalid: {
620
+ eng: 'Invalid group',
621
+ cht: '群組無效',
622
+ },
623
+ errRowsInvalid: {
624
+ eng: 'Invalid rows',
625
+ cht: '資料列無效',
626
+ },
627
+ errTokenNoPermission: {
628
+ eng: 'Token does not have permission',
629
+ cht: 'token 沒有權限',
630
+ },
631
+ errKeyTableInvalid: {
632
+ eng: 'Invalid table',
633
+ cht: '資料表無效',
634
+ },
635
+
250
636
  }
251
637
 
252
638
 
@@ -0,0 +1,120 @@
1
+ import get from 'lodash-es/get.js'
2
+ import isestr from 'wsemi/src/isestr.mjs'
3
+ import isobj from 'wsemi/src/isobj.mjs'
4
+ import axios from 'axios'
5
+
6
+
7
+ function procProxy(opt = {}) {
8
+
9
+ //srLog(後端 log;錯誤一律 log err-key,axios 例外另 log 真實訊息供排查)
10
+ let srLog = get(opt, 'srLog', null)
11
+
12
+ //isAllowTarget
13
+ let isAllowTarget = get(opt, 'isAllowTarget', null)
14
+
15
+
16
+ let proxyRequest = (inp = {}) => {
17
+ return new Promise(async (resolve, reject) => {
18
+
19
+ //method
20
+ let method = get(inp, 'method', 'GET')
21
+ if (!isestr(method)) {
22
+ method = 'GET'
23
+ }
24
+ method = method.toUpperCase()
25
+
26
+ //url
27
+ let url = get(inp, 'url', '')
28
+ if (!isestr(url)) {
29
+ reject('errReqUrlInvalid')
30
+ return
31
+ }
32
+ if (!url.startsWith('http://') && !url.startsWith('https://')) {
33
+ reject('errReqUrlInvalid')
34
+ return
35
+ }
36
+
37
+ //isAllowTarget check
38
+ if (typeof isAllowTarget === 'function') {
39
+ let allowed = isAllowTarget(url)
40
+ if (allowed === false) {
41
+ reject('errReqTargetNotAllowed')
42
+ return
43
+ }
44
+ }
45
+
46
+ //headers
47
+ let headers = get(inp, 'headers', {})
48
+ if (!isobj(headers)) {
49
+ headers = {}
50
+ }
51
+ //移除 host 與 content-length (交給 axios)
52
+ delete headers['host']
53
+ delete headers['Host']
54
+ delete headers['content-length']
55
+ delete headers['Content-Length']
56
+
57
+ //query
58
+ let query = get(inp, 'query', null)
59
+ let params = null
60
+ if (isobj(query) && Object.keys(query).length > 0) {
61
+ params = query
62
+ }
63
+
64
+ //body
65
+ let body = get(inp, 'body', undefined)
66
+ let data = undefined
67
+ if (method !== 'GET' && method !== 'HEAD') {
68
+ if (body !== undefined) {
69
+ data = body
70
+ }
71
+ }
72
+
73
+ //timeout
74
+ let timeout = get(inp, 'timeout', 30000)
75
+ if (typeof timeout !== 'number' || timeout <= 0) {
76
+ timeout = 30000
77
+ }
78
+
79
+ //send
80
+ let t0 = Date.now()
81
+ try {
82
+ let res = await axios({
83
+ method,
84
+ url,
85
+ headers,
86
+ params,
87
+ data,
88
+ timeout,
89
+ validateStatus: () => true,
90
+ })
91
+
92
+ let durationMs = Date.now() - t0
93
+
94
+ resolve({
95
+ status: res.status,
96
+ statusText: res.statusText,
97
+ headers: res.headers,
98
+ data: res.data,
99
+ durationMs,
100
+ })
101
+ }
102
+ catch (err) {
103
+ //axios 例外(timeout/DNS 等):log 真實訊息供排查,但回前端只給 err-key(前端依 lang 顯示)
104
+ if (srLog) {
105
+ srLog.error({ event: 'proxyRequest-axios', msg: get(err, 'message', String(err)) })
106
+ }
107
+ reject('errProxyRequestFailed')
108
+ }
109
+
110
+ })
111
+ }
112
+
113
+
114
+ return {
115
+ proxyRequest,
116
+ }
117
+ }
118
+
119
+
120
+ export default procProxy
@@ -0,0 +1,30 @@
1
+ import get from 'lodash-es/get.js'
2
+ import isestr from 'wsemi/src/isestr.mjs'
3
+ import WSyslog from 'w-syslog/src/WSyslog.mjs'
4
+
5
+
6
+ //後端 log(比照 w-web-sso server/srLog.mjs):包 w-syslog,依時段輪檔寫入 ./_logs。
7
+ //用法:srLog.info({ event, ... }) / srLog.warn({...}) / srLog.error({ event, err, ... })。
8
+ //錯誤一律 log 其 err key(對齊「後端錯誤須 log err key」原則),供事後識別。
9
+ let init = (opt = {}) => {
10
+
11
+ let fdLog = get(opt, 'logFd', '')
12
+ if (!isestr(fdLog)) {
13
+ fdLog = './_logs'
14
+ }
15
+
16
+ let interval = get(opt, 'logInterval', '')
17
+ if (!isestr(interval)) {
18
+ interval = 'hr'
19
+ }
20
+
21
+ let srLog = WSyslog({
22
+ fdLog,
23
+ interval,
24
+ })
25
+
26
+ return srLog
27
+ }
28
+
29
+
30
+ export default init