w-web-perm 1.0.48 → 1.0.49

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 (95) hide show
  1. package/.github/workflows/ci-test.yml +2 -2
  2. package/_gh-pages-deploy/.nojekyll +0 -0
  3. package/_gh-pages-deploy/WWebPerm.html +938 -0
  4. package/_gh-pages-deploy/WWebPerm.mjs.html +1228 -0
  5. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  6. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  7. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  8. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  9. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  10. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  11. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  12. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  13. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  14. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  15. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  16. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  17. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  18. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  19. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  20. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  21. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  22. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  23. package/_gh-pages-deploy/index.html +84 -0
  24. package/_gh-pages-deploy/scripts/collapse.js +39 -0
  25. package/_gh-pages-deploy/scripts/commonNav.js +28 -0
  26. package/_gh-pages-deploy/scripts/linenumber.js +25 -0
  27. package/_gh-pages-deploy/scripts/nav.js +12 -0
  28. package/_gh-pages-deploy/scripts/polyfill.js +4 -0
  29. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +202 -0
  30. package/_gh-pages-deploy/scripts/prettify/lang-css.js +2 -0
  31. package/_gh-pages-deploy/scripts/prettify/prettify.js +28 -0
  32. package/_gh-pages-deploy/scripts/search.js +99 -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.d8b16216.css +1 -0
  36. package/dist/css/{chunk-vendors.f149e124.css → chunk-vendors.2d3ef2ba.css} +1 -1
  37. package/dist/index.tmp +2 -2
  38. package/dist/js/app-legacy.fb48310a.js +1 -0
  39. package/dist/js/app.fb48310a.js +1 -0
  40. package/dist/js/chunk-vendors-legacy.8fdd4435.js +21 -0
  41. package/dist/js/chunk-vendors.8fdd4435.js +21 -0
  42. package/dist/w-web-perm.umd.js +2 -2
  43. package/dist/w-web-perm.umd.js.map +1 -1
  44. package/docs/WWebPerm.html +2 -2
  45. package/docs/WWebPerm.mjs.html +138 -199
  46. package/docs/index.html +1 -1
  47. package/package.json +15 -11
  48. package/public/index.html +2 -2
  49. package/server/WWebPerm.mjs +137 -198
  50. package/server/procCore.mjs +169 -0
  51. package/server/procLang.mjs +197 -0
  52. package/server/procStaInfor.mjs +118 -0
  53. package/server/provideTabs.mjs +1 -1
  54. package/server/srLog.mjs +30 -0
  55. package/server/staLogs/staEvent.callWorker.mjs +46 -0
  56. package/server/staLogs/staEvent.mjs +116 -0
  57. package/server/staLogs/staEvent.shellWorker.mjs +19 -0
  58. package/server/staLogs/staEventTable.mjs +100 -0
  59. package/server/staLogs/test_staEvent.mjs +22 -0
  60. package/settings.json +40 -0
  61. package/src/components/Common/CheckYes.vue +18 -1
  62. package/src/components/Layout.vue +1 -1
  63. package/src/components/LayoutContent.vue +13 -1
  64. package/src/components/LayoutContentGrups.vue +32 -23
  65. package/src/components/LayoutContentPemis.vue +32 -23
  66. package/src/components/LayoutContentStaInfor.vue +536 -0
  67. package/src/components/LayoutContentTargets.vue +32 -23
  68. package/src/components/LayoutContentUsers.vue +32 -23
  69. package/src/components/LayoutState.vue +5 -0
  70. package/src/components/VeCgrups.vue +12 -3
  71. package/src/components/VeCpemis.vue +12 -3
  72. package/src/components/VeCrules.vue +12 -3
  73. package/src/components/VeGrupBlngUsers.vue +18 -6
  74. package/src/components/VePemiBlngGrups.vue +18 -6
  75. package/src/getPerm.mjs +7 -17
  76. package/src/getPermUserInfor.mjs +8 -18
  77. package/src/main.js +1 -0
  78. package/src/plugins/mShare.mjs +8 -13
  79. package/src/plugins/mUI.mjs +11 -0
  80. package/srv.mjs +76 -101
  81. package/tableTags.json +1 -1
  82. package/db/wperm/grups/data.mdb +0 -0
  83. package/db/wperm/grups/lock.mdb +0 -0
  84. package/db/wperm/pemis/data.mdb +0 -0
  85. package/db/wperm/pemis/lock.mdb +0 -0
  86. package/db/wperm/targets/data.mdb +0 -0
  87. package/db/wperm/targets/lock.mdb +0 -0
  88. package/db/wperm/users/data.mdb +0 -0
  89. package/db/wperm/users/lock.mdb +0 -0
  90. package/dist/css/app.30e81bfe.css +0 -1
  91. package/dist/js/app-legacy.3324392e.js +0 -1
  92. package/dist/js/app.3324392e.js +0 -1
  93. package/dist/js/chunk-vendors-legacy.e8703728.js +0 -21
  94. package/dist/js/chunk-vendors.e8703728.js +0 -21
  95. package/test/getUserRules.test.mjs +0 -899
