alemonjs 2.1.85 → 2.1.87

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.
@@ -21,5 +21,6 @@ const defineRouter = routes => {
21
21
  current: routes
22
22
  };
23
23
  };
24
+ global.defineRouter = defineRouter;
24
25
 
25
26
  export { defineRouter, lazy, runHandler };
@@ -1 +1,9 @@
1
- export {};
1
+ import '../define-children.js';
2
+ import '../define-response.js';
3
+ import '../define-middleware.js';
4
+ import '../define-router.js';
5
+ import '../format/message-api.js';
6
+ import './event-response.js';
7
+ import './event-middleware.js';
8
+ import './event-utils.js';
9
+ import './event-group.js';
@@ -1,3 +1,12 @@
1
+ import '../define-children.js';
2
+ import '../define-response.js';
3
+ import '../define-middleware.js';
4
+ import '../define-router.js';
5
+ import '../format/message-api.js';
6
+ import './event-response.js';
7
+ import './event-middleware.js';
8
+ import './event-utils.js';
9
+ import './event-group.js';
1
10
  import { cbpClient } from './cbp/connects/client.js';
2
11
  import 'flatted';
3
12
  import 'fs';
@@ -1,103 +1,135 @@
1
1
  import { DOCTYPE, renderToString, createElement, Component, Html, Head, Title, Style, Body, Div, P } from '../../../../common/react.js';
2
2
 
