w-web-perm 1.1.11 → 1.1.13
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 +158 -117
- package/dist/css/app.f09c7433.css +1 -0
- package/dist/index.tmp +1 -1
- package/dist/js/app-legacy.8af87052.js +1 -0
- package/dist/js/app.8af87052.js +1 -0
- package/dist/js/{chunk-vendors.3e9e3ef1.js → chunk-vendors-legacy.ece5a361.js} +1 -1
- package/dist/js/{chunk-vendors-legacy.3e9e3ef1.js → chunk-vendors.ece5a361.js} +1 -1
- package/dist/w-web-perm.umd.js +2 -2
- package/dist/w-web-perm.umd.js.map +1 -1
- package/docs/WWebPerm.html +84 -4
- package/docs/global.html +24747 -832
- package/docs/index.html +2 -2
- package/docs/server_WWebPerm.mjs.html +245 -32
- package/docs/server_cascadeWrite.mjs.html +225 -0
- package/docs/server_dataChannel.mjs.html +2 -2
- package/docs/server_keyCheck.mjs.html +353 -0
- package/docs/server_lockSave.mjs.html +2 -2
- package/docs/server_maskLog.mjs.html +2 -2
- package/docs/server_procCore.mjs.html +180 -41
- package/docs/server_staLogs_resolveShellWorker.mjs.html +2 -2
- package/docs/server_syncKeep.mjs.html +311 -0
- package/docs/server_tools_authRefsAudit.mjs.html +247 -0
- package/docs/server_tools_authRefsClean.mjs.html +335 -0
- package/docs/server_tools_fromTools.mjs.html +797 -0
- package/docs/server_tools_isMain.mjs.html +103 -0
- package/docs/server_tools_nameDupReport.mjs.html +280 -0
- package/docs/server_validateRows.mjs.html +15 -4
- package/docs/server_wrapInjected.mjs.html +3 -3
- package/docs/src_fetchJson.mjs.html +2 -2
- package/docs/src_js_cvKpToArr.mjs.html +125 -0
- package/docs/src_js_cvKpToObj.mjs.html +210 -0
- package/docs/src_js_draftSync.mjs.html +142 -0
- package/docs/src_js_eachOwn.mjs.html +3 -3
- package/docs/src_js_editorRefRows.mjs.html +356 -0
- package/docs/src_js_externalRows.mjs.html +338 -0
- package/docs/src_js_externalUi.mjs.html +230 -0
- package/docs/src_js_findRefRows.mjs.html +107 -0
- package/docs/src_js_findTouchedDup.mjs.html +150 -0
- package/docs/src_js_fmtLossyMsg.mjs.html +95 -0
- package/docs/src_js_fromAudit.mjs.html +489 -0
- package/docs/src_js_getAddImpact.mjs.html +269 -0
- package/docs/src_js_getAuthWarn.mjs.html +463 -0
- package/docs/src_js_getCascadePreview.mjs.html +258 -0
- package/docs/src_js_getDelRefCount.mjs.html +210 -0
- package/docs/src_js_getEffMode.mjs.html +92 -0
- package/docs/src_js_getKpLossy.mjs.html +155 -0
- package/docs/src_js_getNameErrs.mjs.html +266 -0
- package/docs/src_js_getOwn.mjs.html +3 -3
- package/docs/src_js_getPropKey.mjs.html +109 -0
- package/docs/src_js_getRuleEnable.mjs.html +2 -2
- package/docs/src_js_isAuthMode.mjs.html +92 -0
- package/docs/src_js_joinNames.mjs.html +96 -0
- package/docs/src_js_legendFit.mjs.html +2 -2
- package/docs/src_js_pairRowsToSnapshot.mjs.html +156 -0
- package/docs/src_js_refAudit.mjs.html +359 -0
- package/docs/src_js_refCascade.mjs.html +572 -0
- package/docs/src_js_relDialogSend.mjs.html +199 -0
- package/docs/src_js_rowDigest.mjs.html +265 -0
- package/docs/src_plugins_dataReloadGuard.mjs.html +109 -0
- package/docs/src_plugins_reuseDeletedIds.mjs.html +2 -2
- package/docs/src_plugins_submitGuard.mjs.html +2 -2
- package/g_authRefsClean.mjs +79 -0
- package/g_fixFromType.mjs +92 -0
- package/g_initialData.mjs +3 -3
- package/g_purgeFrom.mjs +127 -0
- package/package.json +1 -1
- package/server/WWebPerm.mjs +243 -30
- package/server/cascadeWrite.mjs +153 -0
- package/server/keyCheck.mjs +281 -0
- package/server/procCore.mjs +178 -39
- package/server/procLang.mjs +271 -0
- package/server/syncKeep.mjs +239 -0
- package/server/tools/authRefsAudit.mjs +175 -0
- package/server/tools/authRefsClean.mjs +263 -0
- package/server/tools/fromTools.mjs +725 -0
- package/server/tools/isMain.mjs +31 -0
- package/server/tools/nameDupReport.mjs +208 -0
- package/server/validateRows.mjs +13 -2
- package/server/wrapInjected.mjs +1 -1
- package/src/components/LayoutContentGrups.vue +399 -77
- package/src/components/LayoutContentPemis.vue +400 -78
- package/src/components/LayoutContentTargets.vue +261 -25
- package/src/components/LayoutContentUsers.vue +336 -98
- package/src/components/VeCgrups.vue +119 -115
- package/src/components/VeCpemis.vue +117 -115
- package/src/components/VeCrules.vue +18 -2
- package/src/components/VeGrupBlngUsers.vue +240 -73
- package/src/components/VePemiBlngGrups.vue +247 -83
- package/src/js/cvKpToArr.mjs +53 -0
- package/src/js/cvKpToObj.mjs +138 -0
- package/src/js/draftSync.mjs +70 -0
- package/src/js/eachOwn.mjs +1 -1
- package/src/js/editorRefRows.mjs +284 -0
- package/src/js/externalRows.mjs +266 -0
- package/src/js/externalUi.mjs +158 -0
- package/src/js/findRefRows.mjs +35 -0
- package/src/js/findTouchedDup.mjs +78 -0
- package/src/js/fmtLossyMsg.mjs +23 -0
- package/src/js/fromAudit.mjs +417 -0
- package/src/js/getAddImpact.mjs +197 -0
- package/src/js/getAuthWarn.mjs +391 -0
- package/src/js/getCascadePreview.mjs +186 -0
- package/src/js/getDelRefCount.mjs +138 -0
- package/src/js/getEffMode.mjs +20 -0
- package/src/js/getKpLossy.mjs +83 -0
- package/src/js/getNameErrs.mjs +194 -0
- package/src/js/getOwn.mjs +1 -1
- package/src/js/getPropKey.mjs +37 -0
- package/src/js/isAuthMode.mjs +20 -0
- package/src/js/joinNames.mjs +24 -0
- package/src/js/pairRowsToSnapshot.mjs +84 -0
- package/src/js/refAudit.mjs +287 -0
- package/src/js/refCascade.mjs +500 -0
- package/src/js/relDialogSend.mjs +127 -0
- package/src/js/rowDigest.mjs +193 -0
- package/src/plugins/dataReloadGuard.mjs +37 -0
- package/src/plugins/mShare.mjs +147 -174
- package/src/plugins/mUI.mjs +3 -8
- package/src/schema/tables/users.mjs +152 -152
- package/dist/css/app.6918ec45.css +0 -1
- package/dist/js/app-legacy.963e800c.js +0 -1
- package/dist/js/app.963e800c.js +0 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>server/tools/isMain.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#applyPurgePlan">applyPurgePlan</a></li><li><a href="global.html#auditFrom">auditFrom</a></li><li><a href="global.html#auditRefs">auditRefs</a></li><li><a href="global.html#buildReport">buildReport</a></li><li><a href="global.html#buildRowsSend">buildRowsSend</a></li><li><a href="global.html#buildSyncRowsNew">buildSyncRowsNew</a></li><li><a href="global.html#checkBaseline">checkBaseline</a></li><li><a href="global.html#checkCascadePlan">checkCascadePlan</a></li><li><a href="global.html#checkDbNotInUse">checkDbNotInUse</a></li><li><a href="global.html#checkExternalWrite">checkExternalWrite</a></li><li><a href="global.html#checkMapKeyBatch">checkMapKeyBatch</a></li><li><a href="global.html#checkUsersWrite">checkUsersWrite</a></li><li><a href="global.html#cleanOutOf">cleanOutOf</a></li><li><a href="global.html#compareBaseline">compareBaseline</a></li><li><a href="global.html#countAndRefs">countAndRefs</a></li><li><a href="global.html#countExternalRows">countExternalRows</a></li><li><a href="global.html#countIdRenumber">countIdRenumber</a></li><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#cvKpToArr">cvKpToArr</a></li><li><a href="global.html#cvKpToObj">cvKpToObj</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#diffRefTargets">diffRefTargets</a></li><li><a href="global.html#dropServerOnlyDiff">dropServerOnlyDiff</a></li><li><a href="global.html#eachOwn">eachOwn</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#fillIdlessIds">fillIdlessIds</a></li><li><a href="global.html#findDupIndex">findDupIndex</a></li><li><a href="global.html#findKeyOtherFrom">findKeyOtherFrom</a></li><li><a href="global.html#findRefRows">findRefRows</a></li><li><a href="global.html#findTouchedDup">findTouchedDup</a></li><li><a href="global.html#fmtLossyMsg">fmtLossyMsg</a></li><li><a href="global.html#fmtVars">fmtVars</a></li><li><a href="global.html#fmtWarn">fmtWarn</a></li><li><a href="global.html#formatFixReport">formatFixReport</a></li><li><a href="global.html#formatFromAudit">formatFromAudit</a></li><li><a href="global.html#formatPurgeReport">formatPurgeReport</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#getAddConfirmText">getAddConfirmText</a></li><li><a href="global.html#getAddImpact">getAddImpact</a></li><li><a href="global.html#getBannerLines">getBannerLines</a></li><li><a href="global.html#getBaselineDigest">getBaselineDigest</a></li><li><a href="global.html#getCascadePreview">getCascadePreview</a></li><li><a href="global.html#getChangedIdx">getChangedIdx</a></li><li><a href="global.html#getDelConfirmText">getDelConfirmText</a></li><li><a href="global.html#getDelImpact">getDelImpact</a></li><li><a href="global.html#getDelRefCount">getDelRefCount</a></li><li><a href="global.html#getDigestFields">getDigestFields</a></li><li><a href="global.html#getDupRowsInconsistent">getDupRowsInconsistent</a></li><li><a href="global.html#getEffMode">getEffMode</a></li><li><a href="global.html#getExternalEdits">getExternalEdits</a></li><li><a href="global.html#getItemWarnText">getItemWarnText</a></li><li><a href="global.html#getKpLossy">getKpLossy</a></li><li><a href="global.html#getLockFields">getLockFields</a></li><li><a href="global.html#getNameErrs">getNameErrs</a></li><li><a href="global.html#getOwn">getOwn</a></li><li><a href="global.html#getPropKey">getPropKey</a></li><li><a href="global.html#getRawModeMap">getRawModeMap</a></li><li><a href="global.html#getRefRowsExtra">getRefRowsExtra</a></li><li><a href="global.html#getRefState">getRefState</a></li><li><a href="global.html#getRefWarnText">getRefWarnText</a></li><li><a href="global.html#getRefWarns">getRefWarns</a></li><li><a href="global.html#getRowIdxs">getRowIdxs</a></li><li><a href="global.html#getRowState">getRowState</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</a></li><li><a href="global.html#getRuleWarnText">getRuleWarnText</a></li><li><a href="global.html#getRuleWarns">getRuleWarns</a></li><li><a href="global.html#getSavePreview">getSavePreview</a></li><li><a href="global.html#getSyncWarnLines">getSyncWarnLines</a></li><li><a href="global.html#hasDupKey">hasDupKey</a></li><li><a href="global.html#hasExternalDiff">hasExternalDiff</a></li><li><a href="global.html#isAuthMode">isAuthMode</a></li><li><a href="global.html#isBaselineStale">isBaselineStale</a></li><li><a href="global.html#isBaselineValid">isBaselineValid</a></li><li><a href="global.html#isDraftStale">isDraftStale</a></li><li><a href="global.html#isExternalRow">isExternalRow</a></li><li><a href="global.html#isJsonLossy">isJsonLossy</a></li><li><a href="global.html#isMain">isMain</a></li><li><a href="global.html#joinList">joinList</a></li><li><a href="global.html#joinNames">joinNames</a></li><li><a href="global.html#keepAssignByEntity">keepAssignByEntity</a></li><li><a href="global.html#keepAssignOnMissing">keepAssignOnMissing</a></li><li><a href="global.html#makeBaseline">makeBaseline</a></li><li><a href="global.html#makeRowStates">makeRowStates</a></li><li><a href="global.html#mapKeyOf">mapKeyOf</a></li><li><a href="global.html#mapNameKp">mapNameKp</a></li><li><a href="global.html#markDataReload">markDataReload</a></li><li><a href="global.html#markHasKey">markHasKey</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#pairRowsToSnapshot">pairRowsToSnapshot</a></li><li><a href="global.html#pickUniqueUser">pickUniqueUser</a></li><li><a href="global.html#planDraftSync">planDraftSync</a></li><li><a href="global.html#planFixFromType">planFixFromType</a></li><li><a href="global.html#planPurgeChain">planPurgeChain</a></li><li><a href="global.html#planPurgeFrom">planPurgeFrom</a></li><li><a href="global.html#planRefChanges">planRefChanges</a></li><li><a href="global.html#putRefEntry">putRefEntry</a></li><li><a href="global.html#putRowsToKp">putRowsToKp</a></li><li><a href="global.html#refsChanged">refsChanged</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#restoreExternalOrder">restoreExternalOrder</a></li><li><a href="global.html#restoreServerFields">restoreServerFields</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#rewriteRefs">rewriteRefs</a></li><li><a href="global.html#rowDigest">rowDigest</a></li><li><a href="global.html#runAuditFrom">runAuditFrom</a></li><li><a href="global.html#runClean">runClean</a></li><li><a href="global.html#runFixFromType">runFixFromType</a></li><li><a href="global.html#runPurgeFrom">runPurgeFrom</a></li><li><a href="global.html#splitCheckedRows">splitCheckedRows</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#tabWriteKey">tabWriteKey</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#withTabLocks">withTabLocks</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li><li><a href="global.html#writeWithCascade">writeWithCascade</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">server/tools/isMain.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 { fileURLToPath } from 'url'
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 判斷呼叫端模組是否為 node 直接執行之入口(CLI 區塊的進入條件)
|
|
54
|
+
*
|
|
55
|
+
* 套件經 symlink/junction 安裝(npm link、pnpm、workspaces)時, node 以真實路徑載入入口模組(import.meta.url 為真實路徑),
|
|
56
|
+
* 而 process.argv[1] 維持命令列所給之路徑, 兩者直接比較不相等, CLI 區塊靜默不執行(無報告卻正常結束; run08 外審 sol #5).
|
|
57
|
+
* 故兩邊皆取真實路徑再比對(Windows 路徑不分大小寫).
|
|
58
|
+
*
|
|
59
|
+
* @param {String} importMetaUrl 輸入呼叫端的 import.meta.url
|
|
60
|
+
* @param {String} [argv1=process.argv[1]] 輸入命令列給 node 的入口路徑, 預設 process.argv[1]
|
|
61
|
+
* @returns {Boolean} 回傳呼叫端模組即為入口為 true; 無法判定(路徑不存在等)為 false
|
|
62
|
+
*/
|
|
63
|
+
function isMain(importMetaUrl, argv1 = process.argv[1]) {
|
|
64
|
+
if (typeof argv1 !== 'string' || argv1 === '') {
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
let a = fs.realpathSync.native(fileURLToPath(importMetaUrl))
|
|
69
|
+
let b = fs.realpathSync.native(argv1)
|
|
70
|
+
return process.platform === 'win32' ? a.toLowerCase() === b.toLowerCase() : a === b
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
return false
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
export default isMain
|
|
79
|
+
</code></pre>
|
|
80
|
+
</article>
|
|
81
|
+
</section>
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<br class="clear">
|
|
91
|
+
|
|
92
|
+
<footer>
|
|
93
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 23 2026 10:56:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
94
|
+
</footer>
|
|
95
|
+
|
|
96
|
+
<script>prettyPrint();</script>
|
|
97
|
+
<script src="scripts/polyfill.js"></script>
|
|
98
|
+
<script src="scripts/linenumber.js"></script>
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
</body>
|
|
103
|
+
</html>
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>server/tools/nameDupReport.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#applyPurgePlan">applyPurgePlan</a></li><li><a href="global.html#auditFrom">auditFrom</a></li><li><a href="global.html#auditRefs">auditRefs</a></li><li><a href="global.html#buildReport">buildReport</a></li><li><a href="global.html#buildRowsSend">buildRowsSend</a></li><li><a href="global.html#buildSyncRowsNew">buildSyncRowsNew</a></li><li><a href="global.html#checkBaseline">checkBaseline</a></li><li><a href="global.html#checkCascadePlan">checkCascadePlan</a></li><li><a href="global.html#checkDbNotInUse">checkDbNotInUse</a></li><li><a href="global.html#checkExternalWrite">checkExternalWrite</a></li><li><a href="global.html#checkMapKeyBatch">checkMapKeyBatch</a></li><li><a href="global.html#checkUsersWrite">checkUsersWrite</a></li><li><a href="global.html#cleanOutOf">cleanOutOf</a></li><li><a href="global.html#compareBaseline">compareBaseline</a></li><li><a href="global.html#countAndRefs">countAndRefs</a></li><li><a href="global.html#countExternalRows">countExternalRows</a></li><li><a href="global.html#countIdRenumber">countIdRenumber</a></li><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#cvKpToArr">cvKpToArr</a></li><li><a href="global.html#cvKpToObj">cvKpToObj</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#diffRefTargets">diffRefTargets</a></li><li><a href="global.html#dropServerOnlyDiff">dropServerOnlyDiff</a></li><li><a href="global.html#eachOwn">eachOwn</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#fillIdlessIds">fillIdlessIds</a></li><li><a href="global.html#findDupIndex">findDupIndex</a></li><li><a href="global.html#findKeyOtherFrom">findKeyOtherFrom</a></li><li><a href="global.html#findRefRows">findRefRows</a></li><li><a href="global.html#findTouchedDup">findTouchedDup</a></li><li><a href="global.html#fmtLossyMsg">fmtLossyMsg</a></li><li><a href="global.html#fmtVars">fmtVars</a></li><li><a href="global.html#fmtWarn">fmtWarn</a></li><li><a href="global.html#formatFixReport">formatFixReport</a></li><li><a href="global.html#formatFromAudit">formatFromAudit</a></li><li><a href="global.html#formatPurgeReport">formatPurgeReport</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#getAddConfirmText">getAddConfirmText</a></li><li><a href="global.html#getAddImpact">getAddImpact</a></li><li><a href="global.html#getBannerLines">getBannerLines</a></li><li><a href="global.html#getBaselineDigest">getBaselineDigest</a></li><li><a href="global.html#getCascadePreview">getCascadePreview</a></li><li><a href="global.html#getChangedIdx">getChangedIdx</a></li><li><a href="global.html#getDelConfirmText">getDelConfirmText</a></li><li><a href="global.html#getDelImpact">getDelImpact</a></li><li><a href="global.html#getDelRefCount">getDelRefCount</a></li><li><a href="global.html#getDigestFields">getDigestFields</a></li><li><a href="global.html#getDupRowsInconsistent">getDupRowsInconsistent</a></li><li><a href="global.html#getEffMode">getEffMode</a></li><li><a href="global.html#getExternalEdits">getExternalEdits</a></li><li><a href="global.html#getItemWarnText">getItemWarnText</a></li><li><a href="global.html#getKpLossy">getKpLossy</a></li><li><a href="global.html#getLockFields">getLockFields</a></li><li><a href="global.html#getNameErrs">getNameErrs</a></li><li><a href="global.html#getOwn">getOwn</a></li><li><a href="global.html#getPropKey">getPropKey</a></li><li><a href="global.html#getRawModeMap">getRawModeMap</a></li><li><a href="global.html#getRefRowsExtra">getRefRowsExtra</a></li><li><a href="global.html#getRefState">getRefState</a></li><li><a href="global.html#getRefWarnText">getRefWarnText</a></li><li><a href="global.html#getRefWarns">getRefWarns</a></li><li><a href="global.html#getRowIdxs">getRowIdxs</a></li><li><a href="global.html#getRowState">getRowState</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</a></li><li><a href="global.html#getRuleWarnText">getRuleWarnText</a></li><li><a href="global.html#getRuleWarns">getRuleWarns</a></li><li><a href="global.html#getSavePreview">getSavePreview</a></li><li><a href="global.html#getSyncWarnLines">getSyncWarnLines</a></li><li><a href="global.html#hasDupKey">hasDupKey</a></li><li><a href="global.html#hasExternalDiff">hasExternalDiff</a></li><li><a href="global.html#isAuthMode">isAuthMode</a></li><li><a href="global.html#isBaselineStale">isBaselineStale</a></li><li><a href="global.html#isBaselineValid">isBaselineValid</a></li><li><a href="global.html#isDraftStale">isDraftStale</a></li><li><a href="global.html#isExternalRow">isExternalRow</a></li><li><a href="global.html#isJsonLossy">isJsonLossy</a></li><li><a href="global.html#isMain">isMain</a></li><li><a href="global.html#joinList">joinList</a></li><li><a href="global.html#joinNames">joinNames</a></li><li><a href="global.html#keepAssignByEntity">keepAssignByEntity</a></li><li><a href="global.html#keepAssignOnMissing">keepAssignOnMissing</a></li><li><a href="global.html#makeBaseline">makeBaseline</a></li><li><a href="global.html#makeRowStates">makeRowStates</a></li><li><a href="global.html#mapKeyOf">mapKeyOf</a></li><li><a href="global.html#mapNameKp">mapNameKp</a></li><li><a href="global.html#markDataReload">markDataReload</a></li><li><a href="global.html#markHasKey">markHasKey</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#pairRowsToSnapshot">pairRowsToSnapshot</a></li><li><a href="global.html#pickUniqueUser">pickUniqueUser</a></li><li><a href="global.html#planDraftSync">planDraftSync</a></li><li><a href="global.html#planFixFromType">planFixFromType</a></li><li><a href="global.html#planPurgeChain">planPurgeChain</a></li><li><a href="global.html#planPurgeFrom">planPurgeFrom</a></li><li><a href="global.html#planRefChanges">planRefChanges</a></li><li><a href="global.html#putRefEntry">putRefEntry</a></li><li><a href="global.html#putRowsToKp">putRowsToKp</a></li><li><a href="global.html#refsChanged">refsChanged</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#restoreExternalOrder">restoreExternalOrder</a></li><li><a href="global.html#restoreServerFields">restoreServerFields</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#rewriteRefs">rewriteRefs</a></li><li><a href="global.html#rowDigest">rowDigest</a></li><li><a href="global.html#runAuditFrom">runAuditFrom</a></li><li><a href="global.html#runClean">runClean</a></li><li><a href="global.html#runFixFromType">runFixFromType</a></li><li><a href="global.html#runPurgeFrom">runPurgeFrom</a></li><li><a href="global.html#splitCheckedRows">splitCheckedRows</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#tabWriteKey">tabWriteKey</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#withTabLocks">withTabLocks</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li><li><a href="global.html#writeWithCascade">writeWithCascade</a></li></ul>
|
|
33
|
+
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<div id="main">
|
|
37
|
+
|
|
38
|
+
<h1 class="page-title">server/tools/nameDupReport.mjs</h1>
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
<section>
|
|
47
|
+
<article>
|
|
48
|
+
<pre class="prettyprint source linenums"><code>//名稱重複與使用者對應鍵之唯讀稽核工具(F-02/F-14; 規則帳本 R-NAME-UNIQ-03; ADR-034). 不屬測試, 不寫任何資料, 不提供自動刪除/改名——清理由管理者於後台逐一處理並確認授權.
|
|
49
|
+
//
|
|
50
|
+
//用法(自專案根; 套件安裝後此檔位於 node_modules/w-web-perm/server/tools/, 以該路徑執行即可, 匯出檔路徑相對於目前工作目錄):
|
|
51
|
+
// node server/tools/nameDupReport.mjs <匯出檔.json> [--mapping-by id|email|name] [--json]
|
|
52
|
+
// node server/tools/nameDupReport.mjs --audit <匯出檔.json> [--mapping-by id|email|name] [--json] (同上; 與 authMergeReport.mjs --audit 寫法一致)
|
|
53
|
+
//
|
|
54
|
+
// 匯出檔內容 { users, grups, pemis, targets }(各為列陣列, 如以資料通道 select 之結果或資料庫匯出)。
|
|
55
|
+
// --mapping-by 省略時 email 與 name 皆報告(部署之 mappingBy 設定不在資料庫內); 給 id 則只查 id 缺漏(id 為主鍵, 不會重複).
|
|
56
|
+
// --json 輸出結構化結果(供其他工具), 省略則輸出文字報告.
|
|
57
|
+
//
|
|
58
|
+
//報告內容:
|
|
59
|
+
// 1. grups/pemis 同名組: 各筆之 id/from/isActive/order, 以及被哪些 users.cgrups(查 grups 名)/grups.cpemis(查 pemis 名)以該名稱引用(只計名稱字串出現之引用; 解碼用 src/js/cvKpToArr.mjs,
|
|
60
|
+
// JSON5 解析失敗之列容錯: 視為無引用並列入「壞 JSON」清單). 比對為精確 ===(同伺服端 arrFinder).
|
|
61
|
+
// 已知邊界(增量外審 mmd-N8, 未處理): 陣列形式之引用元素缺 name 時, 伺服端 arrFinder 以 get(vv,'name','') 取得 ''(可對應名稱為 '' 之列), 本工具解碼後名稱為索引數字, 不計入該引用;
|
|
62
|
+
// 須同時存在「名稱為空字串之群組/權限」與「陣列形式且缺 name 之引用」, 空名稱者已另由 authMergeReport --audit 列出, 請一併人工檢視.
|
|
63
|
+
// 2. users 對應鍵: isActive==='y' 之列, 對應鍵(email/name/id)為空/空白/非字串者, 以及值重複者(精確 ===; 與 getTokenUser 之 select 一致), 附各列 id/name/from.
|
|
64
|
+
//
|
|
65
|
+
//【清理須知】引用以「名稱」比對, 改名級聯(F-07)尚未實作: 同名組中改名或刪除其一, 引用該名稱者會全部指向剩下的那一筆或失效.
|
|
66
|
+
// 請先以本報告列出引用者, 清理後逐一確認授權(getPermUserInfor/getPerm 之結果), 再處理下一組.
|
|
67
|
+
// 報告含 email(對應鍵)原文, 請妥善保管、勿外傳.
|
|
68
|
+
|
|
69
|
+
import fs from 'fs'
|
|
70
|
+
import isMain from './isMain.mjs'
|
|
71
|
+
import JSON5 from 'json5'
|
|
72
|
+
import cvKpToArr from '../../src/js/cvKpToArr.mjs'
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
let isStr = (v) => typeof v === 'string'
|
|
76
|
+
let arr = (v) => (Array.isArray(v) ? v : [])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
//decodeNames: 解碼授權字串(cgrups/cpemis)為 [{ name, mode, isActive }], 失敗回 null(壞 JSON); 空字串視為無內容([])
|
|
80
|
+
function decodeRefs(s) {
|
|
81
|
+
if (!isStr(s) || s.trim() === '') {
|
|
82
|
+
return []
|
|
83
|
+
}
|
|
84
|
+
let kp = null
|
|
85
|
+
try {
|
|
86
|
+
kp = JSON5.parse(s)
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
return null
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
//名稱保留原型別: 伺服端 arrFinder 以 === 比對, 非字串名稱(如 1、['1'])不會對應任何群組/權限, 不得轉字串後報成引用者(外審 sol R8)
|
|
93
|
+
return cvKpToArr(kp).map((r) => ({ name: r.name, mode: r.mode, isActive: r.isActive }))
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return null
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
//dupGroups: 表內 name 為字串且出現 ≥ 2 次者之組(精確 ===)
|
|
102
|
+
function dupGroups(rows) {
|
|
103
|
+
let kp = new Map()
|
|
104
|
+
for (let r of arr(rows)) {
|
|
105
|
+
if (r && isStr(r.name)) {
|
|
106
|
+
if (!kp.has(r.name)) {
|
|
107
|
+
kp.set(r.name, [])
|
|
108
|
+
}
|
|
109
|
+
kp.get(r.name).push(r)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return [...kp].filter(([, rs]) => rs.length >= 2).map(([name, rs]) => ({ name, rows: rs }))
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
//refsTo: 以 refTable 各列之授權欄位(refCol)引用 name 者
|
|
117
|
+
function refsTo(name, refRows, refCol, badJson) {
|
|
118
|
+
let out = []
|
|
119
|
+
for (let r of arr(refRows)) {
|
|
120
|
+
let ds = decodeRefs(r && r[refCol])
|
|
121
|
+
if (ds === null) {
|
|
122
|
+
badJson.push({ table: refCol === 'cgrups' ? 'users' : 'grups', id: r.id })
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
for (let d of ds) {
|
|
126
|
+
if (d.name === name) {
|
|
127
|
+
out.push({ id: r.id, name: r.name, mode: d.mode, isActive: d.isActive })
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return out
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
//mapKeyIssues: isActive==='y' 之 users, 對應鍵 key 為空/空白/非字串(empty), 以及值重複(dup)
|
|
136
|
+
function mapKeyIssues(users, key) {
|
|
137
|
+
let act = arr(users).filter((u) => u && u.isActive === 'y')
|
|
138
|
+
let brief = (u) => ({ id: u.id, name: u.name, from: u.from })
|
|
139
|
+
let empty = act.filter((u) => !(isStr(u[key]) && u[key].trim().length > 0)).map(brief)
|
|
140
|
+
let kp = new Map()
|
|
141
|
+
for (let u of act) {
|
|
142
|
+
if (isStr(u[key]) && u[key].trim().length > 0) {
|
|
143
|
+
if (!kp.has(u[key])) {
|
|
144
|
+
kp.set(u[key], [])
|
|
145
|
+
}
|
|
146
|
+
kp.get(u[key]).push(brief(u))
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
let dup = [...kp].filter(([, rs]) => rs.length >= 2).map(([value, rows]) => ({ value, rows }))
|
|
150
|
+
return { empty, dup }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 建立稽核結果(純函數, 不讀寫檔案)
|
|
156
|
+
*
|
|
157
|
+
* @param {Object} data { users, grups, pemis, targets }
|
|
158
|
+
* @param {Object} [opt={}] 設定
|
|
159
|
+
* @param {String} [opt.mappingBy] 'id'|'email'|'name', 省略時 email 與 name 皆報告
|
|
160
|
+
* @returns {Object} 稽核結果
|
|
161
|
+
*/
|
|
162
|
+
function buildReport(data, opt = {}) {
|
|
163
|
+
let d = data || {}
|
|
164
|
+
let badJson = []
|
|
165
|
+
let brief = (r) => ({ id: r.id, from: r.from, isActive: r.isActive, order: r.order })
|
|
166
|
+
let grups = dupGroups(d.grups).map((g) => ({
|
|
167
|
+
name: g.name,
|
|
168
|
+
rows: g.rows.map(brief),
|
|
169
|
+
refs: refsTo(g.name, d.users, 'cgrups', badJson), //users.cgrups 以群組名引用
|
|
170
|
+
}))
|
|
171
|
+
let pemis = dupGroups(d.pemis).map((g) => ({
|
|
172
|
+
name: g.name,
|
|
173
|
+
rows: g.rows.map(brief),
|
|
174
|
+
refs: refsTo(g.name, d.grups, 'cpemis', badJson), //grups.cpemis 以權限名引用
|
|
175
|
+
}))
|
|
176
|
+
//壞 JSON 全表掃描(外審 sol R9): 不論有無同名組, users.cgrups/grups.cpemis 解析失敗者皆列出(refsTo 只掃同名組之引用者, 會漏列)
|
|
177
|
+
for (let [rows, col, table] of [[d.users, 'cgrups', 'users'], [d.grups, 'cpemis', 'grups']]) {
|
|
178
|
+
for (let r of arr(rows)) {
|
|
179
|
+
if (r && decodeRefs(r[col]) === null) {
|
|
180
|
+
badJson.push({ table, id: r.id })
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
let keys = (opt.mappingBy === 'id' || opt.mappingBy === 'email' || opt.mappingBy === 'name') ? [opt.mappingBy] : ['email', 'name']
|
|
185
|
+
let mapKey = {}
|
|
186
|
+
for (let key of keys) {
|
|
187
|
+
mapKey[key] = (key === 'id')
|
|
188
|
+
? { empty: arr(d.users).filter((u) => u && u.isActive === 'y' && !(isStr(u.id) && u.id !== '')).map((u) => ({ id: u.id, name: u.name, from: u.from })), dup: [] }
|
|
189
|
+
: mapKeyIssues(d.users, key)
|
|
190
|
+
}
|
|
191
|
+
//壞 JSON 去重(同一列被多個重複名稱之解碼重複記錄)
|
|
192
|
+
let seen = new Set()
|
|
193
|
+
badJson = badJson.filter((b) => {
|
|
194
|
+
let k = `${b.table}:${b.id}`
|
|
195
|
+
return seen.has(k) ? false : (seen.add(k), true)
|
|
196
|
+
})
|
|
197
|
+
return {
|
|
198
|
+
counts: { users: arr(d.users).length, grups: arr(d.grups).length, pemis: arr(d.pemis).length, targets: arr(d.targets).length },
|
|
199
|
+
grups,
|
|
200
|
+
pemis,
|
|
201
|
+
mapKey,
|
|
202
|
+
badJson,
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
//formatReport: 結果轉文字
|
|
208
|
+
function formatReport(rp) {
|
|
209
|
+
let L = []
|
|
210
|
+
let rowTxt = (r) => `id=${r.id} from=${JSON.stringify(r.from)} isActive=${JSON.stringify(r.isActive)} order=${r.order}`
|
|
211
|
+
L.push(`資料筆數: users ${rp.counts.users}、grups ${rp.counts.grups}、pemis ${rp.counts.pemis}、targets ${rp.counts.targets}`)
|
|
212
|
+
for (let [tab, refFrom, label] of [['grups', 'users.cgrups', '群組'], ['pemis', 'grups.cpemis', '權限']]) {
|
|
213
|
+
L.push('')
|
|
214
|
+
L.push(`== ${label}(${tab})同名組: ${rp[tab].length} 組 ==`)
|
|
215
|
+
for (let g of rp[tab]) {
|
|
216
|
+
L.push(`- 「${g.name}」${g.rows.length} 筆`)
|
|
217
|
+
g.rows.forEach((r) => L.push(` ${rowTxt(r)}`))
|
|
218
|
+
L.push(` 被 ${refFrom} 引用: ${g.refs.length} 處`)
|
|
219
|
+
g.refs.forEach((r) => L.push(` ${tab === 'grups' ? 'user' : 'grup'} id=${r.id} name=${JSON.stringify(r.name)} mode=${JSON.stringify(r.mode)} isActive=${JSON.stringify(r.isActive)}`))
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
for (let [key, v] of Object.entries(rp.mapKey)) {
|
|
223
|
+
L.push('')
|
|
224
|
+
L.push(`== users 對應鍵 ${key}(僅 isActive='y'): 空/空白/非字串 ${v.empty.length} 筆, 值重複 ${v.dup.length} 組 ==`)
|
|
225
|
+
v.empty.forEach((u) => L.push(`- 空: id=${u.id} name=${JSON.stringify(u.name)} from=${JSON.stringify(u.from)}`))
|
|
226
|
+
for (let g of v.dup) {
|
|
227
|
+
L.push(`- 重複「${g.value}」${g.rows.length} 筆`)
|
|
228
|
+
g.rows.forEach((u) => L.push(` id=${u.id} name=${JSON.stringify(u.name)} from=${JSON.stringify(u.from)}`))
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
L.push('')
|
|
232
|
+
L.push(`== 授權字串壞 JSON(解析失敗, 視為無引用): ${rp.badJson.length} 列 ==`)
|
|
233
|
+
rp.badJson.forEach((b) => L.push(`- ${b.table} id=${b.id}`))
|
|
234
|
+
return L.join('\n')
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
//CLI
|
|
239
|
+
if (isMain(import.meta.url)) {
|
|
240
|
+
let args = process.argv.slice(2)
|
|
241
|
+
let iMap = args.indexOf('--mapping-by')
|
|
242
|
+
let mappingBy = (iMap >= 0) ? args[iMap + 1] : undefined
|
|
243
|
+
let iAudit = args.indexOf('--audit')
|
|
244
|
+
let fp = (iAudit >= 0) ? args[iAudit + 1] : args.find((a, k) => !a.startsWith('--') && !(iMap >= 0 && k === iMap + 1))
|
|
245
|
+
if (!fp || (iMap >= 0 && !['id', 'email', 'name'].includes(mappingBy))) {
|
|
246
|
+
console.log('用法: node server/tools/nameDupReport.mjs <匯出檔.json> [--mapping-by id|email|name] [--json]')
|
|
247
|
+
process.exit(2)
|
|
248
|
+
}
|
|
249
|
+
let data = JSON.parse(fs.readFileSync(fp, 'utf8'))
|
|
250
|
+
let rp = buildReport(data, { mappingBy })
|
|
251
|
+
console.log(args.includes('--json') ? JSON.stringify(rp, null, 1) : formatReport(rp))
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
export { buildReport, formatReport, decodeRefs }
|
|
256
|
+
</code></pre>
|
|
257
|
+
</article>
|
|
258
|
+
</section>
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<br class="clear">
|
|
268
|
+
|
|
269
|
+
<footer>
|
|
270
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 23 2026 10:56:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
271
|
+
</footer>
|
|
272
|
+
|
|
273
|
+
<script>prettyPrint();</script>
|
|
274
|
+
<script src="scripts/polyfill.js"></script>
|
|
275
|
+
<script src="scripts/linenumber.js"></script>
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
</body>
|
|
280
|
+
</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#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#eachOwn">eachOwn</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#getOwn">getOwn</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</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>
|
|
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#applyPurgePlan">applyPurgePlan</a></li><li><a href="global.html#auditFrom">auditFrom</a></li><li><a href="global.html#auditRefs">auditRefs</a></li><li><a href="global.html#buildReport">buildReport</a></li><li><a href="global.html#buildRowsSend">buildRowsSend</a></li><li><a href="global.html#buildSyncRowsNew">buildSyncRowsNew</a></li><li><a href="global.html#checkBaseline">checkBaseline</a></li><li><a href="global.html#checkCascadePlan">checkCascadePlan</a></li><li><a href="global.html#checkDbNotInUse">checkDbNotInUse</a></li><li><a href="global.html#checkExternalWrite">checkExternalWrite</a></li><li><a href="global.html#checkMapKeyBatch">checkMapKeyBatch</a></li><li><a href="global.html#checkUsersWrite">checkUsersWrite</a></li><li><a href="global.html#cleanOutOf">cleanOutOf</a></li><li><a href="global.html#compareBaseline">compareBaseline</a></li><li><a href="global.html#countAndRefs">countAndRefs</a></li><li><a href="global.html#countExternalRows">countExternalRows</a></li><li><a href="global.html#countIdRenumber">countIdRenumber</a></li><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#cvKpToArr">cvKpToArr</a></li><li><a href="global.html#cvKpToObj">cvKpToObj</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#diffRefTargets">diffRefTargets</a></li><li><a href="global.html#dropServerOnlyDiff">dropServerOnlyDiff</a></li><li><a href="global.html#eachOwn">eachOwn</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#fillIdlessIds">fillIdlessIds</a></li><li><a href="global.html#findDupIndex">findDupIndex</a></li><li><a href="global.html#findKeyOtherFrom">findKeyOtherFrom</a></li><li><a href="global.html#findRefRows">findRefRows</a></li><li><a href="global.html#findTouchedDup">findTouchedDup</a></li><li><a href="global.html#fmtLossyMsg">fmtLossyMsg</a></li><li><a href="global.html#fmtVars">fmtVars</a></li><li><a href="global.html#fmtWarn">fmtWarn</a></li><li><a href="global.html#formatFixReport">formatFixReport</a></li><li><a href="global.html#formatFromAudit">formatFromAudit</a></li><li><a href="global.html#formatPurgeReport">formatPurgeReport</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#getAddConfirmText">getAddConfirmText</a></li><li><a href="global.html#getAddImpact">getAddImpact</a></li><li><a href="global.html#getBannerLines">getBannerLines</a></li><li><a href="global.html#getBaselineDigest">getBaselineDigest</a></li><li><a href="global.html#getCascadePreview">getCascadePreview</a></li><li><a href="global.html#getChangedIdx">getChangedIdx</a></li><li><a href="global.html#getDelConfirmText">getDelConfirmText</a></li><li><a href="global.html#getDelImpact">getDelImpact</a></li><li><a href="global.html#getDelRefCount">getDelRefCount</a></li><li><a href="global.html#getDigestFields">getDigestFields</a></li><li><a href="global.html#getDupRowsInconsistent">getDupRowsInconsistent</a></li><li><a href="global.html#getEffMode">getEffMode</a></li><li><a href="global.html#getExternalEdits">getExternalEdits</a></li><li><a href="global.html#getItemWarnText">getItemWarnText</a></li><li><a href="global.html#getKpLossy">getKpLossy</a></li><li><a href="global.html#getLockFields">getLockFields</a></li><li><a href="global.html#getNameErrs">getNameErrs</a></li><li><a href="global.html#getOwn">getOwn</a></li><li><a href="global.html#getPropKey">getPropKey</a></li><li><a href="global.html#getRawModeMap">getRawModeMap</a></li><li><a href="global.html#getRefRowsExtra">getRefRowsExtra</a></li><li><a href="global.html#getRefState">getRefState</a></li><li><a href="global.html#getRefWarnText">getRefWarnText</a></li><li><a href="global.html#getRefWarns">getRefWarns</a></li><li><a href="global.html#getRowIdxs">getRowIdxs</a></li><li><a href="global.html#getRowState">getRowState</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</a></li><li><a href="global.html#getRuleWarnText">getRuleWarnText</a></li><li><a href="global.html#getRuleWarns">getRuleWarns</a></li><li><a href="global.html#getSavePreview">getSavePreview</a></li><li><a href="global.html#getSyncWarnLines">getSyncWarnLines</a></li><li><a href="global.html#hasDupKey">hasDupKey</a></li><li><a href="global.html#hasExternalDiff">hasExternalDiff</a></li><li><a href="global.html#isAuthMode">isAuthMode</a></li><li><a href="global.html#isBaselineStale">isBaselineStale</a></li><li><a href="global.html#isBaselineValid">isBaselineValid</a></li><li><a href="global.html#isDraftStale">isDraftStale</a></li><li><a href="global.html#isExternalRow">isExternalRow</a></li><li><a href="global.html#isJsonLossy">isJsonLossy</a></li><li><a href="global.html#isMain">isMain</a></li><li><a href="global.html#joinList">joinList</a></li><li><a href="global.html#joinNames">joinNames</a></li><li><a href="global.html#keepAssignByEntity">keepAssignByEntity</a></li><li><a href="global.html#keepAssignOnMissing">keepAssignOnMissing</a></li><li><a href="global.html#makeBaseline">makeBaseline</a></li><li><a href="global.html#makeRowStates">makeRowStates</a></li><li><a href="global.html#mapKeyOf">mapKeyOf</a></li><li><a href="global.html#mapNameKp">mapNameKp</a></li><li><a href="global.html#markDataReload">markDataReload</a></li><li><a href="global.html#markHasKey">markHasKey</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#pairRowsToSnapshot">pairRowsToSnapshot</a></li><li><a href="global.html#pickUniqueUser">pickUniqueUser</a></li><li><a href="global.html#planDraftSync">planDraftSync</a></li><li><a href="global.html#planFixFromType">planFixFromType</a></li><li><a href="global.html#planPurgeChain">planPurgeChain</a></li><li><a href="global.html#planPurgeFrom">planPurgeFrom</a></li><li><a href="global.html#planRefChanges">planRefChanges</a></li><li><a href="global.html#putRefEntry">putRefEntry</a></li><li><a href="global.html#putRowsToKp">putRowsToKp</a></li><li><a href="global.html#refsChanged">refsChanged</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#restoreExternalOrder">restoreExternalOrder</a></li><li><a href="global.html#restoreServerFields">restoreServerFields</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#rewriteRefs">rewriteRefs</a></li><li><a href="global.html#rowDigest">rowDigest</a></li><li><a href="global.html#runAuditFrom">runAuditFrom</a></li><li><a href="global.html#runClean">runClean</a></li><li><a href="global.html#runFixFromType">runFixFromType</a></li><li><a href="global.html#runPurgeFrom">runPurgeFrom</a></li><li><a href="global.html#splitCheckedRows">splitCheckedRows</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#tabWriteKey">tabWriteKey</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#withTabLocks">withTabLocks</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li><li><a href="global.html#writeWithCascade">writeWithCascade</a></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -55,6 +55,10 @@ import eachOwn from '../src/js/eachOwn.mjs'
|
|
|
55
55
|
let maxIdBytes = 1978
|
|
56
56
|
|
|
57
57
|
|
|
58
|
+
//純量: 字串、數字、布林、null、undefined(欄位未給)
|
|
59
|
+
let isScalar = (x) => x === null || x === undefined || typeof x === 'string' || typeof x === 'number' || typeof x === 'boolean'
|
|
60
|
+
|
|
61
|
+
|
|
58
62
|
/**
|
|
59
63
|
* 寫入前驗證可預判之 ORM 寫入失敗(ADR-026, 規則帳本 R-ORM-01)
|
|
60
64
|
*
|
|
@@ -64,6 +68,9 @@ let maxIdBytes = 1978
|
|
|
64
68
|
* 且批內不得重複(以 String(id) 比對: w-serv-orm 1.1.11 起數字主鍵存為其字串形式, 數字與其字串形式為同一主鍵).
|
|
65
69
|
* 2. 任一字串欄位之值會被 wsemi 之 clearXSS 改寫者(含 HTML 標記, 如「<」後接英文字母)即拒絕——與 w-serv-orm 寫入前之 adjustData 同一函數,
|
|
66
70
|
* 主鍵被改寫時 ORM 拒絕整批, 其他欄位則會被靜默改寫(存值與送入值不同), 兩者皆於此擋下, 使送入值即儲存值.
|
|
71
|
+
* 3. 任一欄位之值須為純量(字串、數字、布林、null、undefined)——物件、陣列、函數、symbol、bigint 一律拒絕(規則帳本 R-FIELD-SCALAR-01):
|
|
72
|
+
* 四表 schema 欄位型別只有 STRING/INTEGER/TEXT(cgrups/cpemis/crules 為 TEXT 存 JSON 字串), 無合法物件型欄位; 修正前預檢只看 isestr(vv),
|
|
73
|
+
* 巢狀字串(如 { description: { value: '<標記>' } })避過預檢而於寫入時被 w-serv-orm 靜默改寫(非拒絕), 「送入值即儲存值」不成立.
|
|
67
74
|
* 本函數為純函數: 不修改輸入、不呼叫 ORM; 主鍵是否必填由呼叫端以 opt.idRequired 指定(未給主鍵之列由 ORM 自動補主鍵者可不要求).
|
|
68
75
|
* 列物件之欄位一律依自有可列舉字串鍵逐一檢查(規則帳本 R-OBJ-ITER-01): 名為 length 之欄位與其他欄位同為一般欄位, 即使其值為非負整數(0、1、2**32-1)亦然——
|
|
69
76
|
* lodash each 對這類物件會改走索引 0..length-1 而略過全部字串欄位, 且迭代次數即 length 之值; rows 與 rowsIdOnly 須為真陣列(Array.isArray),
|
|
@@ -73,7 +80,7 @@ let maxIdBytes = 1978
|
|
|
73
80
|
* @param {Object} [opt={}] 輸入設定物件
|
|
74
81
|
* @param {Boolean} [opt.idRequired=false] 輸入主鍵是否必填, 預設false
|
|
75
82
|
* @param {Array} [opt.rowsIdOnly=[]] 輸入只參與主鍵檢查(重複、長度)而不檢查欄位標記之列陣列(如整表儲存中不會被寫入之既有列), 非真陣列視為未給, 預設[]
|
|
76
|
-
* @returns {Object|null} 回傳第一個違規 { reason, k, field }, reason 為 'rowsInvalid'、'idInvalid'、'idTooLong'、'idDuplicate'、'htmlMarkup' 之一, k 為該列於 rows 之位置(rowsIdOnly 之列為 -1), field 為欄位名; 皆通過回傳 null
|
|
83
|
+
* @returns {Object|null} 回傳第一個違規 { reason, k, field }, reason 為 'rowsInvalid'、'idInvalid'、'idTooLong'、'idDuplicate'、'fieldNotScalar'、'htmlMarkup' 之一, k 為該列於 rows 之位置(rowsIdOnly 之列為 -1), field 為欄位名; 皆通過回傳 null
|
|
77
84
|
*/
|
|
78
85
|
function validateRowsBeforeWrite(rows, opt = {}) {
|
|
79
86
|
|
|
@@ -136,12 +143,16 @@ function validateRowsBeforeWrite(rows, opt = {}) {
|
|
|
136
143
|
return err
|
|
137
144
|
}
|
|
138
145
|
|
|
139
|
-
|
|
146
|
+
//欄位型別與標記: 只檢查待寫入之列, 列物件依自有可列舉字串鍵走訪(length 為一般欄位, 見檔頭 JSDoc)
|
|
140
147
|
eachOwn(rows, (v, k) => {
|
|
141
148
|
if (v === null || typeof v !== 'object' || Array.isArray(v)) { //列須為物件(不用依 toString 判型之 iseobj: 可被 Symbol.toStringTag 偽稱為 Array 而略過全部欄位)
|
|
142
149
|
return true //跳出換下一個
|
|
143
150
|
}
|
|
144
151
|
eachOwn(v, (vv, kk) => {
|
|
152
|
+
if (!isScalar(vv)) { //非純量(物件、陣列、函數、symbol、bigint): schema 欄位型別只有 STRING/INTEGER/TEXT, 無合法物件型欄位(規則帳本 R-FIELD-SCALAR-01)
|
|
153
|
+
err = { reason: 'fieldNotScalar', k, field: kk }
|
|
154
|
+
return false //跳出
|
|
155
|
+
}
|
|
145
156
|
if (isestr(vv) && clearXSS(vv) !== vv) {
|
|
146
157
|
err = { reason: 'htmlMarkup', k, field: kk }
|
|
147
158
|
return false //跳出
|
|
@@ -172,7 +183,7 @@ export default validateRowsBeforeWrite
|
|
|
172
183
|
<br class="clear">
|
|
173
184
|
|
|
174
185
|
<footer>
|
|
175
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
186
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 23 2026 10:56:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
176
187
|
</footer>
|
|
177
188
|
|
|
178
189
|
<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#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#eachOwn">eachOwn</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#getOwn">getOwn</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</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>
|
|
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#applyPurgePlan">applyPurgePlan</a></li><li><a href="global.html#auditFrom">auditFrom</a></li><li><a href="global.html#auditRefs">auditRefs</a></li><li><a href="global.html#buildReport">buildReport</a></li><li><a href="global.html#buildRowsSend">buildRowsSend</a></li><li><a href="global.html#buildSyncRowsNew">buildSyncRowsNew</a></li><li><a href="global.html#checkBaseline">checkBaseline</a></li><li><a href="global.html#checkCascadePlan">checkCascadePlan</a></li><li><a href="global.html#checkDbNotInUse">checkDbNotInUse</a></li><li><a href="global.html#checkExternalWrite">checkExternalWrite</a></li><li><a href="global.html#checkMapKeyBatch">checkMapKeyBatch</a></li><li><a href="global.html#checkUsersWrite">checkUsersWrite</a></li><li><a href="global.html#cleanOutOf">cleanOutOf</a></li><li><a href="global.html#compareBaseline">compareBaseline</a></li><li><a href="global.html#countAndRefs">countAndRefs</a></li><li><a href="global.html#countExternalRows">countExternalRows</a></li><li><a href="global.html#countIdRenumber">countIdRenumber</a></li><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#cvKpToArr">cvKpToArr</a></li><li><a href="global.html#cvKpToObj">cvKpToObj</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#diffRefTargets">diffRefTargets</a></li><li><a href="global.html#dropServerOnlyDiff">dropServerOnlyDiff</a></li><li><a href="global.html#eachOwn">eachOwn</a></li><li><a href="global.html#fetchJson">fetchJson</a></li><li><a href="global.html#fillIdlessIds">fillIdlessIds</a></li><li><a href="global.html#findDupIndex">findDupIndex</a></li><li><a href="global.html#findKeyOtherFrom">findKeyOtherFrom</a></li><li><a href="global.html#findRefRows">findRefRows</a></li><li><a href="global.html#findTouchedDup">findTouchedDup</a></li><li><a href="global.html#fmtLossyMsg">fmtLossyMsg</a></li><li><a href="global.html#fmtVars">fmtVars</a></li><li><a href="global.html#fmtWarn">fmtWarn</a></li><li><a href="global.html#formatFixReport">formatFixReport</a></li><li><a href="global.html#formatFromAudit">formatFromAudit</a></li><li><a href="global.html#formatPurgeReport">formatPurgeReport</a></li><li><a href="global.html#genLegend">genLegend</a></li><li><a href="global.html#getAddConfirmText">getAddConfirmText</a></li><li><a href="global.html#getAddImpact">getAddImpact</a></li><li><a href="global.html#getBannerLines">getBannerLines</a></li><li><a href="global.html#getBaselineDigest">getBaselineDigest</a></li><li><a href="global.html#getCascadePreview">getCascadePreview</a></li><li><a href="global.html#getChangedIdx">getChangedIdx</a></li><li><a href="global.html#getDelConfirmText">getDelConfirmText</a></li><li><a href="global.html#getDelImpact">getDelImpact</a></li><li><a href="global.html#getDelRefCount">getDelRefCount</a></li><li><a href="global.html#getDigestFields">getDigestFields</a></li><li><a href="global.html#getDupRowsInconsistent">getDupRowsInconsistent</a></li><li><a href="global.html#getEffMode">getEffMode</a></li><li><a href="global.html#getExternalEdits">getExternalEdits</a></li><li><a href="global.html#getItemWarnText">getItemWarnText</a></li><li><a href="global.html#getKpLossy">getKpLossy</a></li><li><a href="global.html#getLockFields">getLockFields</a></li><li><a href="global.html#getNameErrs">getNameErrs</a></li><li><a href="global.html#getOwn">getOwn</a></li><li><a href="global.html#getPropKey">getPropKey</a></li><li><a href="global.html#getRawModeMap">getRawModeMap</a></li><li><a href="global.html#getRefRowsExtra">getRefRowsExtra</a></li><li><a href="global.html#getRefState">getRefState</a></li><li><a href="global.html#getRefWarnText">getRefWarnText</a></li><li><a href="global.html#getRefWarns">getRefWarns</a></li><li><a href="global.html#getRowIdxs">getRowIdxs</a></li><li><a href="global.html#getRowState">getRowState</a></li><li><a href="global.html#getRuleEnable">getRuleEnable</a></li><li><a href="global.html#getRuleWarnText">getRuleWarnText</a></li><li><a href="global.html#getRuleWarns">getRuleWarns</a></li><li><a href="global.html#getSavePreview">getSavePreview</a></li><li><a href="global.html#getSyncWarnLines">getSyncWarnLines</a></li><li><a href="global.html#hasDupKey">hasDupKey</a></li><li><a href="global.html#hasExternalDiff">hasExternalDiff</a></li><li><a href="global.html#isAuthMode">isAuthMode</a></li><li><a href="global.html#isBaselineStale">isBaselineStale</a></li><li><a href="global.html#isBaselineValid">isBaselineValid</a></li><li><a href="global.html#isDraftStale">isDraftStale</a></li><li><a href="global.html#isExternalRow">isExternalRow</a></li><li><a href="global.html#isJsonLossy">isJsonLossy</a></li><li><a href="global.html#isMain">isMain</a></li><li><a href="global.html#joinList">joinList</a></li><li><a href="global.html#joinNames">joinNames</a></li><li><a href="global.html#keepAssignByEntity">keepAssignByEntity</a></li><li><a href="global.html#keepAssignOnMissing">keepAssignOnMissing</a></li><li><a href="global.html#makeBaseline">makeBaseline</a></li><li><a href="global.html#makeRowStates">makeRowStates</a></li><li><a href="global.html#mapKeyOf">mapKeyOf</a></li><li><a href="global.html#mapNameKp">mapNameKp</a></li><li><a href="global.html#markDataReload">markDataReload</a></li><li><a href="global.html#markHasKey">markHasKey</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#pairRowsToSnapshot">pairRowsToSnapshot</a></li><li><a href="global.html#pickUniqueUser">pickUniqueUser</a></li><li><a href="global.html#planDraftSync">planDraftSync</a></li><li><a href="global.html#planFixFromType">planFixFromType</a></li><li><a href="global.html#planPurgeChain">planPurgeChain</a></li><li><a href="global.html#planPurgeFrom">planPurgeFrom</a></li><li><a href="global.html#planRefChanges">planRefChanges</a></li><li><a href="global.html#putRefEntry">putRefEntry</a></li><li><a href="global.html#putRowsToKp">putRowsToKp</a></li><li><a href="global.html#refsChanged">refsChanged</a></li><li><a href="global.html#resolveShellWorker">resolveShellWorker</a></li><li><a href="global.html#restoreExternalOrder">restoreExternalOrder</a></li><li><a href="global.html#restoreServerFields">restoreServerFields</a></li><li><a href="global.html#reuseDeletedIds">reuseDeletedIds</a></li><li><a href="global.html#rewriteRefs">rewriteRefs</a></li><li><a href="global.html#rowDigest">rowDigest</a></li><li><a href="global.html#runAuditFrom">runAuditFrom</a></li><li><a href="global.html#runClean">runClean</a></li><li><a href="global.html#runFixFromType">runFixFromType</a></li><li><a href="global.html#runPurgeFrom">runPurgeFrom</a></li><li><a href="global.html#splitCheckedRows">splitCheckedRows</a></li><li><a href="global.html#submitGuard">submitGuard</a></li><li><a href="global.html#tabWriteKey">tabWriteKey</a></li><li><a href="global.html#validateRowsBeforeWrite">validateRowsBeforeWrite</a></li><li><a href="global.html#withTabLocks">withTabLocks</a></li><li><a href="global.html#wrapInjected">wrapInjected</a></li><li><a href="global.html#wrapOperOrm">wrapOperOrm</a></li><li><a href="global.html#writeWithCascade">writeWithCascade</a></li></ul>
|
|
33
33
|
|
|
34
34
|
</nav>
|
|
35
35
|
|
|
@@ -58,7 +58,7 @@ import isfun from 'wsemi/src/isfun.mjs'
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
//keysUpstream: 上游失敗可照記之 key 白名單 = w-web-sso 對外 helper 之 K 契約 14 個 key(w-web-sso ADR-068)
|
|
61
|
-
//與 sso 之同步點: sso 之 K 契約增減 key 時須同步本表(見
|
|
61
|
+
//與 sso 之同步點: sso 之 K 契約增減 key 時須同步本表(見 sgud/rule/rulebook.md「權杖不外洩」)
|
|
62
62
|
let keysUpstream = [
|
|
63
63
|
'invalidUrl',
|
|
64
64
|
'invalidTokenSelf',
|
|
@@ -150,7 +150,7 @@ export default wrapInjected
|
|
|
150
150
|
<br class="clear">
|
|
151
151
|
|
|
152
152
|
<footer>
|
|
153
|
-
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on
|
|
153
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Fri Oct 23 2026 10:56:39 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
154
154
|
</footer>
|
|
155
155
|
|
|
156
156
|
<script>prettyPrint();</script>
|