@@ -80,7 +80,7 @@
80
80
 
81
81
  <dt class="tag-source">Source:</dt>
82
82
  <dd class="tag-source"><ul class="dummy"><li>
83
- <a href="WWebPerm.mjs.html">WWebPerm.mjs</a>, <a href="WWebPerm.mjs.html#line138">line 138</a>
83
+ <a href="WWebPerm.mjs.html">WWebPerm.mjs</a>, <a href="WWebPerm.mjs.html#line139">line 139</a>
84
84
  </li></ul></dd>
85
85
 
86
86
 
@@ -925,7 +925,7 @@
925
925
  <br class="clear">
926
926
 
927
927
  <footer>
928
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.4</a> on Sun Mar 29 2026 22:04:12 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
928
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Jun 22 2026 15:47:48 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
929
929
  </footer>
930
930
 
931
931
  <script>prettyPrint();</script>
@@ -70,15 +70,16 @@ import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
70
70
  import fsIsFile from 'wsemi/src/fsIsFile.mjs'
71
71
  import replace from 'wsemi/src/replace.mjs'
72
72
  import strdelleft from 'wsemi/src/strdelleft.mjs'
73
- import haskey from 'wsemi/src/haskey.mjs'
74
- import arrHas from 'wsemi/src/arrHas.mjs'
75
- import ltdtDiffByKey from 'wsemi/src/ltdtDiffByKey.mjs'
76
73
  import ltdtmapping from 'wsemi/src/ltdtmapping.mjs'
74
+ import pmKeyMutex from 'wsemi/src/pmKeyMutex.mjs'
77
75
  import WServHapiServer from 'w-serv-hapi/src/WServHapiServer.mjs'
78
76
  import WServOrm from 'w-serv-orm/src/WServOrm.mjs'
79
77
  import ds from '../src/schema/index.mjs'
80
78
  import { getUserRules } from '../src/plugins/mShare.mjs'
79
+ import procCore from './procCore.mjs'
81
80
  import procLang from './procLang.mjs'
81
+ import srLogInit from './srLog.mjs'
82
+ import procStaInfor from './procStaInfor.mjs'
82
83
 
83
84
 