3
- const escapeHtml = (value) => String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
3
+ const escapeHtml = (value) => {
4
+ return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
5
+ };
4
6
  const styles = `
5
7
  :root {
6
- --bg: #f3efe5;
7
- --panel: rgba(255, 251, 245, 0.88);
8
- --panel-strong: #fffaf2;
8
+ --bg: #ece5d6;
9
+ --bg-deep: #e4dac6;
10
+ --panel: rgba(255, 251, 244, 0.76);
11
+ --panel-strong: rgba(255, 250, 242, 0.92);
9
12
  --text: #17212b;
10
- --muted: #6a7684;
11
- --line: rgba(23, 33, 43, 0.08);
12
- --accent: #d96c28;
13
- --accent-strong: #a54a13;
14
- --shadow: 0 24px 60px rgba(47, 35, 20, 0.12);
13
+ --muted: #667281;
14
+ --line: rgba(20, 29, 36, 0.09);
15
+ --line-strong: rgba(20, 29, 36, 0.16);
16
+ --accent: #cf6a2c;
17
+ --accent-strong: #9b4717;
18
+ --accent-soft: rgba(207, 106, 44, 0.16);
19
+ --shadow: 0 24px 80px rgba(49, 34, 17, 0.14);
20
+ --shadow-card: 0 18px 40px rgba(33, 37, 41, 0.08);
15
21
  }
16
22
  * { box-sizing: border-box; }
17
23
  html, body { margin: 0; min-height: 100%; }
18
24
  body {
19
- font-family: "SF Pro Display", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
25
+ font-family: "Avenir Next", "SF Pro Display", "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
20
26
  color: var(--text);
21
27
  background:
22
- radial-gradient(circle at top left, rgba(217, 108, 40, 0.18), transparent 28%),
23
- radial-gradient(circle at right center, rgba(78, 140, 124, 0.14), transparent 26%),
24
- linear-gradient(180deg, #f8f4ec 0%, var(--bg) 100%);
28
+ radial-gradient(circle at 12% 12%, rgba(207, 106, 44, 0.22), transparent 0 26%),
29
+ radial-gradient(circle at 88% 18%, rgba(69, 119, 104, 0.18), transparent 0 24%),
30
+ radial-gradient(circle at 50% 120%, rgba(33, 58, 78, 0.08), transparent 0 28%),
31
+ linear-gradient(180deg, #f8f4ec 0%, var(--bg) 48%, var(--bg-deep) 100%);
32
+ background-attachment: fixed;
33
+ }
34
+ body::before {
35
+ content: "";
36
+ position: fixed;
37
+ inset: 0;
38
+ background:
39
+ linear-gradient(rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.1)),
40
+ repeating-linear-gradient(
41
+ 90deg,
42
+ transparent 0,
43
+ transparent 31px,
44
+ rgba(255, 255, 255, 0.18) 31px,
45
+ rgba(255, 255, 255, 0.18) 32px
46
+ );
47
+ opacity: 0.22;
48
+ pointer-events: none;
25
49
  }
26
50
  .page {
27
- width: min(1680px, calc(100vw - 32px));
51
+ position: relative;
52
+ width: min(1520px, calc(100vw - 32px));
28
53
  margin: 0 auto;
29
- padding: clamp(28px, 4vw, 56px) 0 64px;
54
+ padding: clamp(24px, 3vw, 44px) 0 72px;
30
55
  }
31
56
  .hero {
32
57
  position: relative;
33
58
  overflow: hidden;
34
- padding: clamp(28px, 4vw, 56px);
35
- border-radius: 32px;
36
- background: linear-gradient(135deg, rgba(255, 250, 242, 0.95), rgba(255, 244, 231, 0.88));
37
- border: 1px solid rgba(255, 255, 255, 0.72);
59
+ isolation: isolate;
60
+ display: grid;
61
+ align-items: end;
62
+ min-height: clamp(240px, 32vw, 380px);
63
+ padding: clamp(28px, 4vw, 52px);
64
+ border-radius: 36px;
65
+ background:
66
+ linear-gradient(135deg, rgba(255, 250, 242, 0.84), rgba(247, 236, 220, 0.88)),
67
+ linear-gradient(180deg, rgba(255, 255, 255, 0.24), rgba(255, 255, 255, 0));
68
+ border: 1px solid rgba(255, 255, 255, 0.68);
38
69
  box-shadow: var(--shadow);
70
+ backdrop-filter: blur(20px);
39
71
  }
72
+ .hero::before,
40
73
  .hero::after {
41
74
  content: "";
42
75
  position: absolute;
43
- inset: auto -8% -48% auto;
44
- width: min(38vw, 520px);
45
- aspect-ratio: 1;
46
76
  border-radius: 999px;
47
- background: radial-gradient(circle, rgba(217, 108, 40, 0.18), transparent 62%);
48
77
  pointer-events: none;
49
78
  }
79
+ .hero::before {
80
+ inset: -18% auto auto -8%;
81
+ width: min(34vw, 420px);
82
+ aspect-ratio: 1;
83
+ background: radial-gradient(circle, rgba(244, 161, 85, 0.28), transparent 62%);
84
+ filter: blur(8px);
85
+ opacity: 0.95;
86
+ }
87
+ .hero::after {
88
+ inset: auto -8% -44% auto;
89
+ width: min(42vw, 560px);
90
+ aspect-ratio: 1;
91
+ background: radial-gradient(circle, rgba(49, 83, 104, 0.22), transparent 62%);
92
+ filter: blur(16px);
93
+ }
50
94
  .hero-kicker {
51
- margin: 0 0 12px;
52
- font-size: clamp(14px, 1.2vw, 18px);
95
+ position: relative;
96
+ z-index: 1;
97
+ display: inline-flex;
98
+ width: fit-content;
99
+ margin: 0 0 16px;
100
+ padding: 10px 14px;
101
+ border-radius: 999px;
102
+ border: 1px solid rgba(155, 71, 23, 0.14);
103
+ background: rgba(255, 255, 255, 0.62);
104
+ box-shadow: 0 8px 22px rgba(155, 71, 23, 0.08);
105
+ font-size: clamp(12px, 1vw, 14px);
53
106
  letter-spacing: 0.18em;
54
107
  text-transform: uppercase;
55
108
  color: var(--accent-strong);
56
109
  }
57
110
  .hero-title {
111
+ position: relative;
112
+ z-index: 1;
58
113
  margin: 0;
59
- max-width: 12ch;
60
- font-size: clamp(40px, 7vw, 86px);
61
- line-height: 0.95;
62
- letter-spacing: -0.04em;
63
- }
64
- .hero-desc {
65
- margin: 18px 0 0;
66
- max-width: 56rem;
67
- font-size: clamp(18px, 2vw, 28px);
68
- line-height: 1.6;
69
- color: var(--muted);
70
- }
71
- .hero-meta {
72
- display: flex;
73
- flex-wrap: wrap;
74
- gap: 14px;
75
- margin-top: 28px;
76
- }
77
- .hero-pill {
78
- display: inline-flex;
79
- align-items: center;
80
- gap: 10px;
81
- padding: 12px 18px;
82
- border-radius: 999px;
83
- background: rgba(255, 255, 255, 0.78);
84
- border: 1px solid rgba(23, 33, 43, 0.08);
85
- font-size: clamp(14px, 1.4vw, 18px);
86
- }
87
- .hero-pill strong {
88
- color: var(--accent-strong);
114
+ max-width: 9ch;
115
+ font-size: clamp(42px, 8vw, 96px);
116
+ line-height: 0.88;
117
+ letter-spacing: -0.06em;
118
+ text-wrap: balance;
89
119
  }
90
120
  .section-head {
91
121
  display: flex;
92
122
  align-items: end;
93
123
  justify-content: space-between;
94
124
  gap: 20px;
95
- margin: 28px 0 18px;
125
+ margin: 34px 0 22px;
96
126
  padding: 0 6px;
97
127
  }
98
128
  .section-title {
99
129
  margin: 0;
100
- font-size: clamp(28px, 3vw, 42px);
130
+ font-size: clamp(28px, 3vw, 40px);
131
+ line-height: 1;
132
+ letter-spacing: -0.04em;
101
133
  }
102
134
  .section-note {
103
135
  margin: 0;
@@ -106,27 +138,72 @@ const styles = `
106
138
  }
