w-web-api 1.0.53 → 1.0.55

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 (94) hide show
  1. package/README.md +1 -1
  2. package/dist/css/{app.fe69497a.css → app.cad4a1ca.css} +1 -1
  3. package/dist/index.tmp +1 -1
  4. package/dist/js/app-legacy.7687b23b.js +1 -0
  5. package/dist/js/app.7687b23b.js +1 -0
  6. package/dist/js/chunk-vendors-legacy.4c27cf51.js +15 -0
  7. package/dist/js/chunk-vendors.4c27cf51.js +15 -0
  8. package/dist/w-web-api.umd.js +2 -2
  9. package/dist/w-web-api.umd.js.map +1 -1
  10. package/docs/WWebApi.html +1 -1
  11. package/docs/index.html +1 -1
  12. package/docs/server_WWebApi.mjs.html +24 -34
  13. package/docs/src_components_Common_CheckYesNo.vue.html +1 -1
  14. package/logs/2026-06-19T16.log +6 -0
  15. package/logs/2026-06-20T11.log +4 -0
  16. package/logs/2026-06-20T14.log +2 -0
  17. package/logs/2026-06-21T20.log +1 -0
  18. package/logs/2026-06-21T21.log +4 -0
  19. package/logs/2026-06-22T07.log +12 -0
  20. package/logs/2026-06-22T08.log +808 -0
  21. package/logs/2026-06-22T09.log +104 -0
  22. package/logs/2026-06-22T10.log +26 -0
  23. package/logs/2026-06-22T11.log +860 -0
  24. package/logs/2026-06-22T12.log +430 -0
  25. package/logs/2026-06-22T23.log +1547 -0
  26. package/logs/2026-06-23T00.log +473 -0
  27. package/logs/2026-06-23T08.log +231 -0
  28. package/logs/2026-06-23T09.log +179 -0
  29. package/logs/2026-07-01T11.log +488 -0
  30. package/logs/2026-07-09T22.log +370 -0
  31. package/logs/2026-07-09T23.log +370 -0
  32. package/logs/2026-07-10T12.log +284 -0
  33. package/logs/2026-07-10T13.log +777 -0
  34. package/logs/2026-07-11T17.log +2 -0
  35. package/package.json +15 -14
  36. package/server/WWebApi.mjs +23 -33
  37. package/server/procLang.mjs +8 -88
  38. package/server/procProxy.mjs +89 -89
  39. package/server/srLog.mjs +2 -2
  40. package/server/staLogs/filterVpfsByWindow.mjs +27 -0
  41. package/server/staLogs/staEvent.mjs +4 -2
  42. package/server/staLogs/test_staEvent.mjs +67 -1
  43. package/settings.json +4 -0
  44. package/src/components/Layout.vue +1 -20
  45. package/src/components/LayoutContent.vue +0 -26
  46. package/src/components/LayoutContentEdit.vue +2 -2
  47. package/src/components/LayoutContentTest.vue +1 -19
  48. package/src/main.js +3 -8
  49. package/src/plugins/mUI.mjs +0 -35
  50. package/src/store/mutations.mjs +0 -14
  51. package/src/store/types.mjs +0 -3
  52. package/srv.mjs +6 -4
  53. package/tableTags.json +1 -1
  54. package/z/344/277/256/346/255/243/350/246/217/345/212/203/346/233/270.md +246 -0
  55. package/_gh-pages-deploy/.nojekyll +0 -0
  56. package/_gh-pages-deploy/WWebApi.html +0 -898
  57. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  58. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  59. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  60. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  61. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  62. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  63. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  64. package/_gh-pages-deploy/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  65. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  66. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +0 -978
  67. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  68. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  69. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  70. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  71. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +0 -1049
  72. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  73. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  74. package/_gh-pages-deploy/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  75. package/_gh-pages-deploy/index.html +0 -84
  76. package/_gh-pages-deploy/scripts/collapse.js +0 -39
  77. package/_gh-pages-deploy/scripts/commonNav.js +0 -28
  78. package/_gh-pages-deploy/scripts/linenumber.js +0 -25
  79. package/_gh-pages-deploy/scripts/nav.js +0 -12
  80. package/_gh-pages-deploy/scripts/polyfill.js +0 -4
  81. package/_gh-pages-deploy/scripts/prettify/Apache-License-2.0.txt +0 -202
  82. package/_gh-pages-deploy/scripts/prettify/lang-css.js +0 -2
  83. package/_gh-pages-deploy/scripts/prettify/prettify.js +0 -28
  84. package/_gh-pages-deploy/scripts/search.js +0 -99
  85. package/_gh-pages-deploy/server_WWebApi.mjs.html +0 -1012
  86. package/_gh-pages-deploy/src_components_Common_CheckYesNo.vue.html +0 -187
  87. package/_gh-pages-deploy/styles/jsdoc.css +0 -776
  88. package/_gh-pages-deploy/styles/prettify.css +0 -80
  89. package/dist/js/app-legacy.15819aa7.js +0 -1
  90. package/dist/js/app.15819aa7.js +0 -1
  91. package/dist/js/chunk-vendors-legacy.c1a32dd1.js +0 -15
  92. package/dist/js/chunk-vendors.c1a32dd1.js +0 -15
  93. package/src/plugins/mDataSelectorSchema.mjs +0 -30
  94. package/src/plugins/mShare.mjs +0 -44