84
85
  /**
@@ -315,6 +316,10 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
315
316
  let kpLang = procLang({ kpLangExt, webName, webDescription })
316
317
 
317
318
 
319
+ //srLog
320
+ let srLog = srLogInit(opt)
321
+
322
+
318
323
  //WServOrm
319
324
  let optWServOrm = {
320
325
  useCheckUser,
@@ -331,8 +336,25 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
331
336
  let { woItems, procOrm } = wp
332
337
 
333
338
 
339
+ //pmKeyMutex: per-key in-memory mutex, 同 key 序列化、不同 key 並行.
340
+ //perm 為「整表批次 diff」寫入, key 粒度為 {op}:{keyTable}, 防同表並行 race (lost update).
341
+ let kmx = pmKeyMutex()
342
+
343
+
344
+ //procCore: 整表批次 diff 寫入邏輯 (updateTabItems + updateTargets/Pemis/Grups/Users)
345
+ let pc = procCore(woItems, procOrm, { srLog, kmx })
346
+
347
+
348
+ //procStaInfor: 統計資訊, fdLog 對齊 srLog 使用同一目錄; mock 由 settings.staEventMock 注入(e2e 統計圖穩定用)
349
+ let psi = procStaInfor({ fdLog: './_logs', mock: get(opt, 'staEventMock', false) })
350
+
351
+
334
352
  //getWebInfor
335
353
  let getWebInfor = (userId) => {
354
+
355
+ //info
356
+ srLog.info({ event: 'getWebInfor-success', userId })
357
+
336
358
  return {
337
359
 
338
360
  // webName, //已併入kpLang
@@ -395,162 +417,32 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
395
417
  // }
396
418
 
397
419
 
398
- //updateTabItems
399
- let updateTabItems = async (keyTable, userId, rows, keyDetect) => {
400
- // console.log('updateTabItems', keyTable, userId, rows.length, keyDetect)
401
-
402
- //ltdtmapping
403
- rows = ltdtmapping(rows, ds[keyTable].keys)
404
- // console.log('ltdtmapping rows', rows)
405
-
406
- //重給order
407
- rows = map(rows, (r, k) => {
408
- r.order = k + 1
409
- return r
410
- })
411
-
412
- //ckKey
413
- let ckKey = (rows, key) => {
414
- let err = null
415
-
416
- //check
417
- let kp = {}
418
- each(rows, (v, k) => {
419
-
420
- //value
421
- let value = get(v, key, '')
422
-
423
- //check
424
- if (!isestr(value)) {
425
- err = `rows[${k}].${key} is not an effective string`
426
- return false //跳出
427
- }
428
-
429
- //check
430
- if (haskey(kp, value)) {
431
- err = `rows[${k}].${key}[${value}] is duplicate`
432
- return false //跳出
433
- }
434
-
435
- //kp
436
- kp[value] = true
437
-
438
- })
439
-
440
- return err
441
- }
442
-
443
- //偵測未給予或重複
444
- let err = null
445
- if (true) {
446
- if (arrHas(keyTable, ['targets'])) {
447
- err = ckKey(rows, 'id')
448
- if (err !== null) {
449
- return Promise.reject(err)
450
- }
451
- }
452
- if (arrHas(keyTable, ['pemis', 'grups'])) { //users可重複name故不列入
453
- err = ckKey(rows, 'name')
454
- if (err !== null) {
455
- return Promise.reject(err)
456
- }
457
- }
458
- if (arrHas(keyTable, ['users'])) {
459
- err = ckKey(rows, 'email')
460
- if (err !== null) {
461
- return Promise.reject(err)
462
- }
463
- }
464
- }
465
-
466
- //ltdtDiffByKey
467
- let ltdtOld = await woItems[keyTable].select()
468
- let ltdtNew = rows
469
- let r = ltdtDiffByKey(ltdtOld, ltdtNew, keyDetect)
470
- // console.log('ltdtDiffByKey r', r)
471
-
472
- //del
473
- if (size(r.del) > 0) {
474
- await procOrm(userId, keyTable, 'del', r.del) //須使用procOrm才有辦法自動給予相關欄位
475
- // .catch((err) => {
476
- // console.log('woItems[keyTable].del err', err)
477
- // })
478
- }
479
-
480
- //add
481
- if (size(r.add) > 0) {
482
- await procOrm(userId, keyTable, 'insert', r.add) //須使用procOrm才有辦法自動給予相關欄位
483
- // .catch((err) => {
484
- // console.log('woItems[keyTable].insert err', err)
485
- // })
486
- }
487
-
488
- //diff
489
- if (size(r.diff) > 0) {
490
- await procOrm(userId, keyTable, 'save', r.diff) //須使用procOrm才有辦法自動給予相關欄位
491
- // .catch((err) => {
492
- // console.log('woItems[keyTable].save err', err)
493
- // })
494
- }
495
-
496
- return ltdtNew
497
- }
498
-
499
-
500
- //updateTargets
501
- let updateTargets = async (userId, rows) => {
502
- rows = await updateTabItems('targets', userId, rows, 'id')
503
- return rows
504
- }
505
-
506
-
507
- //updatePemis
508
- let updatePemis = async (userId, rows) => {
509
- rows = await updateTabItems('pemis', userId, rows, 'name')
510
- return rows
511
- }
512
-
513
-
514
- //updateGrups
515
- let updateGrups = async (userId, rows) => {
516
- rows = await updateTabItems('grups', userId, rows, 'name')
517
- return rows
518
- }
519
-
520
-
521
- //updateUsers
522
- let updateUsers = async (userId, rows) => {
523
- rows = await updateTabItems('users', userId, rows, 'id')
524
- return rows
525
- }
526
-
527
-
528
420
  //checkUser
529
421
  let checkUser = async(user) => {
530
422
  let id = get(user, 'id', '')
531
423
  if (!isestr(id)) {
532
424
  console.log('user', user)
533
- console.log('can not get the userId')
534
- return Promise.reject(`can not get the userId`)
425
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserId' })
426
+ return Promise.reject(`cannotGetUserId`)
535
427
  }
536
428
  let email = get(user, 'email', '')
537
429
  if (!isestr(email)) {
538
430
  console.log('user', user)
539
- console.log('can not get the email of user')
540
- return Promise.reject(`can not get the email of user`)
431
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserEmail' })
432
+ return Promise.reject(`cannotGetUserEmail`)
541
433
  }
542
434
  let name = get(user, 'name', '')
543
435
  if (!isestr(name)) {
544
436
  console.log('user', user)
545
- console.log('can not get userName')
546
- return Promise.reject(`can not get userName`)
437
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserName' })
438
+ return Promise.reject(`cannotGetUserName`)
547
439
  }
548
440
  let isAdmin = get(user, 'isAdmin', '')
549
441
  if (isAdmin !== 'y' &amp;&amp; isAdmin !== 'n') {
550
442
  console.log('user', user)
551
443
  console.log('user.isAdmin is not y or n', user.isAdmin)
552
- console.log('can not get the role of user')
553
- return Promise.reject(`can not get the role of user`)
444
+ srLog.error({ event: 'checkUser-error', msg: 'cannotGetUserRole' })
445
+ return Promise.reject(`cannotGetUserRole`)
554
446
  }
555
447
  return true
556
448
  }
@@ -573,8 +465,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
573
465
  //check
574
466
  if (!iseobj(userSelf)) {
575
467
  console.log(`token`, token)
576
- console.log(`can not find the user from token`)
577
- return Promise.reject(`can not find the user from token`)
468
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotFindUserFromToken' })
469
+ return Promise.reject(`cannotFindUserFromToken`)
578
470
  }
579
471
 
580
472
  //check userSelf
@@ -588,8 +480,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
588
480
  if (!isestr(vSelf)) {
589
481
  console.log('userSelf', userSelf)
590
482
  console.log('mappingBy', mappingBy)
591
- console.log('can not get the prop of user by mappingBy')
592
- return Promise.reject(`can not get the prop of user by mappingBy`)
483
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotGetUserProp', mappingBy })
484
+ return Promise.reject(`cannotGetUserProp`)
593
485
  }
594
486
 
595
487
  //userFind
@@ -601,8 +493,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
601
493
  if (!iseobj(userFind)) {
602
494
  console.log('userSelf', userSelf)
603
495
  console.log('mappingBy', mappingBy)
604
- console.log('can not get the user from perm')
605
- return Promise.reject(`can not get the user from perm`)
496
+ srLog.error({ event: 'getTokenUser-error', msg: 'cannotGetUserFromPerm', mappingBy })
497
+ return Promise.reject(`cannotGetUserFromPerm`)
606
498
  }
607
499
 
608
500
  //複寫isAdmin
@@ -649,8 +541,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
649
541
  //check
650
542
  if (!b) {
651
543
  console.log('user', user)
652
- console.log(`user does not have permission`)
653
- return Promise.reject(`user does not have permission`)
544
+ srLog.error({ event: 'getAndVerifyClientUser-error', msg: 'userNoPermission', from })
545
+ return Promise.reject(`userNoPermission`)
654
546
  }
655
547
 
656
548
  return user
@@ -674,8 +566,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
674
566
  //check
675
567
  if (!iseobj(user)) {
676
568
  console.log(`token`, token)
677
- console.log(`can not find the user from token`)
678
- return Promise.reject(`can not find the user from token`)
569
+ srLog.error({ event: 'getAndVerifyAppUser-error', msg: 'cannotFindUserFromToken' })
570
+ return Promise.reject(`cannotFindUserFromToken`)
679
571
  }
680
572
 
681
573
  //verifyAppUser
@@ -687,8 +579,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
687
579
  //check
688
580
  if (!b) {
689
581
  console.log('user', user)
690
- console.log(`user does not have permission`)
691
- return Promise.reject(`user does not have permission`)
582
+ srLog.error({ event: 'getAndVerifyAppUser-error', msg: 'userNoPermission', from })
583
+ return Promise.reject(`userNoPermission`)
692
584
  }
693
585
 
694
586
  return user
@@ -709,8 +601,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
709
601
  //check
710
602
  if (!iseobj(payload)) {
711
603
  console.log('payload', payload)
712
- console.log('invalid payload in req')
713
- return Promise.reject(`invalid payload in req`)
604
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidPayload' })
605
+ return Promise.reject(`invalidPayload`)
714
606
  }
715
607
 
716
608
  //from
@@ -719,8 +611,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
719
611
  //check
720
612
  if (!isestr(from)) {
721
613
  console.log('payload', payload)
722
- console.log('invalid from in payload')
723
- return Promise.reject(`invalid from in payload`)
614
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidFromInPayload' })
615
+ return Promise.reject(`invalidFromInPayload`)
724
616
  }
725
617
 
726
618
  //rows
@@ -729,8 +621,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
729
621
  //check
730
622
  if (!isearr(rows)) {
731
623
  console.log('payload', payload)
732
- console.log(`invalid rows in payload`)
733
- return Promise.reject(`invalid rows in payload`)
624
+ srLog.error({ event: 'parsePayload-error', msg: 'invalidRowsInPayload' })
625
+ return Promise.reject(`invalidRowsInPayload`)
734
626
  }
735
627
 
736
628
  //inp
@@ -746,6 +638,9 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
746
638
  //syncAndReplaceTabs
747
639
  let syncAndReplaceTabs = async (userId, inp, keyTable) => {
748
640
 
641
+ //序列化同表之並行整表 delAll+insert: 防 lost update (同 keyTable 序列化, 不同表並行)
642
+ return await kmx('syncAndReplaceTabs:' + keyTable, async () => {
643
+
749
644
  //from
750
645
  let from = get(inp, 'from', '')
751
646
  // console.log('from', from)
@@ -753,8 +648,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
753
648
  //check
754
649
  if (!isestr(from)) {
755
650
  console.log('inp', inp)
756
- console.log(`invalid from`)
757
- return Promise.reject(`invalid from`)
651
+ srLog.error({ event: 'syncAndReplaceTabs-error', msg: 'invalidFrom', keyTable })
652
+ return Promise.reject(`invalidFrom`)
758
653
  }
759
654
 
760
655
  //rows
@@ -765,7 +660,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
765
660
  if (!isearr(rows)) {
766
661
  console.log('inp', inp)
767
662
  console.log('keyTable', keyTable)
768
- return Promise.reject(`invalid rows`)
663
+ srLog.error({ event: 'syncAndReplaceTabs-error', msg: 'invalidRows', keyTable })
664
+ return Promise.reject(`invalidRows`)
769
665
  }
770
666
 
771
667
  //save from
@@ -788,6 +684,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
788
684
  // console.log('r', r)
789
685
 
790
686
  return r
687
+
688
+ })
791
689
  }
792
690
 
793
691
 
@@ -848,8 +746,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
848
746
  //check
849
747
  if (!iseobj(kur)) {
850
748
  console.log('userId', userId)
851
- console.log(`can not get rules of user`)
852
- return Promise.reject(`can not get rules of user`)
749
+ srLog.error({ event: 'getGenUserAndRulesByUserId-error', msg: 'cannotGetUserRules', userId })
750
+ return Promise.reject(`cannotGetUserRules`)
853
751
  }
854
752
 
855
753
  //grupsNames
@@ -923,8 +821,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
923
821
  console.log('req.query', get(req, 'query'))
924
822
  console.log('token', token)
925
823
  console.log('[API]getUserByToken/check token: invalid token')
926
- console.log(`token does not have permission`)
927
- return Promise.reject(`token does not have permission`)
824
+ srLog.error({ event: 'api/getUserByToken-error', msg: 'tokenNoPermission' })
825
+ return Promise.reject(`tokenNoPermission`)
928
826
  }
929
827
 
930
828
  //getAndVerifyClientUser
@@ -935,10 +833,13 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
935
833
  if (!iseobj(user)) {
936
834
  console.log('token', token)
937
835
  console.log('[API]getUserByToken/check user: invalid user')
938
- console.log(`token does not have permission`)
939
- return Promise.reject(`token does not have permission`)
836
+ srLog.error({ event: 'api/getUserByToken-error', msg: 'tokenNoPermission' })
837
+ return Promise.reject(`tokenNoPermission`)
940
838
  }
941
839
 
840
+ //info
841
+ srLog.info({ event: 'api/getUserByToken-success', userId: get(user, 'id', '') })
842
+
942
843
  return user
943
844
  }
944
845
 
@@ -970,8 +871,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
970
871
  console.log('req.query', get(req, 'query'))
971
872
  console.log('token', token)
972
873
  console.log('[API]getPerm/check token: invalid token')
973
- console.log(`token does not have permission`)
974
- return Promise.reject(`token does not have permission`)
874
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
875
+ return Promise.reject(`tokenNoPermission`)
975
876
  }
976
877
 
977
878
  //getAndVerifyClientUser, 發起token的所屬使用者, 驗證僅對client使用者, 不得使用app使用者
@@ -982,8 +883,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
982
883
  if (!iseobj(userSelf)) {
983
884
  console.log('token', token)
984
885
  console.log('[API]getPerm/check userSelf: invalid userSelf')
985
- console.log(`token does not have permission`)
986
- return Promise.reject(`token does not have permission`)
886
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
887
+ return Promise.reject(`tokenNoPermission`)
987
888
  }
988
889
 
989
890
  //userIdSelf, client使用者的userId
@@ -995,8 +896,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
995
896
  console.log('token', token)
996
897
  console.log('userSelf', userSelf)
997
898
  console.log('[API]getPerm/check userIdSelf: invalid userIdSelf')
998
- console.log(`token does not have permission`)
999
- return Promise.reject(`token does not have permission`)
899
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
900
+ return Promise.reject(`tokenNoPermission`)
1000
901
  }
1001
902
 
1002
903
  //getGenUserAndRulesByUserId, 查找到的client使用者與權限
@@ -1009,10 +910,13 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1009
910
  console.log('userSelf', userSelf)
1010
911
  console.log('userIdSelf', userIdSelf)
1011
912
  console.log('[API]getPerm/check userWithRulesSelf: invalid userWithRulesSelf')
1012
- console.log(`token does not have permission`)
1013
- return Promise.reject(`token does not have permission`)
913
+ srLog.error({ event: 'api/getPerm-error', msg: 'tokenNoPermission' })
914
+ return Promise.reject(`tokenNoPermission`)
1014
915
  }
1015
916
 
917
+ //info
918
+ srLog.info({ event: 'api/getPerm-success', userId: userIdSelf })
919
+
1016
920
  return userWithRulesSelf
1017
921
  }
1018
922
 
@@ -1043,8 +947,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1043
947
  if (!isestr(tokenSelf)) {
1044
948
  console.log('req.query', get(req, 'query'))
1045
949
  console.log('[API]getPermUserInfor/check tokenSelf: invalid tokenSelf')
1046
- console.log(`token does not have permission`)
1047
- return Promise.reject(`token does not have permission`)
950
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
951
+ return Promise.reject(`tokenNoPermission`)
1048
952
  }
1049
953
 
1050
954
  //getAndVerifyAppUser, 發起token的所屬使用者, 驗證須為app使用者
@@ -1056,8 +960,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1056
960
  console.log('req.query', get(req, 'query'))
1057
961
  console.log('tokenSelf', tokenSelf)
1058
962
  console.log('[API]getPermUserInfor/check userSelf: invalid userSelf')
1059
- console.log(`token does not have permission`)
1060
- return Promise.reject(`token does not have permission`)
963
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
964
+ return Promise.reject(`tokenNoPermission`)
1061
965
  }
1062
966
 
1063
967
  //userIdFind, 欲查找使用者的userId
@@ -1069,8 +973,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1069
973
  console.log('req.query', get(req, 'query'))
1070
974
  console.log('tokenSelf', tokenSelf)
1071
975
  console.log('[API]getPermUserInfor/check userIdFind: invalid userIdFind')
1072
- console.log(`token does not have permission`)
1073
- return Promise.reject(`token does not have permission`)
976
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'tokenNoPermission' })
977
+ return Promise.reject(`tokenNoPermission`)
1074
978
  }
1075
979
 
1076
980
  //getGenUserAndRulesByUserId, 查找到的使用者與權限
@@ -1081,10 +985,13 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1081
985
  if (!iseobj(userWithRulesFind)) {
1082
986
  console.log('userIdFind', userIdFind)
1083
987
  console.log('[API]getPermUserInfor/check userWithRulesFind: invalid userWithRulesFind')
1084
- console.log(`userId does not have permrules`)
1085
- return Promise.reject(`userId does not have permrules`)
988
+ srLog.error({ event: 'api/getPermUserInfor-error', msg: 'userIdNoPermrules' })
989
+ return Promise.reject(`userIdNoPermrules`)
1086
990
  }
1087
991
 
992
+ //info
993
+ srLog.info({ event: 'api/getPermUserInfor-success', userId: userIdFind })
994
+
1088
995
  return userWithRulesFind
1089
996
  }
1090
997
 
@@ -1116,8 +1023,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1116
1023
  console.log('req.query', get(req, 'query'))
1117
1024
  console.log('token', token)
1118
1025
  console.log('[API]syncAndReplaceTabs/check token: invalid token')
1119
- console.log(`token does not have permission`)
1120
- return Promise.reject(`token does not have permission`)
1026
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1027
+ return Promise.reject(`tokenNoPermission`)
1121
1028
  }
1122
1029
 
1123
1030
  //keyTable
@@ -1128,15 +1035,16 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1128
1035
  console.log('req.query', get(req, 'query'))
1129
1036
  console.log('keyTable', keyTable)
1130
1037
  console.log('[API]syncAndReplaceTabs/check keyTable: invalid keyTable')
1131
- console.log(`token does not have permission`)
1132
- return Promise.reject(`token does not have permission`)
1038
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1039
+ return Promise.reject(`tokenNoPermission`)
1133
1040
  }
1134
1041
 
1135
1042
  //check keyTable
1136
1043
  let allowedTables = ['targets', 'pemis', 'grups', 'users']
1137
1044
  if (!allowedTables.includes(keyTable)) {
1138
1045
  console.log('[API]syncAndReplaceTabs/check keyTable: unexpected keyTable', keyTable)
1139
- return Promise.reject(`invalid keyTable: ${keyTable}`)
1046
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'invalidKeyTable', keyTable })
1047
+ return Promise.reject(`invalidKeyTable`)
1140
1048
  }
1141
1049
 
1142
1050
  //getAndVerifyAppUser
@@ -1146,8 +1054,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1146
1054
  if (!iseobj(user)) {
1147
1055
  console.log('token', token)
1148
1056
  console.log('[API]syncAndReplaceTabs/check user: invalid user')
1149
- console.log(`token does not have permission`)
1150
- return Promise.reject(`token does not have permission`)
1057
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1058
+ return Promise.reject(`tokenNoPermission`)
1151
1059
  }
1152
1060
 
1153
1061
  //userId
@@ -1158,8 +1066,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1158
1066
  console.log('token', token)
1159
1067
  console.log('user', user)
1160
1068
  console.log('[API]syncAndReplaceTabs/check userId: invalid userId')
1161
- console.log(`token does not have permission`)
1162
- return Promise.reject(`token does not have permission`)
1069
+ srLog.error({ event: 'api/syncAndReplaceTabs-error', msg: 'tokenNoPermission' })
1070
+ return Promise.reject(`tokenNoPermission`)
1163
1071
  }
1164
1072
 
1165
1073
  //parsePayload
@@ -1168,6 +1076,9 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1168
1076
  //syncAndReplaceTabs
1169
1077
  let r = await syncAndReplaceTabs(userId, inp, keyTable)
1170
1078
 
1079
+ //info
1080
+ srLog.info({ event: 'api/syncAndReplaceTabs-success', userId, keyTable })
1081
+
1171
1082
  return r
1172
1083
  }
1173
1084
 
@@ -1218,6 +1129,21 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1218
1129
  let b = await p.checkToken(token)
1219
1130
  // console.log('b', b)
1220
1131
 
1132
+ //ip, 對齊sso慣例x-forwarded-for取第1個, fallback到req remoteAddress, 取不到則略過
1133
+ let ip = get(headers, 'x-forwarded-for', '').split(',')[0].trim()
1134
+ if (!isestr(ip)) {
1135
+ ip = get(req, 'info.remoteAddress', '') || get(req, 'socket.remoteAddress', '') || get(req, 'connection.remoteAddress', '')
1136
+ }
1137
+
1138
+ //origin
1139
+ let origin = get(headers, 'origin', '')
1140
+
1141
+ //referer
1142
+ let referer = get(headers, 'referer', '')
1143
+
1144
+ //info
1145
+ srLog.info({ event: 'verifyConn', ok: b, apiType, ip, origin, referer })
1146
+
1221
1147
  return b
1222
1148
  },
1223
1149
  getUserIdByToken: async (token) => { //可使用async或sync函數
@@ -1227,7 +1153,8 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1227
1153
  if (!isestr(userId)) {
1228
1154
  console.log('token', token)
1229
1155
  console.log('userId', userId)
1230
- return Promise.reject(`can not find user.id`)
1156
+ srLog.error({ event: 'getUserIdByToken-error', msg: 'cannotFindUserId' })
1157
+ return Promise.reject(`cannotFindUserId`)
1231
1158
  }
1232
1159
  return userId
1233
1160
  },
@@ -1247,10 +1174,22 @@ function WWebPerm(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser
1247
1174
  // getGrupsList,
1248
1175
  // getUsersList,
1249
1176
 
1250
- updateTargets,
1251
- updatePemis,
1252
- updateGrups,
1253
- updateUsers,
1177
+ updateTargets: pc.updateTargets,
1178
+ updatePemis: pc.updatePemis,
1179
+ updateGrups: pc.updateGrups,
1180
+ updateUsers: pc.updateUsers,
1181
+
1182
+ getStaEvent: async (userId, timeLength, timeInterval) => {
1183
+ let rs = await psi.getStaEvent(userId, timeLength, timeInterval)
1184
+ srLog.info({ event: 'getStaEvent-success', userId })
1185
+ return rs
1186
+ },
1187
+
1188
+ getStaEventTable: async (userId) => {
1189
+ let rs = await psi.getStaEventTable(userId)
1190
+ srLog.info({ event: 'getStaEventTable-success', userId })
1191
+ return rs
1192
+ },
1254
1193
 
1255
1194
  },
1256
1195
  fnTableTags: 'tableTags-web-perm.json',
@@ -1276,7 +1215,7 @@ export default WWebPerm
1276
1215
  <br class="clear">
1277
1216
 
1278
1217
  <footer>
1279
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.4</a> on Sun Mar 29 2026 22:04:12 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1218
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Jun 22 2026 15:47:48 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1280
1219
  </footer>
1281
1220
 
1282
1221
  <script>prettyPrint();</script>
package/docs/index.html CHANGED
@@ -71,7 +71,7 @@
71
71
  <br class="clear">
72
72
 
73
73
  <footer>
74
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.4</a> on Sun Mar 29 2026 22:04:12 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
74
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Jun 22 2026 15:47:48 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
75
75
  </footer>
76
76
 
77
77
  <script>prettyPrint();</script>