107
139
  .app-grid {
108
140
  display: grid;
109
- grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr));
110
- gap: 18px;
141
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
142
+ gap: 20px;
111
143
  }
112
144
  .app-card {
145
+ position: relative;
113
146
  display: flex;
114
147
  flex-direction: column;
115
- gap: 18px;
116
- min-height: 280px;
148
+ justify-content: space-between;
149
+ gap: 24px;
150
+ min-height: 240px;
117
151
  padding: 24px;
118
- border-radius: 28px;
152
+ border-radius: 30px;
119
153
  text-decoration: none;
120
154
  color: inherit;
121
- background: var(--panel);
155
+ background:
156
+ linear-gradient(180deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.14)),
157
+ var(--panel);
122
158
  border: 1px solid var(--line);
123
- box-shadow: 0 14px 40px rgba(30, 37, 44, 0.08);
124
- transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
159
+ box-shadow: var(--shadow-card);
160
+ backdrop-filter: blur(18px);
161
+ transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease, background 180ms ease;
162
+ }
163
+ .app-card::before,
164
+ .app-card::after {
165
+ content: "";
166
+ position: absolute;
167
+ pointer-events: none;
168
+ }
169
+ .app-card::before {
170
+ inset: 0;
171
+ border-radius: inherit;
172
+ padding: 1px;
173
+ background: linear-gradient(135deg, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0), rgba(207, 106, 44, 0.12));
174
+ -webkit-mask:
175
+ linear-gradient(#000 0 0) content-box,
176
+ linear-gradient(#000 0 0);
177
+ -webkit-mask-composite: xor;
178
+ mask-composite: exclude;
179
+ opacity: 0.85;
180
+ }
181
+ .app-card::after {
182
+ top: -24%;
183
+ right: -10%;
184
+ width: 56%;
185
+ aspect-ratio: 1;
186
+ border-radius: 999px;
187
+ background: radial-gradient(circle, rgba(207, 106, 44, 0.16), transparent 68%);
188
+ transition: transform 180ms ease, opacity 180ms ease;
125
189
  }
126
190
  .app-card:hover {
127
- transform: translateY(-4px);
128
- border-color: rgba(217, 108, 40, 0.28);
129
- box-shadow: 0 24px 50px rgba(30, 37, 44, 0.12);
191
+ transform: translateY(-6px);
192
+ border-color: rgba(207, 106, 44, 0.3);
193
+ box-shadow: 0 28px 60px rgba(30, 37, 44, 0.14);
194
+ background:
195
+ linear-gradient(180deg, rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0.18)),
196
+ rgba(255, 251, 244, 0.92);
197
+ }
198
+ .app-card:hover::after {
199
+ transform: scale(1.08);
200
+ opacity: 1;
201
+ }
202
+ .app-card:nth-child(3n + 2)::after {
203
+ background: radial-gradient(circle, rgba(72, 122, 107, 0.18), transparent 68%);
204
+ }
205
+ .app-card:nth-child(3n + 3)::after {
206
+ background: radial-gradient(circle, rgba(53, 92, 128, 0.16), transparent 68%);
130
207
  }