@@ -1,1012 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
-
5
- <meta charset="utf-8">
6
- <title>server/WWebApi.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="WWebApi.html">WWebApi</a></li></ul>
33
-
34
- </nav>
35
-
36
- <div id="main">
37
-
38
- <h1 class="page-title">server/WWebApi.mjs</h1>
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
- <section>
47
- <article>
48
- <pre class="prettyprint source linenums"><code>import path from 'path'
49
- import fs from 'fs'
50
- import get from 'lodash-es/get.js'
51
- import each from 'lodash-es/each.js'
52
- import map from 'lodash-es/map.js'
53
- import keys from 'lodash-es/keys.js'
54
- import j2o from 'wsemi/src/j2o.mjs'
55
- import iseobj from 'wsemi/src/iseobj.mjs'
56
- import isestr from 'wsemi/src/isestr.mjs'
57
- import isearr from 'wsemi/src/isearr.mjs'
58
- import ispint from 'wsemi/src/ispint.mjs'
59
- import isErr from 'wsemi/src/isErr.mjs'
60
- import isfun from 'wsemi/src/isfun.mjs'
61
- import ispm from 'wsemi/src/ispm.mjs'
62
- import cint from 'wsemi/src/cint.mjs'
63
- import strleft from 'wsemi/src/strleft.mjs'
64
- import strdelleft from 'wsemi/src/strdelleft.mjs'
65
- import strright from 'wsemi/src/strright.mjs'
66
- import strdelright from 'wsemi/src/strdelright.mjs'
67
- import pm2resolve from 'wsemi/src/pm2resolve.mjs'
68
- import b642str from 'wsemi/src/b642str.mjs'
69
- import ltdtmapping from 'wsemi/src/ltdtmapping.mjs'
70
- import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
71
- import fsIsFile from 'wsemi/src/fsIsFile.mjs'
72
- import replace from 'wsemi/src/replace.mjs'
73
- import WServHapiServer from 'w-serv-hapi/src/WServHapiServer.mjs'
74
- import WServOrm from 'w-serv-orm/src/WServOrm.mjs'
75
- import procLang from './procLang.mjs'
76
- import procProxy from './procProxy.mjs'
77
- import procApis from './procApis.mjs'
78
- import staEvent from './staLogs/staEvent.mjs'
79
- import srLogInit from './srLog.mjs'
80
- import ds from '../src/schema/index.mjs'
81
-
82
-
83
- /**
84
- * API伺服器
85
- *
86
- * @class
87
- * @param {Function} WOrm 輸入資料庫ORM函數
88
- * @param {String} url 輸入資料庫連線字串,例如w-orm-lmdb為'./db',或w-orm-mongodb為'mongodb://username:password@$127.0.0.1:27017'
89
- * @param {String} db 輸入資料庫名稱字串
90
- * @param {Function} getUserByToken 輸入處理函數,函數會傳入使用者token,通過此函數處理後並回傳使用者資訊物件,並至少須提供'id'、'email'、'name'、'isAdmin'欄位,且'isAdmin'限輸入'y'或'n',且輸入'y'時會複寫權限系統該使用者之'isAdmin'欄位值
91
- * @param {Function} verifyClientUser 輸入驗證瀏覽使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
92
- * @param {Function} verifyAppUser 輸入驗證應用程序使用者身份之處理函數,函數會傳入使用者資訊物件,通過此函數識別後回傳布林值,允許使用者回傳true,反之回傳false
93
- * @param {Object} [opt={}] 輸入設定物件,預設{}
94
- * @param {Integer} [opt.serverPort=11005] 輸入伺服器通訊port,預設11005
95
- * @param {Boolean} [opt.useCheckUser=false] 輸入是否檢查使用者資訊布林值,預設false
96
- * @param {Function} [opt.getUserById=null] 輸入當useCheckUser=true時依照使用者ID取得使用者資訊物件函數,預設null
97
- * @param {Boolean} [opt.useExcludeWhenNotAdmin=false] 輸入使用ORM的select方法時是否自動刪除數據內isActive欄位之布林值,預設false
98
- * @param {Object} [opt.webName={}] 輸入站台名稱物件,至少包含語系eng與cht鍵的名稱,預設{}
99
- * @param {Object} [opt.webDescription={}] 輸入站台描述物件,至少包含語系eng與cht鍵的名稱,預設{}
100
- * @param {String} [opt.webLogo=''] 輸入站台logo字串,採base64格式,預設''
101
- * @param {String} [opt.subfolder=''] 輸入站台所在子目錄字串,提供站台位於內網採反向代理進行服務時,故需支援位於子目錄情形,預設''
102
- * @param {String} [opt.urlRedirect=''] 輸入錯誤時自動轉址字串,提供站台例如無法登入或驗證失敗時須自動轉址,預設''
103
- * @returns {Object} 回傳物件,其內server為hapi伺服器實體,wsrv為w-converhp的伺服器事件物件,wsds為w-serv-webdata的伺服器事件物件,可監聽error事件
104
- * @example
105
- *
106
- * import WOrm from 'w-orm-lmdb/src/WOrmLmdb.mjs'
107
- * import WWebApi from './server/WWebApi.mjs'
108
- * import getSettings from './g.getSettings.mjs'
109
- *
110
- *
111
- * //st
112
- * let st = getSettings()
113
- *
114
- * let url = st.dbUrl
115
- * let db = st.dbName
116
- * let opt = {
117
- *
118
- * useCheckUser: false,
119
- * getUserById: null,
120
- * useExcludeWhenNotAdmin: false,
121
- *
122
- * serverPort: 11005,
123
- * subfolder: '', //mapi
124
- * urlRedirect: 'https://www.google.com/', //本機測試時得先編譯, 再瀏覽: http://localhost:11005/
125
- *
126
- * webName: {
127
- * 'eng': 'API Service',
128
- * 'cht': 'API管理系統',
129
- * },
130
- * webDescription: {
131
- * 'eng': 'A web service package as methods to send requests to and receive responses from an API.',
132
- * 'cht': 'A web service package as methods to send requests to and receive responses from an API.',
133
- * },
134
- * webLogo: 'data:image/svg+xml;base64,...',
135
- *
136
- * }
137
- *
138
- * let getUserByToken = async (token) => {
139
- * // return {} //測試無法登入
140
- * if (token === '{token-for-application}') { //提供外部應用系統作為存取使用者
141
- * return {
142
- * id: 'id-for-application',
143
- * name: 'application',
144
- * email: 'application@example.com',
145
- * isAdmin: 'y',
146
- * }
147
- * }
148
- * if (token === 'sys') { //開發階段w-ui-loginout自動給予browser使用者(且位於localhost)的token為sys
149
- * return {
150
- * id: 'id-for-admin',
151
- * name: '測試者',
152
- * email: 'admin@example.com',
153
- * isAdmin: 'y',
154
- * }
155
- * }
156
- * console.log('invalid token', token)
157
- * console.log('於生產環境時得加入SSO等驗證token機制')
158
- * return {}
159
- * }
160
- *
161
- * let verifyClientUser = (user, from) => {
162
- * console.log('verifyClientUser/user', user)
163
- * // return false //測試無法登入
164
- * console.log('於生產環境時得加入限制瀏覽器使用者身份機制')
165
- * return user.isAdmin === 'y' //測試僅系統管理者使用
166
- * }
167
- *
168
- * let verifyAppUser = (user, from) => {
169
- * console.log('verifyAppUser/user', user)
170
- * // return false //測試無法登入
171
- * console.log('於生產環境時得加入限制應用程式使用者身份機制')
172
- * return user.isAdmin === 'y' //測試僅系統管理者使用
173
- * }
174
- *
175
- * //WWebApi
176
- * let instWWebApi = WWebApi(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser, opt)
177
- *
178
- * instWWebApi.on('error', (err) => {
179
- * console.log(err)
180
- * })
181
- *
182
- */
183
- function WWebApi(WOrm, url, db, getUserByToken, verifyClientUser, verifyAppUser, opt = {}) {
184
- let instWServHapiServer = null
185
-
186
-
187
- //check WOrm
188
- if (!isfun(WOrm)) {
189
- console.log('invalid WOrm', WOrm)
190
- throw new Error('invalid WOrm')
191
- }
192
-
193
-
194
- //check url
195
- if (!isestr(url)) {
196
- console.log('invalid url', url)
197
- throw new Error('invalid url')
198
- }
199
-
200
-
201
- //check db
202
- if (!isestr(db)) {
203
- console.log('invalid db', db)
204
- throw new Error('invalid db')
205
- }
206
-
207
-
208
- //check getUserByToken
209
- if (!isfun(getUserByToken)) {
210
- console.log('invalid getUserByToken', getUserByToken)
211
- throw new Error('invalid getUserByToken')
212
- }
213
-
214
-
215
- //check verifyClientUser
216
- if (!isfun(verifyClientUser)) {
217
- console.log('invalid verifyClientUser', verifyClientUser)
218
- throw new Error('invalid verifyClientUser')
219
- }
220
-
221
-
222
- //check verifyAppUser
223
- if (!isfun(verifyAppUser)) {
224
- console.log('invalid verifyAppUser', verifyAppUser)
225
- throw new Error('invalid verifyAppUser')
226
- }
227
-
228
-
229
- //serverPort
230
- let serverPort = get(opt, 'serverPort')
231
- if (!ispint(serverPort)) {
232
- serverPort = 11005
233
- }
234
- serverPort = cint(serverPort)
235
-
236
-
237
- //useCheckUser
238
- let useCheckUser = get(opt, 'useCheckUser', false)
239
-
240
-
241
- //getUserById
242
- let getUserById = get(opt, 'getUserById', null)
243
-
244
-
245
- //useExcludeWhenNotAdmin
246
- let useExcludeWhenNotAdmin = get(opt, 'useExcludeWhenNotAdmin', false)
247
-
248
-
249
- //webName
250
- let webName = get(opt, 'webName', {})
251
-
252
-
253
- //webDescription
254
- let webDescription = get(opt, 'webDescription', {})
255
-
256
-
257
- //webLogo
258
- let webLogo = get(opt, 'webLogo', '')
259
-
260
-
261
- //subfolder
262
- let subfolder = get(opt, 'subfolder', '')
263
- if (isestr(subfolder)) {
264
- if (strright(subfolder, 1) === '/') { //右邊不需要給「/」
265
- subfolder = strdelright(subfolder, 1)
266
- }
267
- if (strleft(subfolder, 1) !== '/') { //左邊需要給「/」
268
- subfolder = `/${subfolder}`
269
- }
270
- }
271
-
272
-
273
- //urlRedirect
274
- let urlRedirect = get(opt, 'urlRedirect', '')
275
-
276
-
277
- //params
278
- let showLanguage = get(opt, 'showLanguage', 'y')
279
- let language = get(opt, 'language', 'eng')
280
- let logFd = get(opt, 'logFd', './_logs') //srLog 寫入 + staEvent 統計共用之 log 資料夾
281
-
282
-
283
- //kpLangExt
284
- let kpLangExt = get(opt, 'kpLangExt', {})
285
-
286
-
287
- //kpLang
288
- let kpLang = procLang({ kpLangExt, webName, webDescription })
289
-
290
-
291
- //WServOrm
292
- let optWServOrm = {
293
- useCheckUser,
294
- getUserById,
295
- useExcludeWhenNotAdmin,
296
- }
297
- let wp = {}
298
- try {
299
- wp = WServOrm(ds, WOrm, url, db, optWServOrm)
300
- }
301
- catch (err) {
302
- console.log(err)
303
- }
304
- let { woItems, procOrm } = wp
305
-
306
-
307
- //srLog(後端 log;錯誤一律 log err-key 供識別,對齊 w-web-sso)
308
- let srLog = srLogInit(opt)
309
-
310
- //kpFunExt 邊界統一處理:成功記 info(供 staEvent 統計呼叫頻率);catch 後端錯誤 → srLog 該 err-key →
311
- //原樣 re-reject(前端依 key 查自己 lang 顯示)。event 統一加 'kpfun-' 前綴 → 專用事件、與 api/verifyConn 區分。
312
- let wrapErrLog = (event, fn) => {
313
- let ev = 'kpfun-' + event
314
- return async (...args) => {
315
- try {
316
- let result = await fn(...args)
317
- srLog.info({ event: ev }) //成功也記 info
318
- return result
319
- }
320
- catch (err) {
321
- srLog.error({ event: ev, err })
322
- return Promise.reject(err)
323
- }
324
- }
325
- }
326
-
327
-
328
- //procProxy
329
- let { proxyRequest } = procProxy({ srLog })
330
-
331
-
332
- //procApis
333
- let { getApisList, saveApi, deleteApi } = procApis({ woItems, procOrm, ds })
334
-
335
-
336
- //getWebInfor
337
- let getWebInfor = (userId) => {
338
- return {
339
-
340
- // webName, //已併入kpLang
341
- // webDescription, //已併入kpLang
342
- webLogo,
343
-
344
- showLanguage,
345
- language,
346
- kpLang,
347
-
348
- }
349
- }
350
-
351
-
352
- //checkUser
353
- let checkUser = async(user) => {
354
- let id = get(user, 'id', '')
355
- if (!isestr(id)) {
356
- console.log('user', user)
357
- console.log('can not get the userId')
358
- return Promise.reject('errUserIdMissing')
359
- }
360
- let email = get(user, 'email', '')
361
- if (!isestr(email)) {
362
- console.log('user', user)
363
- console.log('can not get the email of user')
364
- return Promise.reject('errUserEmailMissing')
365
- }
366
- let name = get(user, 'name', '')
367
- if (!isestr(name)) {
368
- console.log('user', user)
369
- console.log('can not get userName')
370
- return Promise.reject('errUserNameMissing')
371
- }
372
- let isAdmin = get(user, 'isAdmin', '')
373
- if (isAdmin !== 'y' &amp;&amp; isAdmin !== 'n') {
374
- console.log('user', user)
375
- console.log('user.isAdmin is not y or n', user.isAdmin)
376
- console.log('can not get the role of user')
377
- return Promise.reject('errUserRoleMissing')
378
- }
379
- return true
380
- }
381
-
382
-
383
- //getTokenUser
384
- let getTokenUser = async (token) => {
385
-
386
- //getUserByToken
387
- let userSelf = getUserByToken(token)
388
- if (ispm(userSelf)) {
389
- userSelf = await userSelf
390
- }
391
-
392
- //check
393
- if (true) {
394
- // if (!iseobj(userSelf)) {
395
- // console.log(`token`, token)
396
- // console.log(`can not find the user from token`)
397
- // return Promise.reject('errUserNotFound')
398
- // }
399
- await checkUser(userSelf)
400
- }
401
-
402
- return userSelf
403
- }
404
-
405
-
406
- //p
407
- let p = {
408
- checkToken: async(token) => {
409
-
410
- //getUserByToken
411
- let u = await getUserByToken(token)
412
- // console.log('u', u)
413
-
414
- //checkUser
415
- await checkUser(u)
416
-
417
- return true
418
- },
419
- }
420
-
421
-
422
- //getAndVerifyClientUser
423
- let getAndVerifyClientUser = async (token, from = '') => {
424
- //基於token查找client使用者, 會基於外部getUserByToken以及perm內部users進行查找並比對
425
-
426
- //getTokenUser
427
- let user = await getTokenUser(token)
428
-
429
- //verifyClientUser
430
- let b = verifyClientUser(user, from)
431
- if (ispm(b)) {
432
- b = await b
433
- }
434
-
435
- //check
436
- if (!b) {
437
- console.log('user', user)
438
- console.log(`user does not have permission`)
439
- return Promise.reject('errUserNoPermission')
440
- }
441
-
442
- srLog.info({ event: 'verifyClientUser', from, userId: get(user, 'id', '') }) //瀏覽使用者驗證通過
443
- return user
444
- }
445
-
446
-
447
- //getAndVerifyAppUser
448
- let getAndVerifyAppUser = async (token, from = '') => {
449
- //基於token查找app使用者, 會基於外部getUserByToken進行查找, 故只要getUserByToken提供使用者即可, 可支援getUserByToken給予針對應用程式所產生之虛擬使用者
450
-
451
- //user
452
- let user = null
453
- if (isestr(token)) {
454
- user = getUserByToken(token)
455
- if (ispm(user)) {
456
- user = await user
457
- }
458
- }
459
- // console.log('user', user)
460
-
461
- //check
462
- if (!iseobj(user)) {
463
- console.log(`token`, token)
464
- console.log(`can not find the user from token`)
465
- return Promise.reject('errUserNotFound')
466
- }
467
-
468
- //verifyAppUser
469
- let b = verifyAppUser(user, from)
470
- if (ispm(b)) {
471
- b = await b
472
- }
473
-
474
- //check
475
- if (!b) {
476
- console.log('user', user)
477
- console.log(`user does not have permission`)
478
- return Promise.reject('errUserNoPermission')
479
- }
480
-
481
- srLog.info({ event: 'verifyAppUser', from, userId: get(user, 'id', '') }) //應用程式使用者驗證通過
482
- return user
483
- }
484
-
485
-
486
- // //getAPIsList
487
- // let getAPIsList = async (query = {}) => {
488
- // let rs = await woItems.apis.select(query)
489
- // return rs
490
- // }
491
-
492
-
493
- //parsePayload
494
- let parsePayload = async (req) => {
495
-
496
- //payload
497
- let payload = get(req, 'payload')
498
-
499
- //to obj
500
- if (isestr(payload)) {
501
- payload = j2o(payload)
502
- }
503
-
504
- //check
505
- if (!iseobj(payload)) {
506
- console.log('payload', payload)
507
- console.log(`invalid payload in req`)
508
- return Promise.reject('errPayloadInvalid')
509
- }
510
-
511
- //group
512
- let group = get(payload, 'group', '')
513
-
514
- //check
515
- if (!isestr(group)) {
516
- console.log('payload', payload)
517
- console.log(`invalid group in payload`)
518
- return Promise.reject('errGroupInvalid')
519
- }
520
-
521
- //rows
522
- let rows = get(payload, 'rows', [])
523
-
524
- //check
525
- if (!isearr(rows)) {
526
- console.log('payload', payload)
527
- console.log(`invalid rows in payload`)
528
- return Promise.reject('errRowsInvalid')
529
- }
530
-
531
- //r
532
- let r = {
533
- group,
534
- rows,
535
- }
536
-
537
- return r
538
- }
539
-
540
-
541
- // //updateAPIs
542
- // let updateAPIs = async (inp = {}) => {
543
-
544
- // //spread inp
545
- // let { apis: rsApis } = inp
546
- // // console.log('group', group)
547
- // // console.log('rsApis', rsApis)
548
-
549
- // //save
550
- // let r = await woItems.apis.save(rsApis)
551
-
552
- // return r
553
- // }
554
-
555
-
556
- //syncAndReplaceTabs
557
- let syncAndReplaceTabs = async (userId, inp, keyTable) => {
558
-
559
- //group
560
- let group = get(inp, 'group', '')
561
- // console.log('group', group)
562
-
563
- //check
564
- if (!isestr(group)) {
565
- console.log('inp', inp)
566
- console.log('group', group)
567
- console.log(`invalid group`)
568
- return Promise.reject('errGroupInvalid')
569
- }
570
-
571
- //rows
572
- let rows = get(inp, 'rows', [])
573
- // console.log('rows', rows)
574
-
575
- //check
576
- if (!isearr(rows)) {
577
- console.log('inp', inp)
578
- console.log('keyTable', keyTable)
579
- return Promise.reject('errRowsInvalid')
580
- }
581
-
582
- //save from
583
- rows = map(rows, (v, k) => {
584
- // v.order = k + 1 //order大部分由外部給予, 不能複寫
585
- v.group = group
586
- return v
587
- })
588
-
589
- //偵測b64自動恢復
590
- if (keyTable === 'apis') {
591
- each(rows, (row, krow) => {
592
- // console.log(kapi, row.name)
593
- each(row, (v, k) => {
594
- // console.log(k, v)
595
- if (isestr(v)) {
596
- if (strleft(v, 7) === 'base64:') {
597
- // console.log(k, 'get base64')
598
- v = strdelleft(v, 7)
599
- v = b642str(v)
600
- // console.log(v)
601
- rows[krow][k] = v
602
- }
603
- }
604
- })
605
- })
606
- }
607
-
608
- //ltdtmapping
609
- rows = ltdtmapping(rows, ds[keyTable].keys)
610
- // console.log('ltdtmapping rows', rows)
611
-
612
- //delAll group
613
- await woItems[keyTable].delAll({ group })
614
-
615
- //insert
616
- // let r = await woItems[keyTable].insert(rows)
617
- let r = await procOrm(userId, keyTable, 'insert', rows) //須使用procOrm才有辦法自動給予相關欄位
618
- // console.log('r', r)
619
-
620
- return r
621
- }
622
-
623
-
624
- //pathStaticFiles
625
- let pathStaticFiles = 'dist'
626
- let npmPathStaticFiles = './node_modules/w-web-api/dist'
627
- if (fsIsFolder(npmPathStaticFiles)) {
628
- pathStaticFiles = npmPathStaticFiles
629
- }
630
- // console.log('pathStaticFiles', pathStaticFiles)
631
-
632
-
633
- //subfolder
634
- let fnEntryIn = 'index.tmp'
635
- let fnEntryOut = 'index.html'
636
- try {
637
- let fpEntryIn = path.resolve(pathStaticFiles, fnEntryIn)
638
- if (!fsIsFile(fpEntryIn)) {
639
- fpEntryIn = path.resolve(pathStaticFiles, fnEntryOut) //本機開發另使用html替代tmp
640
- }
641
- if (!fsIsFile(fpEntryIn)) {
642
- console.log('fpEntryIn', fpEntryIn)
643
- throw new Error(`invalid fpEntryIn`)
644
- }
645
- let fpEntryOut = path.resolve(pathStaticFiles, fnEntryOut)
646
- let c = fs.readFileSync(fpEntryIn, 'utf8')
647
- c = replace(c, '/mapi/', '{sfd}/') //方法同genEntry
648
- c = replace(c, '{sfd}', subfolder)
649
- c = replace(c, '{urlRedirect}', urlRedirect)
650
- c = replace(c, '{language}', language) //注入初始語系 → window.___pmwperm___.language(前端 getLang 之來源之一)
651
- fs.writeFileSync(fpEntryOut, c, 'utf8')
652
- }
653
- catch (err) {
654
- console.log(err)
655
- console.log(`can not generate ${fnEntryOut}`)
656
- }
657
-
658
-
659
- //apis
660
- let apis = [
661
-
662
- {
663
- method: 'GET',
664
- path: '/api/getUserByToken', //未登入主頁時需先檢測token, getUserByToken為w-ui-loginout預設值, 若要更改兩邊須同時修改
665
- handler: async function (req, res) {
666
- // console.log('getUserByToken', req)
667
-
668
- async function core() {
669
-
670
- //token
671
- let token = get(req, 'query.token', '')
672
-
673
- //check
674
- if (!isestr(token)) {
675
- console.log('req.query', get(req, 'query'))
676
- console.log('token', token)
677
- console.log('[API]getUserByToken/check token: invalid token')
678
- console.log(`token does not have permission`)
679
- return Promise.reject('errTokenNoPermission')
680
- }
681
-
682
- //getAndVerifyClientUser
683
- let user = await getAndVerifyClientUser(token, 'getUserByToken')
684
-
685
- //check
686
- if (!iseobj(user)) {
687
- console.log('token', token)
688
- console.log('[API]getUserByToken/check user: invalid user')
689
- console.log(`token does not have permission`)
690
- return Promise.reject('errTokenNoPermission')
691
- }
692
-
693
- srLog.info({ event: 'api/getUserByToken', userId: get(user, 'id', '') })
694
- return user
695
- }
696
-
697
- //pm2resolve core
698
- let r = await pm2resolve(core)() //w-ui-loginout接收已預設格式用pm2resolve轉過, 會提取state進行判斷
699
- if (isErr(r.msg)) {
700
- r.msg = r.msg.message
701
- }
702
- // console.log('getUserByToken', r)
703
-
704
- return r
705
- },
706
- },
707
-
708
- // {
709
- // method: 'GET',
710
- // path: '/getAPIsList',
711
- // handler: async function (req, res) {
712
- // // console.log('getAPIsList', req)
713
-
714
- // async function core() {
715
-
716
- // //token
717
- // let token = get(req, 'query.token', '')
718
-
719
- // //check
720
- // if (!isestr(token)) {
721
- // console.log('req.query', get(req, 'query'))
722
- // console.log('token', token)
723
- // console.log('[API]getAPIsList/check token: invalid token')
724
- // console.log(`token does not have permission`)
725
- // return Promise.reject('errTokenNoPermission')
726
- // }
727
-
728
- // //getAndVerifyClientUser
729
- // let user = await getAndVerifyClientUser(token, 'getAPIsList')
730
-
731
- // //check
732
- // if (!iseobj(user)) {
733
- // console.log('token', token)
734
- // console.log('[API]getAPIsList/check user: invalid user')
735
- // console.log(`token does not have permission`)
736
- // return Promise.reject('errTokenNoPermission')
737
- // }
738
-
739
- // //getAPIsList
740
- // let r = await getAPIsList({ isActive: 'y' })
741
-
742
- // return r
743
- // }
744
-
745
- // //pm2resolve core
746
- // let r = await pm2resolve(core)()
747
- // if (isErr(r.msg)) {
748
- // r.msg = r.msg.message
749
- // }
750
- // // console.log('getAPIsList', r)
751
-
752
- // return r
753
- // },
754
- // },
755
-
756
- // {
757
- // method: 'POST',
758
- // path: '/updateAPIs',
759
- // handler: async function (req, res) {
760
- // // console.log('updateAPIs', req)
761
- // // console.log('payload', req.payload)
762
-
763
- // async function core() {
764
-
765
- // //token
766
- // let token = get(req, 'query.token', '')
767
-
768
- // //check
769
- // if (!isestr(token)) {
770
- // console.log('req.query', get(req, 'query'))
771
- // console.log('token', token)
772
- // console.log('[API]updateAPIs/check token: invalid token')
773
- // console.log(`token does not have permission`)
774
- // return Promise.reject('errTokenNoPermission')
775
- // }
776
-
777
- // //getAndVerifyClientUser
778
- // let user = await getAndVerifyClientUser(token, 'updateAPIs')
779
-
780
- // //check
781
- // if (!iseobj(user)) {
782
- // console.log('token', token)
783
- // console.log('[API]updateAPIs/check user: invalid user')
784
- // console.log(`token does not have permission`)
785
- // return Promise.reject('errTokenNoPermission')
786
- // }
787
-
788
- // //parsePayload
789
- // let inp = await parsePayload(req)
790
-
791
- // //updateAPIs
792
- // let r = await updateAPIs(inp)
793
-
794
- // return r
795
- // }
796
-
797
- // //pm2resolve core
798
- // let r = await pm2resolve(core)()
799
- // if (isErr(r.msg)) {
800
- // r.msg = r.msg.message
801
- // }
802
- // // console.log('updateAPIs', r)
803
-
804
- // return r
805
- // },
806
- // },
807
-
808
- {
809
- method: 'POST',
810
- path: '/syncAndReplaceTabs',
811
- handler: async function (req, res) {
812
- // console.log('syncAndReplaceTabs', req)
813
- // console.log('payload', req.payload)
814
-
815
- async function core() {
816
-
817
- //token
818
- let token = get(req, 'query.token', '')
819
-
820
- //check
821
- if (!isestr(token)) {
822
- console.log('req.query', get(req, 'query'))
823
- console.log('token', token)
824
- console.log('[API]syncAndReplaceTabs/check token: invalid token')
825
- console.log(`token does not have permission`)
826
- return Promise.reject('errTokenNoPermission')
827
- }
828
-
829
- //keyTable
830
- let keyTable = get(req, 'query.keyTable', '')
831
-
832
- //check
833
- if (!isestr(keyTable)) {
834
- console.log('req.query', get(req, 'query'))
835
- console.log('keyTable', keyTable)
836
- console.log('[API]syncAndReplaceTabs/check keyTable: invalid keyTable')
837
- console.log(`token does not have permission`)
838
- return Promise.reject('errTokenNoPermission')
839
- }
840
-
841
- //check keyTable
842
- let allowedTables = ['apis']
843
- if (!allowedTables.includes(keyTable)) {
844
- console.log('[API]syncAndReplaceTabs/check keyTable: unexpected keyTable', keyTable)
845
- return Promise.reject('errKeyTableInvalid')
846
- }
847
-
848
- //getAndVerifyAppUser
849
- let user = await getAndVerifyAppUser(token, 'syncAndReplaceTabs')
850
-
851
- //check
852
- if (!iseobj(user)) {
853
- console.log('token', token)
854
- console.log('[API]syncAndReplaceTabs/check user: invalid user')
855
- console.log(`token does not have permission`)
856
- return Promise.reject('errTokenNoPermission')
857
- }
858
-
859
- //userId
860
- let userId = get(user, 'id', '')
861
-
862
- //check userId
863
- if (!isestr(userId)) {
864
- console.log('token', token)
865
- console.log('user', user)
866
- console.log('[API]syncAndReplaceTabs/check userId: invalid userId')
867
- console.log(`token does not have permission`)
868
- return Promise.reject('errTokenNoPermission')
869
- }
870
-
871
- //parsePayload
872
- let inp = await parsePayload(req)
873
-
874
- //syncAndReplaceTabs
875
- let r = await syncAndReplaceTabs(userId, inp, keyTable)
876
-
877
- srLog.info({ event: 'api/syncAndReplaceTabs', userId, keyTable })
878
- return r
879
- }
880
-
881
- //pm2resolve core
882
- let r = await pm2resolve(core)()
883
- if (isErr(r.msg)) {
884
- r.msg = r.msg.message
885
- }
886
- // console.log('syncAndReplaceTabs', r)
887
-
888
- return r
889
- },
890
- },
891
-
892
- ]
893
-
894
-
895
- //tableNamesExec, tableNamesSync
896
- let tableNamesExec = keys(ds)
897
- // let tableNamesSync = filter(tableNamesExec, (v) => {
898
- // return strright(v, 5) !== 'Items'//不同步數據
899
- // })
900
- let tableNamesSync = tableNamesExec
901
-
902
-
903
- //WServHapiServer
904
- instWServHapiServer = new WServHapiServer({
905
- port: opt.serverPort,
906
- pathStaticFiles,
907
- apiName: 'api',
908
- apis,
909
- tokenType: 'Bearer',
910
- verifyConn: async ({ apiType, authorization, query, headers, req }) => {
911
- // console.log('verifyConn', `apiType[${apiType}]`, `authorization[${authorization}]`)
912
-
913
- //token
914
- let token = strdelleft(authorization, 7) //刪除Bearer
915
- // console.log('token', token)
916
-
917
- //check
918
- if (!isestr(token)) {
919
- console.log('apiType', apiType)
920
- console.log('authorization', authorization)
921
- console.log('invalid token')
922
- return false
923
- }
924
-
925
- //checkToken
926
- let b = await p.checkToken(token)
927
- // console.log('b', b)
928
-
929
- srLog.info({ event: 'verifyConn', apiType }) //連線驗證通過(checkToken 失敗時會 throw 不到此)
930
- return b
931
- },
932
- getUserIdByToken: async (token) => { //可使用async或sync函數
933
- // console.log('getUserIdByToken', token)
934
- if (!isestr(token)) {
935
- return ''
936
- }
937
- let user = await getUserByToken(token)
938
- let userId = get(user, 'id', '')
939
- return userId
940
- },
941
- useDbOrm: true,
942
- kpOrm: woItems,
943
- operOrm: procOrm, //procOrm的輸入為: userId, tableName, methodName, input
944
- tableNamesExec,
945
- methodsExec: ['select', 'insert', 'save', 'del'], //mix需於procOrm內註冊以提供
946
- tableNamesSync,
947
- kpFunExt: { //接收參數第1個為userId, 之後才是前端給予參數(皆經 wrapErrLog:錯誤 srLog err-key 後 re-reject)
948
-
949
- getWebInfor: wrapErrLog('getWebInfor', getWebInfor),
950
-
951
- proxyRequest: wrapErrLog('proxyRequest', (userId, reqSpec) => {
952
- return proxyRequest(reqSpec)
953
- }),
954
-
955
- getApisList: wrapErrLog('getApisList', (userId) => {
956
- return getApisList(userId)
957
- }),
958
- saveApi: wrapErrLog('saveApi', (userId, row) => {
959
- return saveApi(userId, row)
960
- }),
961
- deleteApi: wrapErrLog('deleteApi', (userId, id) => {
962
- return deleteApi(userId, id)
963
- }),
964
-
965
- //統計資訊頁:回傳各 event 之時段發生頻率(讀 logFd 之 log)。連線已由 verifyClientUser 限管理員,
966
- //故此處不另檢查(同 getApisList)。timeLength 天數 / timeInterval 'hr'|'day'。
967
- getStaEvent: wrapErrLog('getStaEvent', (userId, timeLength = 7, timeInterval = 'hr') => {
968
- return staEvent(timeLength, timeInterval, { fdLog: logFd })
969
- }),
970
-
971
- // getAPIsList: (userId, query = {}) => { //待提供api管理系統界面使用
972
- // return getAPIsList(query)
973
- // },
974
- // updateApis: (userId, rows) => { //待提供api管理系統界面使用
975
- // return updateApis(rows)
976
- // },
977
-
978
- },
979
- fnTableTags: 'tableTags-web-api.json',
980
- })
981
-
982
-
983
- return instWServHapiServer
984
- }
985
-
986
-
987
- export default WWebApi
988
- </code></pre>
989
- </article>
990
- </section>
991
-
992
-
993
-
994
-
995
-
996
-
997
- </div>
998
-
999
- <br class="clear">
1000
-
1001
- <footer>
1002
- Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 4.0.5</a> on Mon Jun 22 2026 15:42:09 GMT+0800 (台北標準時間) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
1003
- </footer>
1004
-
1005
- <script>prettyPrint();</script>
1006
- <script src="scripts/polyfill.js"></script>
1007
- <script src="scripts/linenumber.js"></script>
1008
-
1009
-
1010
-
1011
- </body>
1012
- </html>