tgo-widget-miniprogram 1.0.0

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 (55) hide show
  1. package/README.md +81 -0
  2. package/miniprogram_dist/adapters/request.js +38 -0
  3. package/miniprogram_dist/adapters/storage.js +42 -0
  4. package/miniprogram_dist/adapters/systemInfo.js +22 -0
  5. package/miniprogram_dist/chat/index.js +164 -0
  6. package/miniprogram_dist/chat/index.json +7 -0
  7. package/miniprogram_dist/chat/index.wxml +48 -0
  8. package/miniprogram_dist/chat/index.wxss +92 -0
  9. package/miniprogram_dist/components/json-render-element/index.js +374 -0
  10. package/miniprogram_dist/components/json-render-element/index.json +6 -0
  11. package/miniprogram_dist/components/json-render-element/index.wxml +218 -0
  12. package/miniprogram_dist/components/json-render-element/index.wxss +450 -0
  13. package/miniprogram_dist/components/json-render-message/index.js +89 -0
  14. package/miniprogram_dist/components/json-render-message/index.json +7 -0
  15. package/miniprogram_dist/components/json-render-message/index.wxml +25 -0
  16. package/miniprogram_dist/components/json-render-message/index.wxss +26 -0
  17. package/miniprogram_dist/components/json-render-surface/index.js +116 -0
  18. package/miniprogram_dist/components/json-render-surface/index.json +6 -0
  19. package/miniprogram_dist/components/json-render-surface/index.wxml +10 -0
  20. package/miniprogram_dist/components/json-render-surface/index.wxss +6 -0
  21. package/miniprogram_dist/components/markdown-text/index.js +23 -0
  22. package/miniprogram_dist/components/markdown-text/index.json +3 -0
  23. package/miniprogram_dist/components/markdown-text/index.wxml +1 -0
  24. package/miniprogram_dist/components/markdown-text/index.wxss +6 -0
  25. package/miniprogram_dist/components/message-bubble/index.js +12 -0
  26. package/miniprogram_dist/components/message-bubble/index.json +3 -0
  27. package/miniprogram_dist/components/message-bubble/index.wxml +3 -0
  28. package/miniprogram_dist/components/message-bubble/index.wxss +17 -0
  29. package/miniprogram_dist/components/message-input/index.js +76 -0
  30. package/miniprogram_dist/components/message-input/index.json +3 -0
  31. package/miniprogram_dist/components/message-input/index.wxml +28 -0
  32. package/miniprogram_dist/components/message-input/index.wxss +56 -0
  33. package/miniprogram_dist/components/message-list/index.js +113 -0
  34. package/miniprogram_dist/components/message-list/index.json +9 -0
  35. package/miniprogram_dist/components/message-list/index.wxml +108 -0
  36. package/miniprogram_dist/components/message-list/index.wxss +113 -0
  37. package/miniprogram_dist/components/system-message/index.js +8 -0
  38. package/miniprogram_dist/components/system-message/index.json +3 -0
  39. package/miniprogram_dist/components/system-message/index.wxml +3 -0
  40. package/miniprogram_dist/components/system-message/index.wxss +15 -0
  41. package/miniprogram_dist/core/chatStore.js +758 -0
  42. package/miniprogram_dist/core/i18n.js +66 -0
  43. package/miniprogram_dist/core/platformStore.js +86 -0
  44. package/miniprogram_dist/core/types.js +192 -0
  45. package/miniprogram_dist/services/chat.js +67 -0
  46. package/miniprogram_dist/services/messageHistory.js +46 -0
  47. package/miniprogram_dist/services/platform.js +27 -0
  48. package/miniprogram_dist/services/upload.js +74 -0
  49. package/miniprogram_dist/services/visitor.js +67 -0
  50. package/miniprogram_dist/services/wukongim.js +183 -0
  51. package/miniprogram_dist/utils/jsonRender.js +158 -0
  52. package/miniprogram_dist/utils/markdown.js +31 -0
  53. package/miniprogram_dist/utils/time.js +85 -0
  54. package/miniprogram_dist/utils/uid.js +11 -0
  55. package/package.json +37 -0
