w-web-perm 1.1.8 → 1.1.9
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/README.md +14 -4
- package/dist/index.tmp +1 -1
- package/dist/js/app-legacy.ecb7ce08.js +1 -0
- package/dist/js/app.ecb7ce08.js +1 -0
- package/dist/js/{chunk-vendors-legacy.00f159e8.js → chunk-vendors-legacy.da785a99.js} +3 -3
- package/dist/js/{chunk-vendors.00f159e8.js → chunk-vendors.da785a99.js} +3 -3
- package/dist/w-web-perm.umd.js +2 -2
- package/dist/w-web-perm.umd.js.map +1 -1
- package/docs/WWebPerm.html +78 -128
- package/docs/global.html +1280 -39
- package/docs/index.html +2 -2
- package/docs/server_WWebPerm.mjs.html +1247 -1196
- package/docs/server_dataChannel.mjs.html +131 -0
- package/docs/server_lockSave.mjs.html +2 -2
- package/docs/server_maskLog.mjs.html +2 -2
- package/docs/server_procCore.mjs.html +53 -11
- package/docs/server_staLogs_resolveShellWorker.mjs.html +180 -0
- package/docs/server_validateRows.mjs.html +184 -0
- package/docs/server_wrapInjected.mjs.html +2 -2
- package/docs/src_fetchJson.mjs.html +2 -2
- package/docs/src_js_legendFit.mjs.html +2 -2
- package/docs/src_plugins_reuseDeletedIds.mjs.html +2 -2
- package/docs/src_plugins_submitGuard.mjs.html +2 -2
- package/g_backupDb.mjs +4 -0
- package/g_initialData.mjs +1 -0
- package/g_initialTestData.mjs +1 -0
- package/g_mOrm.mjs +2 -7
- package/g_provideGrups.mjs +1 -0
- package/g_providePemis.mjs +1 -0
- package/g_provideTargets.mjs +1 -0
- package/g_provideUsers.mjs +1 -0
- package/package.json +10 -10
- package/server/WWebPerm.mjs +1245 -1194
- package/server/dataChannel.mjs +59 -0
- package/server/procCore.mjs +51 -9
- package/server/procLang.mjs +13 -3
- package/server/staLogs/resolveShellWorker.mjs +108 -0
- package/server/staLogs/staLogsCore.callWorker.mjs +29 -9
- package/server/validateRows.mjs +112 -0
- package/src/components/LayoutContentGrups.vue +8 -8
- package/src/components/LayoutContentPemis.vue +8 -8
- package/src/components/LayoutContentTargets.vue +2 -2
- package/src/components/LayoutContentUsers.vue +4 -4
- package/src/components/VeCgrups.vue +3 -3
- package/src/components/VeCpemis.vue +3 -3
- package/src/components/VeCrules.vue +3 -3
- package/src/components/VeGrupBlngUsers.vue +6 -6
- package/src/components/VePemiBlngGrups.vue +6 -6
- package/srv.mjs +0 -4
- package/dist/js/app-legacy.6f82d8bd.js +0 -1
- package/dist/js/app.6f82d8bd.js +0 -1
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>server/dataChannel.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">server/dataChannel.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>import isestr from 'wsemi/src/isestr.mjs'
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
//資料通道(w-serv-webdata, useDbOrm:true)之表操作授權與 ORM 呼叫包裝(規則帳本 R-WSD-01、R-ORM-02; spec/設計要點與取捨.md ADR-026、ADR-015 Update)
|
|
52
|
+
//
|
|
53
|
+
//政策: 資料通道只開 select(methodsExec:['select'] 為第一道, 本授權函數只放行 select 為第二道).
|
|
54
|
+
//why: 裸 insert/save/del/delAll 繞過 procCore 之 lockSave、kmx、ckKey、寫入前驗證與整表比對(ADR-009/012/025/026 之不變式只在 kpFunExt 成立),
|
|
55
|
+
//同表兩條寫入路徑不對稱; 前端與測試皆只用 kpFunExt 寫入、同步只用 select(2026-10-14 Grep `\$fapi\.`、`callRpc(` 實證).
|
|
56
|
+
//連線者之身分授權仍在 verifyConn(getAndVerifyClientUser), 本函數不重做.
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 建立資料通道之表操作授權函數(w-serv-webdata 之 opt.authorizeExec)
|
|
61
|
+
*
|
|
62
|
+
* @param {Object} p 輸入物件
|
|
63
|
+
* @param {Object} p.srLog 輸入 srLog(須有 error 方法)
|
|
64
|
+
* @returns {Function} 回傳授權函數 ({ userId, tableName, methodName }) => Boolean, 只對已取得 userId 之 select 回傳 true; 拒絕時記 srLog(event 'authorizeExec', msg 為 err key)
|
|
65
|
+
*/
|
|
66
|
+
function createAuthorizeExec({ srLog }) {
|
|
67
|
+
return ({ userId, tableName, methodName }) => {
|
|
68
|
+
let msg = ''
|
|
69
|
+
if (!isestr(userId)) {
|
|
70
|
+
msg = 'cannotFindUserId'
|
|
71
|
+
}
|
|
72
|
+
else if (methodName !== 'select') {
|
|
73
|
+
msg = 'userNoPermission'
|
|
74
|
+
}
|
|
75
|
+
if (msg !== '') {
|
|
76
|
+
srLog.error({ event: 'authorizeExec', ok: false, msg, userId, tableName, methodName })
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
return true
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* 包裝資料通道之 operOrm: ORM 拒絕之原文(英文訊息、Error)只入 srLog, 對前端改回語系鍵 anUnexpectedErrorOccurred
|
|
86
|
+
*
|
|
87
|
+
* @param {Function} procOrm 輸入 w-serv-orm 之 procOrm(userId, tableName, methodName, input)
|
|
88
|
+
* @param {Object} p 輸入物件
|
|
89
|
+
* @param {Object} p.srLog 輸入 srLog(須有 error 方法)
|
|
90
|
+
* @returns {Function} 回傳同簽名之 async 函數
|
|
91
|
+
*/
|
|
92
|
+
function wrapOperOrm(procOrm, { srLog }) {
|
|
93
|
+
return async (userId, tableName, methodName, input) => {
|
|
94
|
+
try {
|
|
95
|
+
return await procOrm(userId, tableName, methodName, input)
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
let raw = (typeof err === 'string') ? err : ((err && err.message) || String(err))
|
|
99
|
+
srLog.error({ event: 'operOrm-error', msg: 'anUnexpectedErrorOccurred', raw, userId, tableName, methodName })
|
|
100
|
+
return Promise.reject('anUnexpectedErrorOccurred')
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
export { createAuthorizeExec, wrapOperOrm }
|
|
107
|
+
</code></pre>
|
|
108
|
+
</article>
|
|
109
|
+
</section>
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<br class="clear">
|
|
119
|
+
|
|
120
|
+
<footer>
|
|
121
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 16 2026 13:07:24 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
122
|
+
</footer>
|
|
123
|
+
|
|
124
|
+
<script>prettyPrint();</script>
|
|
125
|
+
<script src="scripts/polyfill.js"></script>
|
|
126
|
+
<script src="scripts/linenumber.js"></script>
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<nav >
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -102,7 +102,7 @@ export default createLockSave
|
|
|
102
102
|
<br class="clear">
|
|
103
103
|
|
|
104
104
|
<footer>
|
|
105
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
105
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 16 2026 13:07:24 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
106
106
|
</footer>
|
|
107
107
|
|
|
108
108
|
<script>prettyPrint();</script>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<nav >
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -163,7 +163,7 @@ export {
|
|
|
163
163
|
<br class="clear">
|
|
164
164
|
|
|
165
165
|
<footer>
|
|
166
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
166
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 16 2026 13:07:24 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
167
167
|
</footer>
|
|
168
168
|
|
|
169
169
|
<script>prettyPrint();</script>
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
<nav >
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li></ul>
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -57,6 +57,8 @@ import arrHas from 'wsemi/src/arrHas.mjs'
|
|
|
57
57
|
import ltdtDiffByKey from 'wsemi/src/ltdtDiffByKey.mjs'
|
|
58
58
|
import ltdtmapping from 'wsemi/src/ltdtmapping.mjs'
|
|
59
59
|
import ds from '../src/schema/index.mjs'
|
|
60
|
+
import procLang from './procLang.mjs'
|
|
61
|
+
import validateRowsBeforeWrite from './validateRows.mjs'
|
|
60
62
|
|
|
61
63
|
|
|
62
64
|
/**
|
|
@@ -71,7 +73,7 @@ import ds from '../src/schema/index.mjs'
|
|
|
71
73
|
* @returns {Array} 以資料庫列為基底、僅覆蓋 pickKeys 之新列陣列(順序同資料庫)
|
|
72
74
|
*/
|
|
73
75
|
function mergePickKeysOnly(ltdtDb, rowsIn, keyDetect, pickKeys) {
|
|
74
|
-
let kpIn =
|
|
76
|
+
let kpIn = Object.create(null) //無原型: 鍵為使用者資料(id), 不得命中 constructor 等原型鍵(規則帳本 R-KEY-01)
|
|
75
77
|
each(rowsIn, (r) => {
|
|
76
78
|
let v = get(r, keyDetect, '')
|
|
77
79
|
if (isestr(v)) {
|
|
@@ -144,7 +146,7 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
144
146
|
let err = null
|
|
145
147
|
|
|
146
148
|
//check
|
|
147
|
-
let kp = {}
|
|
149
|
+
let kp = Object.create(null) //無原型: haskey 以 in 判斷, {} 之原型鍵(constructor、toString 等)恆為真而誤判重複(規則帳本 R-KEY-01)
|
|
148
150
|
each(rows, (v, k) => {
|
|
149
151
|
|
|
150
152
|
//value
|
|
@@ -195,6 +197,13 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
195
197
|
}
|
|
196
198
|
}
|
|
197
199
|
|
|
200
|
+
//主鍵之有限數字轉為其字串形式(規則帳本 R-ORM-04; w-serv-orm 1.1.11 起庫內即如此存放): ltdtDiffByKey 以嚴格比對, 未轉時 123 對不上庫內之 '123',
|
|
201
|
+
//成為「刪 '123' 再新增」而重設建立者與建立時間(userId、timeCreate); 放在 ckKey 之後, targets 仍只收字串主鍵(ckKey 以 isestr 檢查 id)
|
|
202
|
+
rows = map(rows, (r) => {
|
|
203
|
+
let id = get(r, 'id')
|
|
204
|
+
return (typeof id === 'number' && Number.isFinite(id)) ? { ...r, id: String(id) } : r
|
|
205
|
+
})
|
|
206
|
+
|
|
198
207
|
//ltdtDiffByKey
|
|
199
208
|
let ltdtOld = await woItems[keyTable].select()
|
|
200
209
|
|
|
@@ -214,6 +223,23 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
214
223
|
let r = ltdtDiffByKey(ltdtOld, ltdtNew, keyDetect)
|
|
215
224
|
// console.log('ltdtDiffByKey r', r)
|
|
216
225
|
|
|
226
|
+
//寫入前驗證(規則帳本 R-ORM-01, ADR-026): 於第一個破壞步驟(del)之前擋下可預判之寫入失敗, 被拒時資料表零變更.
|
|
227
|
+
//why: 寫入順序為 del → insert → save, 而 w-serv-orm 1.1.8 起對「會被 clearXSS 改寫之主鍵」整批拒絕、LMDB 對 > 1978 B 之主鍵整批拒絕,
|
|
228
|
+
//修正前遇之即「舊列已刪、新列被拒」(改標的 id 時該列遺失, 2026-10-14 V3/V7 實測); 非主鍵欄位之標記則被靜默改寫(存值≠送入值).
|
|
229
|
+
//只驗本次會寫入之 add + diff 列(任一字串欄位); 未變更之 same 列不寫入、只參與主鍵重複之判定(舊資料不阻擋儲存)
|
|
230
|
+
let ve = validateRowsBeforeWrite([...r.add, ...r.diff], { rowsIdOnly: r.same })
|
|
231
|
+
if (ve !== null) {
|
|
232
|
+
let key = 'saveRowFieldInvalid'
|
|
233
|
+
if (ve.reason === 'htmlMarkup') {
|
|
234
|
+
key = 'htmlMarkupNotAllowed'
|
|
235
|
+
}
|
|
236
|
+
else if (ve.reason === 'idDuplicate') {
|
|
237
|
+
key = 'saveRowFieldDuplicate'
|
|
238
|
+
}
|
|
239
|
+
srLog.error({ event: 'updateTabItems-validate-error', keyTable, msg: key, reason: ve.reason, row: ve.k, field: ve.field })
|
|
240
|
+
return Promise.reject(key)
|
|
241
|
+
}
|
|
242
|
+
|
|
217
243
|
//del
|
|
218
244
|
if (size(r.del) > 0) {
|
|
219
245
|
await procOrm(userId, keyTable, 'del', r.del) //須使用procOrm才有辦法自動給予相關欄位
|
|
@@ -244,9 +270,15 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
244
270
|
}
|
|
245
271
|
|
|
246
272
|
|
|
247
|
-
//errLog: 失敗統一記 err key
|
|
273
|
+
//errLog: 失敗統一記 err key 並回傳對外之 key(規則帳本 R-ORM-02).
|
|
274
|
+
//拒絕值來源: updateTabItems 自身之 reject 為本套件語系鍵字串(saveRowFieldInvalid、htmlMarkupNotAllowed、saveInProgress 等), 原樣轉出;
|
|
275
|
+
//procOrm 之拒絕為 w-serv-orm 之英文原文字串(1.1.10 起, 如 failed to save data…)或 Error, updateTabItems 內直接呼叫之 woItems[keyTable].select()
|
|
276
|
+
//失敗為 ORM 之原錯誤(可能為 Error)——此兩類原文只入 srLog 之 raw, 對前端與外部改回 saveWriteFail(修正前原樣外送, 前端 tErr 換算為「無法連線至伺服器」)
|
|
248
277
|
let errLog = (event, userId, err) => {
|
|
249
|
-
|
|
278
|
+
let key = toOutKey(err)
|
|
279
|
+
let raw = (typeof err === 'string') ? err : ((err && err.message) || String(err))
|
|
280
|
+
srLog.error({ event, userId, msg: key, ...(raw !== key ? { raw } : {}) })
|
|
281
|
+
return key
|
|
250
282
|
}
|
|
251
283
|
|
|
252
284
|
|
|
@@ -255,7 +287,7 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
255
287
|
try {
|
|
256
288
|
await updateTabItems('targets', userId, rows, 'id')
|
|
257
289
|
}
|
|
258
|
-
catch (err) { errLog('updateTargets-error', userId, err)
|
|
290
|
+
catch (err) { throw errLog('updateTargets-error', userId, err) }
|
|
259
291
|
srLog.info({ event: 'updateTargets-success', userId })
|
|
260
292
|
return 'saveTabItemsSuccess' //成功 msg key
|
|
261
293
|
}
|
|
@@ -266,7 +298,7 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
266
298
|
try {
|
|
267
299
|
await updateTabItems('pemis', userId, rows, 'name')
|
|
268
300
|
}
|
|
269
|
-
catch (err) { errLog('updatePemis-error', userId, err)
|
|
301
|
+
catch (err) { throw errLog('updatePemis-error', userId, err) }
|
|
270
302
|
srLog.info({ event: 'updatePemis-success', userId })
|
|
271
303
|
return 'saveTabItemsSuccess' //成功 msg key
|
|
272
304
|
}
|
|
@@ -277,7 +309,7 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
277
309
|
try {
|
|
278
310
|
await updateTabItems('grups', userId, rows, 'name')
|
|
279
311
|
}
|
|
280
|
-
catch (err) { errLog('updateGrups-error', userId, err)
|
|
312
|
+
catch (err) { throw errLog('updateGrups-error', userId, err) }
|
|
281
313
|
srLog.info({ event: 'updateGrups-success', userId })
|
|
282
314
|
return 'saveTabItemsSuccess' //成功 msg key
|
|
283
315
|
}
|
|
@@ -288,7 +320,7 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
288
320
|
try {
|
|
289
321
|
await updateTabItems('users', userId, rows, 'id', opt)
|
|
290
322
|
}
|
|
291
|
-
catch (err) { errLog('updateUsers-error', userId, err)
|
|
323
|
+
catch (err) { throw errLog('updateUsers-error', userId, err) }
|
|
292
324
|
srLog.info({ event: 'updateUsers-success', userId })
|
|
293
325
|
return 'saveTabItemsSuccess' //成功 msg key
|
|
294
326
|
}
|
|
@@ -306,7 +338,17 @@ function proc(woItems, procOrm, { srLog, kmx, lockSave }) {
|
|
|
306
338
|
}
|
|
307
339
|
|
|
308
340
|
|
|
309
|
-
|
|
341
|
+
//toOutKey: 拒絕值為本套件語系鍵(procLang 之鍵集合)者原樣回傳, 其餘(ORM/I/O 原文、Error)回 keyFail(規則帳本 R-ORM-02)
|
|
342
|
+
let kpLangKey = null
|
|
343
|
+
function toOutKey(err, keyFail = 'saveWriteFail') {
|
|
344
|
+
if (kpLangKey === null) {
|
|
345
|
+
kpLangKey = new Set(Object.keys(procLang({}).eng))
|
|
346
|
+
}
|
|
347
|
+
return (typeof err === 'string' && kpLangKey.has(err)) ? err : keyFail
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
export { mergePickKeysOnly, toOutKey }
|
|
310
352
|
|
|
311
353
|
|
|
312
354
|
export default proc
|
|
@@ -324,7 +366,7 @@ export default proc
|
|
|
324
366
|
<br class="clear">
|
|
325
367
|
|
|
326
368
|
<footer>
|
|
327
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
369
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 16 2026 13:07:24 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
328
370
|
</footer>
|
|
329
371
|
|
|
330
372
|
<script>prettyPrint();</script>
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>server/staLogs/resolveShellWorker.mjs - Documentation</title>
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
10
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
11
|
+
<!--[if lt IE 9]>
|
|
12
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
13
|
+
<![endif]-->
|
|
14
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
15
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
16
|
+
<script src="scripts/nav.js" defer></script>
|
|
17
|
+
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
19
|
+
</head>
|
|
20
|
+
<body>
|
|
21
|
+
|
|
22
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
23
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
24
|
+
<div class="navicon"></div>
|
|
25
|
+
</label>
|
|
26
|
+
|
|
27
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
28
|
+
|
|
29
|
+
<nav >
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
<h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="WWebPerm.html">WWebPerm</a></li></ul><h3>Global</h3><ul><li><a href="global.html#createAuthorizeExec">createAuthorizeExec</a></li><li><a href="global.html#createLegendMeasurer">createLegendMeasurer</a></li><li><a href="global.html#createLockSave">createLockSave</a></li><li><a href="global.html#decideLegendType">decideLegendType</a></li><li><a href="global.html#describeUpstream">describeUpstream</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#maskQuery">maskQuery</a></li><li><a href="global.html#maskTok">maskTok</a></li><li><a href="global.html#maskUrl">maskUrl</a></li><li><a href="global.html#mergePickKeysOnly">mergePickKeysOnly</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">server/staLogs/resolveShellWorker.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>import fs from 'fs'
|
|
49
|
+
import path from 'path'
|
|
50
|
+
import { createRequire } from 'module'
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
//解析 staLogs worker 檔之絕對路徑(規則帳本 R-PKG-01; X1, 對應 w-syslog 審計之方案④).
|
|
54
|
+
//why: 原以模組頂層之 __filename/__dirname 於載入時算出 worker 路徑——打包成 umd(toolg/gDistRollup.mjs)時,
|
|
55
|
+
//rollup 把 import.meta.url 換成引用 __filename 之墊片且避讓名單不含 __filename, 頂層同名宣告使 bundle 載入即 TDZ;
|
|
56
|
+
//改名後 __dirname 為 bundle 所在資料夾(dist/), 其下無 worker 檔. 故改為首次使用時依下列順序解析(由呼叫端快取).
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
let PKG_NAME = 'w-web-perm'
|
|
60
|
+
let REL_SHELL_WORKER = 'server/staLogs/staLogsCore.shellWorker.mjs'
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
//findNearestPkgDir: 由 dir 往上找最近之含 package.json 之資料夾, 找不到回 ''
|
|
64
|
+
function findNearestPkgDir(dir, existsSync) {
|
|
65
|
+
let d = dir
|
|
66
|
+
for (;;) {
|
|
67
|
+
if (existsSync(path.join(d, 'package.json'))) {
|
|
68
|
+
return d
|
|
69
|
+
}
|
|
70
|
+
let up = path.dirname(d)
|
|
71
|
+
if (up === d) {
|
|
72
|
+
return ''
|
|
73
|
+
}
|
|
74
|
+
d = up
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 解析本套件 staLogs worker 檔之絕對路徑, 供源碼、已安裝之套件、本套件之 dist 與被下游再打包時皆可用
|
|
81
|
+
*
|
|
82
|
+
* 順序: (a) 由 fpSelf 往上找最近之 package.json, 其 name 為 pkgName 且其下 rel 存在 → 採用(最近之 package.json 名稱不符即不再往上);
|
|
83
|
+
* (b) createRequire(fpSelf).resolve(`${pkgName}/${rel}`)(被下游打包時往上找 node_modules); (c) 同上但以 cwd 為基準(bundle 被搬離 node_modules 樹而由專案根執行);
|
|
84
|
+
* (d) 皆失敗拋 Error, 訊息含套件名、相對路徑與已試之位置
|
|
85
|
+
*
|
|
86
|
+
* @param {Object} p 輸入物件
|
|
87
|
+
* @param {String} p.fpSelf 輸入呼叫端模組之檔案絕對路徑(由 import.meta.url 轉得; 打包後為 bundle 之位置)
|
|
88
|
+
* @param {String} [p.cwd=process.cwd()] 輸入 (c) 之基準資料夾
|
|
89
|
+
* @param {String} [p.pkgName='w-web-perm'] 輸入本套件名稱
|
|
90
|
+
* @param {String} [p.rel='server/staLogs/staLogsCore.shellWorker.mjs'] 輸入 worker 檔相對於套件根之路徑
|
|
91
|
+
* @param {Function} [p.existsSync=fs.existsSync] 輸入檔案是否存在之函數(測試注入用)
|
|
92
|
+
* @param {Function} [p.readFileSync=fs.readFileSync] 輸入讀檔函數(測試注入用)
|
|
93
|
+
* @param {Function} [p.createRequire] 輸入 module.createRequire(測試注入用)
|
|
94
|
+
* @returns {String} 回傳 worker 檔之絕對路徑
|
|
95
|
+
*/
|
|
96
|
+
function resolveShellWorker(p = {}) {
|
|
97
|
+
let fpSelf = p.fpSelf
|
|
98
|
+
let cwd = p.cwd || process.cwd()
|
|
99
|
+
let pkgName = p.pkgName || PKG_NAME
|
|
100
|
+
let rel = p.rel || REL_SHELL_WORKER
|
|
101
|
+
let existsSync = p.existsSync || fs.existsSync
|
|
102
|
+
let readFileSync = p.readFileSync || fs.readFileSync
|
|
103
|
+
let createRequireFn = p.createRequire || createRequire
|
|
104
|
+
if (typeof fpSelf !== 'string' || fpSelf === '') {
|
|
105
|
+
throw new Error('invalid fpSelf')
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
let tried = []
|
|
109
|
+
|
|
110
|
+
//(a) 本模組所屬套件根
|
|
111
|
+
let dirPkg = findNearestPkgDir(path.dirname(fpSelf), existsSync)
|
|
112
|
+
if (dirPkg === '') {
|
|
113
|
+
tried.push(`(a) no package.json above ${path.dirname(fpSelf)}`)
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
let name = ''
|
|
117
|
+
try {
|
|
118
|
+
name = JSON.parse(readFileSync(path.join(dirPkg, 'package.json'), 'utf8')).name
|
|
119
|
+
}
|
|
120
|
+
catch (err) {}
|
|
121
|
+
let fp = path.join(dirPkg, rel)
|
|
122
|
+
if (name !== pkgName) {
|
|
123
|
+
tried.push(`(a) ${path.join(dirPkg, 'package.json')} name[${name}]`)
|
|
124
|
+
}
|
|
125
|
+
else if (!existsSync(fp)) {
|
|
126
|
+
tried.push(`(a) ${fp}`)
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return fp
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//(b) 由本模組位置以模組解析, (c) 由 cwd 以模組解析
|
|
134
|
+
let id = `${pkgName}/${rel}`
|
|
135
|
+
let bases = [['b', fpSelf], ['c', path.join(cwd, 'noop.js')]]
|
|
136
|
+
for (let [k, base] of bases) {
|
|
137
|
+
try {
|
|
138
|
+
let fp = createRequireFn(base).resolve(id)
|
|
139
|
+
if (existsSync(fp)) {
|
|
140
|
+
return fp
|
|
141
|
+
}
|
|
142
|
+
tried.push(`(${k}) ${fp}`)
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
tried.push(`(${k}) resolve ${id} from ${base}`)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//(d)
|
|
150
|
+
throw new Error(`cannot resolve ${rel} of ${pkgName} (the package must be installed with its server folder), tried: ${tried.join('; ')}`)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
export { PKG_NAME, REL_SHELL_WORKER }
|
|
155
|
+
export default resolveShellWorker
|
|
156
|
+
</code></pre>
|
|
157
|
+
</article>
|
|
158
|
+
</section>
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<br class="clear">
|
|
168
|
+
|
|
169
|
+
<footer>
|
|
170
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 16 2026 13:07:24 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
171
|
+
</footer>
|
|
172
|
+
|
|
173
|
+
<script>prettyPrint();</script>
|
|
174
|
+
<script src="scripts/polyfill.js"></script>
|
|
175
|
+
<script src="scripts/linenumber.js"></script>
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
</body>
|
|
180
|
+
</html>
|