131
208
  .app-card__top,
132
209
  .app-card__bottom {
@@ -135,107 +212,114 @@ const styles = `
135
212
  justify-content: space-between;
136
213
  gap: 16px;
137
214
  }
215
+ .app-card__top {
216
+ align-items: start;
217
+ }
138
218
  .app-eyebrow {
139
- margin: 0 0 8px;
140
- font-size: 13px;
219
+ display: inline-flex;
220
+ margin: 0 0 14px;
221
+ padding: 8px 12px;
222
+ border-radius: 999px;
223
+ background: rgba(255, 255, 255, 0.58);
224
+ border: 1px solid rgba(155, 71, 23, 0.1);
225
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
226
+ font-size: 11px;
141
227
  letter-spacing: 0.16em;
142
228
  text-transform: uppercase;
143
229
  color: var(--accent-strong);
144
230
  }
145
231
  .app-title {
146
232
  margin: 0;
147
- font-size: clamp(28px, 2.8vw, 38px);
148
- line-height: 1;
149
- }
150
- .app-desc {
151
- margin: 0;
152
- font-size: clamp(16px, 1.4vw, 20px);
153
- line-height: 1.7;
154
- color: var(--muted);
155
- }
156
- .app-tags {
157
- display: flex;
158
- flex-wrap: wrap;
159
- gap: 10px;
160
- }
161
- .app-tag {
162
- padding: 8px 12px;
163
- border-radius: 999px;
164
- background: rgba(217, 108, 40, 0.1);
165
- color: var(--accent-strong);
166
- font-size: 14px;
167
- }
168
- .app-rank {
169
- min-width: 84px;
170
- text-align: right;
233
+ max-width: 11ch;
234
+ font-size: clamp(28px, 2.8vw, 40px);
235
+ line-height: 0.95;
236
+ letter-spacing: -0.05em;
237
+ overflow-wrap: anywhere;
171
238
  }
172
- .app-rank__label,
173
239
  .app-link {
174
240
  display: block;
241
+ max-width: 100%;
242
+ font-family: "SF Mono", "ui-monospace", "Menlo", monospace;
175
243
  font-size: 13px;
244
+ letter-spacing: 0.02em;
176
245
  color: var(--muted);
177
- }
178
- .app-rank__value {
179
- font-size: clamp(24px, 2vw, 30px);
180
- font-weight: 700;
246
+ overflow-wrap: anywhere;
181
247
  }
182
248
  .app-action {
249
+ flex-shrink: 0;
183
250
  padding: 12px 18px;
184
251
  border-radius: 999px;
185
252
  background: #1d2d38;
186
253
  color: #fff;
187
- font-size: 15px;
254
+ border: 1px solid rgba(255, 255, 255, 0.14);
255
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.08);
256
+ font-size: 14px;
257
+ letter-spacing: 0.08em;
258
+ text-transform: uppercase;
259
+ transition: transform 180ms ease, background 180ms ease;
260
+ }
261
+ .app-card:hover .app-action {
262
+ transform: translateX(2px);
263
+ background: #223746;
188
264
  }
189
265
  .empty-state {
190
- padding: 32px;
191
- border-radius: 28px;
192
- background: var(--panel-strong);
193
- border: 1px dashed rgba(23, 33, 43, 0.16);
266
+ padding: 40px 32px;
267
+ border-radius: 30px;
268
+ background:
269
+ linear-gradient(180deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0.12)),
270
+ var(--panel-strong);
271
+ border: 1px dashed var(--line-strong);
272
+ box-shadow: var(--shadow-card);
194
273
  }
195
274
  .empty-state__title {
196
275
  margin: 0;
197
276
  font-size: 24px;
277
+ letter-spacing: -0.03em;
198
278
  }
199
279
  .empty-state__desc {
200
280
  margin: 10px 0 0;
201
281
  color: var(--muted);
202
282
  font-size: 16px;
283
+ line-height: 1.7;
203
284
  }
204
285
  @media (max-width: 820px) {
205
- .page { width: min(100vw - 20px, 100%); padding-top: 18px; }
206
- .hero { border-radius: 24px; padding: 22px; }
207
- .section-head { align-items: start; flex-direction: column; }
208
- .app-card { min-height: 0; padding: 20px; border-radius: 22px; }
286
+ body::before {
287
+ opacity: 0.12;
288
+ }
289
+ .page {
290
+ width: min(100vw - 20px, 100%);
291
+ padding-top: 18px;
292
+ }
293
+ .hero {
294
+ min-height: 220px;
295
+ border-radius: 26px;
296
+ padding: 22px;
297
+ }
298
+ .section-head {
299
+ align-items: start;
300
+ flex-direction: column;
301
+ margin-top: 28px;
302
+ }
303
+ .app-card {
304
+ min-height: 0;
305
+ padding: 20px;
306
+ border-radius: 24px;
307
+ }
209
308
  .app-card__top,
210
- .app-card__bottom { align-items: start; flex-direction: column; }
211
- .app-rank { text-align: left; min-width: 0; }
309
+ .app-card__bottom {
310
+ align-items: start;
311
+ flex-direction: column;
312
+ }
313
+ .app-title {
314
+ max-width: none;
315
+ }
212
316
  }
213
317
  `;
214
318
  const appHref = (app) => {
215
319
  return app.kind === 'main' ? '/app/' : `/apps/${app.name}/`;
216
320
  };
217
- const appTags = (app) => {
218
- const tags = [app.kind === 'main' ? '主应用' : '插件'];
219
- if (app.capabilities.web) {
220
- tags.push('页面');
221
- }
222
- if (app.capabilities.httpApi) {
223
- tags.push('接口');
224
- }
225
- if (app.capabilities.event) {
226
- tags.push('事件');
227
- }
228
- if (app.capabilities.expose) {
229
- tags.push('Expose');
230
- }
231
- return tags;
232
- };
233
321
  const renderCardHtml = (app) => {
234
322
  const href = appHref(app);
235
- const tags = appTags(app)
236
- .map(tag => `<span class="app-tag">${escapeHtml(tag)}</span>`)
237
- .join('');
238
- const desc = app.kind === 'main' ? '访问主应用页面、接口与默认资源。' : '访问插件页面、接口与公开入口。';
239
323
  return `
240
324
  <a
241
325
  class="app-card"
@@ -249,13 +333,7 @@ const renderCardHtml = (app) => {
249
333
  <p class="app-eyebrow">${app.kind === 'main' ? 'Main App' : 'Plugin App'}</p>
250
334
  <h2 class="app-title">${escapeHtml(app.name)}</h2>
251
335
  </div>
252
- <div class="app-rank">
253
- <span class="app-rank__label">热度</span>
254
- <span class="app-rank__value" data-click-count>0</span>
255
- </div>
256
336
  </div>
257
- <p class="app-desc">${escapeHtml(desc)}</p>
258
- <div class="app-tags">${tags}</div>
259
337
  <div class="app-card__bottom">
260
338
  <span class="app-link">${escapeHtml(href)}</span>
261
339
  <span class="app-action">进入</span>
@@ -352,7 +430,7 @@ class LaunchpadPage extends Component {
352
430
  });
353
431
  const cards = visibleApps.length ? visibleApps.map(renderCardHtml).join('') : renderEmptyHtml();
354
432
  const script = renderLaunchpadScript(visibleApps);
355
- return Html({ lang: 'zh-CN' }, Head(createElement('meta', { charset: 'utf-8' }), createElement('meta', { name: 'viewport', content: 'width=device-width, initial-scale=1, viewport-fit=cover' }), Title('ALemonJS 应用入口'), Style(styles)), Body(createElement('main', { className: 'page' }, createElement('section', { className: 'hero' }, P({ className: 'hero-kicker' }, 'ALemonJS Launchpad'), createElement('h1', { className: 'hero-title' }, '阿柠檬机器人'), P({ className: 'hero-desc' }, '这里会自动列出当前已准备好的主应用与插件。默认入口优先走静态页面,缺失时再回落到应用路由。'), Div({ className: 'hero-meta' }, createElement('span', { className: 'hero-pill' }, createElement('strong', null, String(visibleApps.length)), ' 个可访问入口'), createElement('span', { className: 'hero-pill' }, '主应用统一在 ', createElement('strong', null, '/app/')), createElement('span', { className: 'hero-pill' }, '插件统一在 ', createElement('strong', null, '/apps/<name>/')))), createElement('section', null, Div({ className: 'section-head' }, Div(null, createElement('h2', { className: 'section-title' }, '应用列表'), P({ className: 'section-note' }, '点击次数越高,卡片排序越靠前。'))), Div({ className: 'app-grid', id: 'app-grid', dangerouslySetInnerHTML: { __html: cards } }))), createElement('script', { dangerouslySetInnerHTML: { __html: script } })));
433
+ return Html({ lang: 'zh-CN' }, Head(createElement('meta', { charset: 'utf-8' }), createElement('meta', { name: 'viewport', content: 'width=device-width, initial-scale=1, viewport-fit=cover' }), Title('ALemonJS 应用入口'), Style(styles)), Body(createElement('main', { className: 'page' }, createElement('section', { className: 'hero' }, P({ className: 'hero-kicker' }, 'ALemonJS Launchpad'), createElement('h1', { className: 'hero-title' }, '阿柠檬机器人')), createElement('section', null, Div({ className: 'section-head' }, Div(null, createElement('h2', { className: 'section-title' }, '应用列表'), P({ className: 'section-note' }, '点击次数越高,卡片排序越靠前。'))), Div({ className: 'app-grid', id: 'app-grid', dangerouslySetInnerHTML: { __html: cards } }))), createElement('script', { dangerouslySetInnerHTML: { __html: script } })));
356
434
  }
357
435
  }
358
436
  const renderHelloHtml = (apps) => {
@@ -184,12 +184,12 @@ const dispatchAppKoaRouters = async (ctx, appName) => {
184
184
  const afterMatched = Array.isArray(matchedContext.matched) ? matchedContext.matched.length : 0;
185
185
  const afterMatchedRoute = ctx._matchedRoute;
186
186
  const afterRouterPath = ctx.routerPath;
187
- const handled = afterMatched > beforeMatched
188
- || afterMatchedRoute !== beforeMatchedRoute
189
- || afterRouterPath !== beforeRouterPath
190
- || ctx.status !== beforeStatus
191
- || ctx.body !== beforeBody
192
- || !fallthrough;
187
+ const handled = afterMatched > beforeMatched ||
188
+ afterMatchedRoute !== beforeMatchedRoute ||
189
+ afterRouterPath !== beforeRouterPath ||
190
+ ctx.status !== beforeStatus ||
191
+ ctx.body !== beforeBody ||
192
+ !fallthrough;
193
193
  if (!handled) {
194
194
  continue;
195
195
  }
@@ -237,7 +237,7 @@ const isNamespacedHtmlRequest = (ctx) => {
237
237
  if (!ctx.path.startsWith('/apps/')) {
238
238
  return false;
239
239
  }
240
- const [, , appName, segment = ''] = ctx.path.split('/');
240
+ const [, , appName] = ctx.path.split('/');
241
241
  if (!appName) {
242
242
  return false;
243
243
  }
@@ -1,5 +1,5 @@
1
1
  import { dirname, join } from 'path';
2
- import { existsSync } from 'fs';
2
+ import { existsSync, readFileSync } from 'fs';
3
3
  import { showErrorModule, getRecursiveDirFiles, createEventName } from '../../../common/utils.js';
4
4
  import { registerRuntimeApp, updateRuntimeAppStatus, ChildrenApp, clearRuntimeAppKoaRouters, setRuntimeAppKoaRouters, updateRuntimeAppCapabilities } from '../store.js';
5
5
  import { registerExpose } from '../../expose.js';
@@ -11,6 +11,50 @@ import { dispatchRuntimeStatusChange, dispatchAppDispose, dispatchAppReady } fro
11
11
  const initRequire = () => { };
12
12
  initRequire.resolve = () => '';
13
13
  const require$1 = module$1?.createRequire?.(import.meta.url) ?? initRequire;
14
+ const resolvePackageDir = (appName) => {
15
+ const resolveWithPaths = require$1.resolve;
16
+ const candidatePaths = resolveWithPaths?.paths?.(appName) ?? [];
17
+ for (const basePath of candidatePaths) {
18
+ const packageDir = join(basePath, appName);
19
+ if (existsSync(join(packageDir, 'package.json'))) {
20
+ return packageDir;
21
+ }
22
+ }
23
+ return null;
24
+ };
25
+ const resolvePackageEntryFromPackageJson = (packageDir) => {
26
+ const packageJsonPath = join(packageDir, 'package.json');
27
+ if (!existsSync(packageJsonPath)) {
28
+ return null;
29
+ }
30
+ try {
31
+ const pkg = JSON.parse(readFileSync(packageJsonPath, 'utf-8')) ?? {};
32
+ const exportsField = pkg?.exports;
33
+ let entry = null;
34
+ if (typeof exportsField === 'string') {
35
+ entry = exportsField;
36
+ }
37
+ else if (exportsField && typeof exportsField === 'object') {
38
+ const rootExport = exportsField['.'];
39
+ if (typeof rootExport === 'string') {
40
+ entry = rootExport;
41
+ }
42
+ else if (rootExport && typeof rootExport === 'object') {
43
+ entry = rootExport.import ?? rootExport.default ?? rootExport.require ?? null;
44
+ }
45
+ }
46
+ if (!entry) {
47
+ entry = pkg?.module ?? pkg?.main ?? 'index.js';
48
+ }
49
+ if (typeof entry !== 'string' || !entry.trim()) {
50
+ return null;
51
+ }
52
+ return join(packageDir, entry);
53
+ }
54
+ catch {
55
+ return null;
56
+ }
57
+ };
14
58
  const resolvePackageRoot = (startDir) => {
15
59
  let currentDir = startDir;
16
60
  while (currentDir && currentDir !== dirname(currentDir)) {
@@ -253,7 +297,14 @@ const loadChildrenFile = (appName) => {
253
297
  return;
254
298
  }
255
299
  try {
256
- const mainPath = require$1.resolve(appName);
300
+ let mainPath = require$1.resolve(appName);
301
+ if (!existsSync(mainPath)) {
302
+ const packageDir = resolvePackageDir(appName);
303
+ const fallbackMainPath = packageDir ? resolvePackageEntryFromPackageJson(packageDir) : null;
304
+ if (fallbackMainPath) {
305
+ mainPath = fallbackMainPath;
306
+ }
307
+ }
257
308
  if (!existsSync(mainPath)) {
258
309
  updateRuntimeAppStatus(appName, 'failed', new Error('The main file does not exist,' + mainPath));
259
310
  logger.error({
@@ -274,6 +325,20 @@ const loadChildrenFile = (appName) => {
274
325
  void loadChildren(mainPath, appName);
275
326
  }
276
327
  catch (e) {
328
+ const packageDir = resolvePackageDir(appName);
329
+ const fallbackMainPath = packageDir ? resolvePackageEntryFromPackageJson(packageDir) : null;
330
+ if (fallbackMainPath && existsSync(fallbackMainPath)) {
331
+ registerRuntimeApp({
332
+ name: appName,
333
+ kind: 'plugin',
334
+ enabled: true,
335
+ status: 'discovered',
336
+ rootDir: dirname(fallbackMainPath),
337
+ mainPath: fallbackMainPath
338
+ });
339
+ void loadChildren(fallbackMainPath, appName);
340
+ return;
341
+ }
277
342
  updateRuntimeAppStatus(appName, 'failed', e);
278
343
  showErrorModule(e);
279
344
  }
@@ -107,8 +107,8 @@ const registerRuntimeApp = (record) => {
107
107
  createdAt: current?.createdAt ?? now,
108
108
  updatedAt: now
109
109
  };
110
- if (current?.status !== record.status) {
111
- logRuntimeAppStatus(record.status === 'failed' ? 'warn' : 'debug', runtimeApps[record.name]);
110
+ if (current?.status !== record.status && process.env.NODE_ENV === 'development') {
111
+ logRuntimeAppStatus('debug', runtimeApps[record.name]);
112
112
  }
113
113
  return runtimeApps[record.name];
114
114
  };
@@ -102,7 +102,9 @@ function renderToString(vnode) {
102
102
  if (voidTags.has(tag.toLowerCase())) {
103
103
  return `<${tag}${attrs} />`;
104
104
  }
105
- const children = rawTextTags.has(tag.toLowerCase()) ? (vnode.children ?? []).map(renderRawText).join('') : (vnode.children ?? []).map(renderToString).join('');
105
+ const children = rawTextTags.has(tag.toLowerCase())
106
+ ? (vnode.children ?? []).map(renderRawText).join('')
107
+ : (vnode.children ?? []).map(renderToString).join('');
106
108
  return `<${tag}${attrs}>${children}</${tag}>`;
107
109
  }
108
110
  function makeTag(tag) {
@@ -112,11 +114,7 @@ function makeTag(tag) {
112
114
  !Array.isArray(first) &&
113
115
  Object.prototype.toString.call(first) === '[object Object]' &&
114
116
  ('type' in first || 'children' in first);
115
- const looksLikeProps = first !== null &&
116
- typeof first === 'object' &&
117
- !Array.isArray(first) &&
118
- Object.prototype.toString.call(first) === '[object Object]' &&
119
- !looksLikeVNode;
117
+ const looksLikeProps = first !== null && typeof first === 'object' && !Array.isArray(first) && Object.prototype.toString.call(first) === '[object Object]' && !looksLikeVNode;
120
118
  if (looksLikeProps) {
121
119
  return createElement(tag, first, ...restChildren);
122
120
  }
package/lib/global.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { DefineChildrenFunc, OnResponseReversalFunc, OnMiddlewareReversalFunc, OnSelectsFunc, OnDataFormatFunc, OnResponseReversalFuncBack, OnGroupFunc, OnMiddlewareReversalFuncBack, DefineResponseFunc, defineMiddlewareFunc, StoreChildrenApp, StateSubscribeMap, SubscribeKeysMap, LoggerUtils, ResponseState, StartOptions } from './types';
1
+ import type { DefineChildrenFunc, OnResponseReversalFunc, OnMiddlewareReversalFunc, OnSelectsFunc, OnDataFormatFunc, OnResponseReversalFuncBack, OnGroupFunc, OnMiddlewareReversalFuncBack, DefineResponseFunc, defineMiddlewareFunc, DefineRouterFunc, StoreChildrenApp, StateSubscribeMap, SubscribeKeysMap, LoggerUtils, ResponseState, StartOptions } from './types';
2
2
  import { type Server } from 'ws';
3
3
  import type WebSocket from 'ws';
4
4
  import type { IncomingMessage } from 'http';
@@ -7,6 +7,9 @@ import type { RuntimeAppRecord } from './application/runtime/store.js';
7
7
  declare global {
8
8
  var __config: any;
9
9
  var __options: StartOptions;
10
+ var __sandbox: boolean | undefined;
11
+ var __client_loaded: boolean | undefined;
12
+ var __publicIp: string | undefined;
10
13
  var logger: LoggerUtils;
11
14
  var alemonjsCore: {
12
15
  storeState: ResponseState;
@@ -25,6 +28,7 @@ declare global {
25
28
  var chatbotServer: Server<typeof WebSocket, typeof IncomingMessage>;
26
29
  var chatbotPlatform: WebSocket;
27
30
  var chatbotClient: WebSocket;
31
+ var testoneClient: WebSocket | undefined;
28
32
  var onResponse: OnResponseReversalFunc;
29
33
  var OnResponse: OnResponseReversalFuncBack;
30
34
  var onMiddleware: OnMiddlewareReversalFunc;
@@ -32,6 +36,7 @@ declare global {
32
36
  var defineChildren: DefineChildrenFunc;
33
37
  var defineResponse: DefineResponseFunc;
34
38
  var defineMiddleware: defineMiddlewareFunc;
39
+ var defineRouter: DefineRouterFunc;
35
40
  var onSelects: OnSelectsFunc;
36
41
  var format: OnDataFormatFunc;
37
42
  var onGroup: OnGroupFunc;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alemonjs",
3
- "version": "2.1.85",
3
+ "version": "2.1.87",
4
4
  "description": "bot script",
5
5
  "author": "lemonade",
6
6
  "license": "MIT",