@@ -0,0 +1,183 @@
1
+ /**
2
+ * WuKongIM EasyJSSDK wrapper for miniprogram
3
+ * easyjssdk v1.1.0+ natively supports WeChat MiniProgram WebSocket
4
+ */
5
+ var WKIM = require('easyjssdk').WKIM
6
+ var WKIMEvent = require('easyjssdk').WKIMEvent
7
+ var adapter = require('../adapters/request')
8
+
9
+ function WuKongIMService() {
10
+ this._inited = false
11
+ this._im = null
12
+ this._cfg = null
13
+ this._uid = null
14
+ this._bound = false
15
+ this._hConnect = null
16
+ this._hDisconnect = null
17
+ this._hError = null
18
+ this._hMessage = null
19
+ this._hCustom = null
20
+ this._msgListeners = []
21
+ this._statusListeners = []
22
+ this._customListeners = []
23
+ }
24
+
25
+ WuKongIMService.prototype.isReady = function () {
26
+ return this._inited && !!this._im && !!this._cfg
27
+ }
28
+
29
+ WuKongIMService.prototype.getUid = function () {
30
+ return this._uid
31
+ }
32
+
33
+ WuKongIMService.prototype.init = function (opts) {
34
+ var self = this
35
+ this._cfg = Object.assign({}, opts, { channelType: opts.channelType || 'person' })
36
+ this._uid = opts.uid
37
+
38
+ return this._fetchRouteWsAddr(opts.apiBase, opts.uid, 10000).then(function (wsAddr) {
39
+ if (self._im && self._bound) {
40
+ try { self._unbindInternalEvents() } catch (e) {}
41
+ }
42
+ self._im = WKIM.init(wsAddr, { uid: opts.uid, token: opts.token || '' })
43
+ self._bindInternalEvents()
44
+ self._inited = true
45
+ })
46
+ }
47
+
48
+ WuKongIMService.prototype._bindInternalEvents = function () {
49
+ if (!this._im || this._bound) return
50
+ var self = this
51
+
52
+ this._hConnect = function (result) { self._emitStatus('connected', result) }
53
+ this._hDisconnect = function (info) { self._emitStatus('disconnected', info) }
54
+ this._hError = function (err) { self._emitStatus('error', err) }
55
+ this._hMessage = function (message) { self._emitMessage(message) }
56
+ this._hCustom = function (ev) { self._emitCustom(ev) }
57
+
58
+ this._im.on(WKIMEvent.Connect, this._hConnect)
59
+ this._im.on(WKIMEvent.Disconnect, this._hDisconnect)
60
+ this._im.on(WKIMEvent.Error, this._hError)
61
+ this._im.on(WKIMEvent.Message, this._hMessage)
62
+ this._im.on(WKIMEvent.CustomEvent, this._hCustom)
63
+ this._bound = true
64
+ }
65
+
66
+ WuKongIMService.prototype._unbindInternalEvents = function () {
67
+ if (!this._im || !this._bound) return
68
+ if (this._hConnect) this._im.off(WKIMEvent.Connect, this._hConnect)
69
+ if (this._hDisconnect) this._im.off(WKIMEvent.Disconnect, this._hDisconnect)
70
+ if (this._hError) this._im.off(WKIMEvent.Error, this._hError)
71
+ if (this._hMessage) this._im.off(WKIMEvent.Message, this._hMessage)
72
+ if (this._hCustom) this._im.off(WKIMEvent.CustomEvent, this._hCustom)
73
+ this._hConnect = this._hDisconnect = this._hError = this._hMessage = this._hCustom = null
74
+ this._bound = false
75
+ }
76
+
77
+ WuKongIMService.prototype._emitMessage = function (m) {
78
+ this._msgListeners.forEach(function (fn) { try { fn(m) } catch (e) {} })
79
+ }
80
+
81
+ WuKongIMService.prototype._emitStatus = function (s, info) {
82
+ this._statusListeners.forEach(function (fn) { try { fn(s, info) } catch (e) {} })
83
+ }
84
+
85
+ WuKongIMService.prototype._emitCustom = function (e) {
86
+ this._customListeners.forEach(function (fn) { try { fn(e) } catch (e2) {} })
87
+ }
88
+
89
+ WuKongIMService.prototype.onMessage = function (cb) {
90
+ this._msgListeners.push(cb)
91
+ var self = this
92
+ return function () {
93
+ var idx = self._msgListeners.indexOf(cb)
94
+ if (idx >= 0) self._msgListeners.splice(idx, 1)
95
+ }
96
+ }
97
+
98
+ WuKongIMService.prototype.onStatus = function (cb) {
99
+ this._statusListeners.push(cb)
100
+ var self = this
101
+ return function () {
102
+ var idx = self._statusListeners.indexOf(cb)
103
+ if (idx >= 0) self._statusListeners.splice(idx, 1)
104
+ }
105
+ }
106
+
107
+ WuKongIMService.prototype.onCustom = function (cb) {
108
+ this._customListeners.push(cb)
109
+ var self = this
110
+ return function () {
111
+ var idx = self._customListeners.indexOf(cb)
112
+ if (idx >= 0) self._customListeners.splice(idx, 1)
113
+ }
114
+ }
115
+
116
+ WuKongIMService.prototype.connect = function () {
117
+ if (!this._im) throw new Error('WuKongIMService not initialized')
118
+ this._emitStatus('connecting')
119
+ return this._im.connect()
120
+ }
121
+
122
+ WuKongIMService.prototype.disconnect = function () {
123
+ if (!this._im) return Promise.resolve()
124
+ if (typeof this._im.disconnect === 'function') {
125
+ try { return this._im.disconnect() } catch (e) { return Promise.resolve() }
126
+ }
127
+ return Promise.resolve()
128
+ }
129
+
130
+ WuKongIMService.prototype._fetchRouteWsAddr = function (apiBase, uid, timeoutMs) {
131
+ var base = apiBase.endsWith('/') ? apiBase : apiBase + '/'
132
+ var url = base + 'v1/wukongim/route?uid=' + encodeURIComponent(uid)
133
+
134
+ return adapter.request({
135
+ url: url,
136
+ method: 'GET',
137
+ timeout: timeoutMs || 10000
138
+ }).then(function (res) {
139
+ if (!res.ok) throw new Error('route HTTP ' + res.status)
140
+ return res.json().then(function (data) {
141
+ // Priority 1: wss_addr
142
+ if (data && data.wss_addr && typeof data.wss_addr === 'string' && data.wss_addr.trim()) {
143
+ return data.wss_addr.trim()
144
+ }
145
+ // Priority 2: ws_addr fallbacks
146
+ var addr = data.ws_addr || data.ws || data.ws_url || data.wsAddr || data.websocket
147
+ if (!addr && data.wss) addr = data.wss
148
+ if (!addr || typeof addr !== 'string') throw new Error('missing ws address')
149
+ var wsAddr = String(addr)
150
+ if (/^http(s)?:/i.test(wsAddr)) wsAddr = wsAddr.replace(/^http/i, 'ws')
151
+ return wsAddr
152
+ })
153
+ }).catch(function (e) {
154
+ var msg = e && e.message ? String(e.message) : String(e)
155
+ throw new Error('[WuKongIM] route fetch failed: ' + msg)
156
+ })
157
+ }
158
+
159
+ WuKongIMService.prototype.sendText = function (text, opts) {
160
+ if (!this._im || !this._cfg) throw new Error('WuKongIMService not ready')
161
+ opts = opts || {}
162
+ var to = opts.to || this._cfg.target
163
+ var payload = { type: 1, content: text }
164
+ return this._im.send(to, opts.channelType || 251, payload, {
165
+ clientMsgNo: opts.clientMsgNo,
166
+ header: opts.header
167
+ })
168
+ }
169
+
170
+ WuKongIMService.prototype.sendPayload = function (payload, opts) {
171
+ if (!this._im || !this._cfg) throw new Error('WuKongIMService not ready')
172
+ opts = opts || {}
173
+ var to = opts.to || this._cfg.target
174
+ return this._im.send(to, opts.channelType || 251, payload, {
175
+ clientMsgNo: opts.clientMsgNo,
176
+ header: opts.header
177
+ })
178
+ }
179
+
180
+ // Singleton
181
+ var instance = new WuKongIMService()
182
+
183
+ module.exports = instance
@@ -0,0 +1,158 @@
1
+ /**
2
+ * json-render utilities for miniprogram
3
+ * Ported from @json-render/react (buildSpecFromParts, groupParts)
4
+ * and tgo-widget-app JSONRenderSurface (formatActionMessage, collectActionNames)
5
+ */
6
+ var core = require('@json-render/core')
7
+
8
+ // Re-export core functions
9
+ var createMixedStreamParser = core.createMixedStreamParser
10
+ var createStateStore = core.createStateStore
11
+ var applySpecPatch = core.applySpecPatch
12
+ var nestedToFlat = core.nestedToFlat
13
+
14
+ var SPEC_DATA_PART_TYPE = 'data-' + (core.SPEC_DATA_PART || 'spec')
15
+
16
+ // ---- buildSpecFromParts ----
17
+ // Ported from @json-render/react buildSpecFromParts
18
+ function isSpecDataPart(data) {
19
+ if (typeof data !== 'object' || data === null) return false
20
+ switch (data.type) {
21
+ case 'patch':
22
+ return typeof data.patch === 'object' && data.patch !== null
23
+ case 'flat':
24
+ case 'nested':
25
+ return typeof data.spec === 'object' && data.spec !== null
26
+ default:
27
+ return false
28
+ }
29
+ }
30
+
31
+ function buildSpecFromParts(parts) {
32
+ var spec = { root: '', elements: {} }
33
+ var hasSpec = false
34
+ for (var i = 0; i < parts.length; i++) {
35
+ var part = parts[i]
36
+ if (part.type === SPEC_DATA_PART_TYPE) {
37
+ if (!isSpecDataPart(part.data)) continue
38
+ var payload = part.data
39
+ if (payload.type === 'patch') {
40
+ hasSpec = true
41
+ applySpecPatch(spec, payload.patch)
42
+ } else if (payload.type === 'flat') {
43
+ hasSpec = true
44
+ Object.assign(spec, payload.spec)
45
+ } else if (payload.type === 'nested') {
46
+ hasSpec = true
47
+ var flat = nestedToFlat(payload.spec)
48
+ Object.assign(spec, flat)
49
+ }
50
+ }
51
+ }
52
+ return hasSpec ? spec : null
53
+ }
54
+
55
+ // ---- groupParts ----
56
+ // Ported from JSONRenderMessage.tsx groupParts
57
+ function groupParts(parts) {
58
+ var groups = []
59
+ for (var i = 0; i < parts.length; i++) {
60
+ var part = parts[i]
61
+ if (part.type === 'text') {
62
+ var last = groups.length > 0 ? groups[groups.length - 1] : null
63
+ if (last && last.type === 'text') {
64
+ last.text += part.text || ''
65
+ } else {
66
+ groups.push({ type: 'text', text: part.text || '' })
67
+ }
68
+ } else {
69
+ var lastG = groups.length > 0 ? groups[groups.length - 1] : null
70
+ if (lastG && lastG.type === 'spec') {
71
+ lastG.parts.push(part)
72
+ } else {
73
+ groups.push({ type: 'spec', parts: [part] })
74
+ }
75
+ }
76
+ }
77
+ return groups
78
+ }
79
+
80
+ // ---- collectActionNames ----
81
+ // Ported from JSONRenderSurface.tsx
82
+ var BUILTIN_ACTIONS = { setState: 1, pushState: 1, removeState: 1, validateForm: 1 }
83
+
84
+ function collectActionNames(spec) {
85
+ if (!spec) return []
86
+ var names = {}
87
+ var elements = spec.elements || {}
88
+ var keys = Object.keys(elements)
89
+ for (var i = 0; i < keys.length; i++) {
90
+ var element = elements[keys[i]]
91
+ if (!element) continue
92
+ var events = element.on
93
+ if (!events || typeof events !== 'object') continue
94
+ var evKeys = Object.keys(events)
95
+ for (var j = 0; j < evKeys.length; j++) {
96
+ var binding = events[evKeys[j]]
97
+ if (Array.isArray(binding)) {
98
+ for (var k = 0; k < binding.length; k++) {
99
+ if (binding[k] && typeof binding[k].action === 'string') {
100
+ names[binding[k].action] = true
101
+ }
102
+ }
103
+ continue
104
+ }
105
+ if (binding && typeof binding.action === 'string') {
106
+ names[binding.action] = true
107
+ }
108
+ }
109
+ }
110
+ var result = []
111
+ var nameKeys = Object.keys(names)
112
+ for (var n = 0; n < nameKeys.length; n++) {
113
+ if (!BUILTIN_ACTIONS[nameKeys[n]]) {
114
+ result.push(nameKeys[n])
115
+ }
116
+ }
117
+ return result
118
+ }
119
+
120
+ // ---- formatActionMessage ----
121
+ // Ported from JSONRenderSurface.tsx
122
+ function formatActionMessage(actionName, params, state) {
123
+ var parts = ['[' + actionName + ']']
124
+ if (params) {
125
+ var pKeys = Object.keys(params)
126
+ for (var i = 0; i < pKeys.length; i++) {
127
+ var v = params[pKeys[i]]
128
+ if (v != null && v !== '') parts.push(pKeys[i] + ': ' + v)
129
+ }
130
+ }
131
+ if (state) {
132
+ var sKeys = Object.keys(state)
133
+ for (var j = 0; j < sKeys.length; j++) {
134
+ var sv = state[sKeys[j]]
135
+ if (typeof sv === 'object' && sv !== null) {
136
+ var fKeys = Object.keys(sv)
137
+ for (var k = 0; k < fKeys.length; k++) {
138
+ var fv = sv[fKeys[k]]
139
+ if (fv != null && fv !== '') parts.push(fKeys[k] + ': ' + fv)
140
+ }
141
+ } else if (sv != null && sv !== '') {
142
+ parts.push(sKeys[j] + ': ' + sv)
143
+ }
144
+ }
145
+ }
146
+ return parts.join('\n')
147
+ }
148
+
149
+ module.exports = {
150
+ createMixedStreamParser: createMixedStreamParser,
151
+ createStateStore: createStateStore,
152
+ applySpecPatch: applySpecPatch,
153
+ nestedToFlat: nestedToFlat,
154
+ buildSpecFromParts: buildSpecFromParts,
155
+ groupParts: groupParts,
156
+ collectActionNames: collectActionNames,
157
+ formatActionMessage: formatActionMessage
158
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Markdown to HTML using marked
3
+ * Output is used with <rich-text> component
4
+ */
5
+ var marked = require('marked')
6
+
7
+ // Configure marked for simple output
8
+ marked.setOptions({
9
+ breaks: true,
10
+ gfm: true
11
+ })
12
+
13
+ /**
14
+ * Parse markdown string to HTML (safe for rich-text)
15
+ * rich-text does its own sanitization so no DOMPurify needed
16
+ */
17
+ function parseMarkdown(text) {
18
+ if (!text) return ''
19
+ try {
20
+ var html = marked.parse(text)
21
+ // Remove outer <p> wrapper for simple single-paragraph text
22
+ if (typeof html === 'string') {
23
+ return html.trim()
24
+ }
25
+ return String(html || '')
26
+ } catch (e) {
27
+ return text
28
+ }
29
+ }
30
+
31
+ module.exports = { parseMarkdown: parseMarkdown }
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Time formatting utilities (ported from widget-app)
3
+ */
4
+ var i18n = require('../core/i18n')
5
+
6
+ function formatMessageTime(input) {
7
+ var msgDate = normalizeToDate(input)
8
+ if (!msgDate) return ''
9
+
10
+ var now = new Date()
11
+ var diff = now.getTime() - msgDate.getTime()
12
+
13
+ var lang = i18n.getLang()
14
+
15
+ // < 1 minute
16
+ if (diff < 60 * 1000) return lang === 'zh' ? '刚才' : 'Just now'
17
+
18
+ // < 1 hour
19
+ if (diff < 60 * 60 * 1000) {
20
+ var minutes = Math.floor(diff / (60 * 1000))
21
+ return lang === 'zh' ? minutes + '分钟前' : minutes + 'm ago'
22
+ }
23
+
24
+ var startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0)
25
+ var startOfYesterday = new Date(startOfToday.getTime() - 24 * 60 * 60 * 1000)
26
+
27
+ // Today
28
+ if (msgDate >= startOfToday) {
29
+ return fmt(msgDate, 'HH:mm')
30
+ }
31
+
32
+ // Yesterday
33
+ if (msgDate >= startOfYesterday) {
34
+ var prefix = lang === 'zh' ? '昨天' : 'Yesterday'
35
+ return prefix + ' ' + fmt(msgDate, 'HH:mm')
36
+ }
37
+
38
+ // Within 7 days
39
+ var sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)
40
+ if (msgDate > sevenDaysAgo) {
41
+ var weekday = lang === 'zh' ? weekdayCN(msgDate) : weekdayEN(msgDate)
42
+ return weekday + ' ' + fmt(msgDate, 'HH:mm')
43
+ }
44
+
45
+ // Same year
46
+ if (msgDate.getFullYear() === now.getFullYear()) {
47
+ return fmt(msgDate, 'MM-DD HH:mm')
48
+ }
49
+
50
+ // Cross year
51
+ return fmt(msgDate, 'YYYY-MM-DD HH:mm')
52
+ }
53
+
54
+ function normalizeToDate(input) {
55
+ if (input instanceof Date) return input
56
+ if (typeof input === 'number' && isFinite(input)) {
57
+ var ms = input < 1e12 ? input * 1000 : input
58
+ var d = new Date(ms)
59
+ return isNaN(d.getTime()) ? null : d
60
+ }
61
+ return null
62
+ }
63
+
64
+ function pad(n) { return n < 10 ? '0' + n : String(n) }
65
+
66
+ function fmt(d, pattern) {
67
+ var Y = d.getFullYear()
68
+ var M = pad(d.getMonth() + 1)
69
+ var D = pad(d.getDate())
70
+ var h = pad(d.getHours())
71
+ var m = pad(d.getMinutes())
72
+ if (pattern === 'HH:mm') return h + ':' + m
73
+ if (pattern === 'MM-DD HH:mm') return M + '-' + D + ' ' + h + ':' + m
74
+ return Y + '-' + M + '-' + D + ' ' + h + ':' + m
75
+ }
76
+
77
+ function weekdayCN(d) {
78
+ return ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'][d.getDay()]
79
+ }
80
+
81
+ function weekdayEN(d) {
82
+ return ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][d.getDay()]
83
+ }
84
+
85
+ module.exports = { formatMessageTime: formatMessageTime }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Generate unique clientMsgNo
3
+ */
4
+ function generateClientMsgNo(prefix) {
5
+ var p = prefix || 'cmn'
6
+ var ts = Date.now()
7
+ var rand = Math.random().toString(36).slice(2, 8)
8
+ return p + '-' + ts + '-' + rand
9
+ }
10
+
11
+ module.exports = { generateClientMsgNo: generateClientMsgNo }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "tgo-widget-miniprogram",
3
+ "version": "1.0.0",
4
+ "description": "TGO visitor chat widget for WeChat Mini Program",
5
+ "miniprogram": "miniprogram_dist",
6
+ "main": "miniprogram_dist/chat/index.js",
7
+ "files": [
8
+ "miniprogram_dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "node tools/build.js",
12
+ "ci:pack-npm": "node tools/build.js && cd example && node ci.js pack-npm",
13
+ "ci:compile": "node tools/build.js && cd example && node ci.js compile",
14
+ "ci:preview": "node tools/build.js && cd example && node ci.js preview",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "wechat",
19
+ "miniprogram",
20
+ "chat",
21
+ "widget",
22
+ "tgo"
23
+ ],
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "@json-render/core": "^0.11.0",
27
+ "easyjssdk": "^2.0.0",
28
+ "marked": "^16.4.1",
29
+ "zod": "^4.3.6"
30
+ },
31
+ "devDependencies": {
32
+ "@babel/cli": "^7.28.6",
33
+ "@babel/core": "^7.29.0",
34
+ "@babel/preset-env": "^7.29.0",
35
+ "miniprogram-ci": "^2.1.26"
36
+ }
37
+ }