webspresso 0.0.90 → 0.0.91
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 +358 -8
- package/bin/commands/service.js +193 -0
- package/bin/webspresso.js +2 -0
- package/core/auth/middleware.js +9 -0
- package/core/compression/compressible.js +51 -0
- package/core/compression/compression-stream.js +59 -0
- package/core/compression/index.js +25 -0
- package/core/compression/middleware.js +301 -0
- package/core/compression/negotiate.js +153 -0
- package/core/errors/base.js +31 -0
- package/core/errors/domain.js +193 -0
- package/core/errors/http.js +133 -0
- package/core/errors/index.js +77 -0
- package/core/errors/middleware.js +162 -0
- package/core/errors/normalize.js +171 -0
- package/core/orm/complexity.js +120 -0
- package/core/orm/events.js +64 -14
- package/core/orm/index.js +45 -10
- package/core/orm/model.js +2 -0
- package/core/orm/query-builder.js +30 -4
- package/core/orm/repository.js +57 -25
- package/core/orm/transaction.js +39 -5
- package/core/orm/utils.js +6 -3
- package/core/queue/adapters/database.js +284 -0
- package/core/queue/adapters/memory.js +155 -0
- package/core/queue/adapters/redis.js +336 -0
- package/core/queue/index.js +21 -0
- package/core/queue/job.js +103 -0
- package/core/queue/manager.js +387 -0
- package/core/realtime/adapters/redis.js +431 -0
- package/core/realtime/adapters/socket-io.js +203 -0
- package/core/realtime/adapters/sse.js +210 -0
- package/core/realtime/adapters/websocket.js +337 -0
- package/core/realtime/auth-manager.js +140 -0
- package/core/realtime/core.js +359 -0
- package/core/realtime/emitter.js +98 -0
- package/core/realtime/errors.js +71 -0
- package/core/realtime/index.js +79 -0
- package/core/realtime/reconnect-manager.js +118 -0
- package/core/realtime/registry.js +243 -0
- package/core/shutdown/http-adapter.js +134 -0
- package/core/shutdown/index.js +12 -0
- package/core/shutdown/shutdown-manager.js +312 -0
- package/core/ssr/index.js +13 -0
- package/core/ssr/stream.js +174 -0
- package/index.d.ts +829 -52
- package/index.js +103 -0
- package/package.json +22 -2
- package/plugins/admin-panel/api.js +37 -4
- package/plugins/admin-panel/app.js +57 -17
- package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +4 -1
- package/plugins/admin-panel/client/parts/04-field-renderers.js +102 -58
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +37 -23
- package/plugins/admin-panel/client/parts/08-record-list.js +17 -24
- package/plugins/admin-panel/client/parts/09-record-form.js +168 -19
- package/plugins/admin-panel/core/admin-module.js +2 -2
- package/plugins/admin-panel/core/api-extensions.js +149 -0
- package/plugins/admin-panel/field-renderers/rich-text.js +3 -2
- package/plugins/admin-panel/index.js +90 -17
- package/plugins/admin-panel/modules/custom-pages.js +144 -45
- package/plugins/admin-panel/modules/menu.js +85 -0
- package/plugins/admin-panel/modules/user-management.js +5 -2
- package/plugins/admin-panel/vendor/mithril.min.js +1 -0
- package/plugins/admin-panel/vendor/quill.min.js +7 -0
- package/plugins/admin-panel/vendor/quill.snow.min.css +945 -0
- package/plugins/admin-panel/vendor/tailwind.min.js +65 -0
- package/plugins/basic-auth/index.js +293 -0
- package/plugins/data-exchange/export-xlsx.js +5 -1
- package/plugins/data-exchange/import.js +16 -2
- package/plugins/data-exchange/index.js +14 -0
- package/plugins/email/index.js +14 -1
- package/plugins/index.js +29 -0
- package/plugins/queue/index.js +108 -0
- package/plugins/realtime/index.js +150 -0
- package/plugins/recaptcha/index.js +11 -0
- package/plugins/redirect/index.js +9 -1
- package/plugins/rest-resources/index.js +280 -11
- package/plugins/upload/index.js +16 -0
- package/src/app-context.js +46 -6
- package/src/file-router.js +196 -21
- package/src/helpers.js +20 -2
- package/src/plugin-manager.js +124 -4
- package/src/server.js +304 -44
- package/src/services/builtins/auth.js +273 -0
- package/src/services/builtins/exchange.js +229 -0
- package/src/services/builtins/mail.js +134 -0
- package/src/services/builtins/media.js +196 -0
- package/src/services/builtins/system.js +221 -0
- package/src/services/discovery.js +140 -0
- package/src/services/executor.js +292 -0
- package/src/services/index.js +70 -0
- package/src/services/memoize.js +256 -0
- package/src/services/registry.js +288 -0
- package/src/services/validator.js +281 -0
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* @module plugins/admin-panel
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const fs = require('fs');
|
|
7
9
|
const { createAdminUserModel } = require('./admin-user-model');
|
|
8
10
|
const { generateAdminUsersMigration } = require('./migration-template');
|
|
9
11
|
const { createApiHandlers } = require('./api');
|
|
@@ -75,22 +77,26 @@ function adminPanelPlugin(options = {}) {
|
|
|
75
77
|
version: '2.0.0',
|
|
76
78
|
description: 'Modular admin panel for Webspresso with extensions support',
|
|
77
79
|
|
|
78
|
-
// CSP requirements for admin panel scripts, styles, and custom page iframe sources
|
|
79
|
-
// Note: cdn.quilljs.com 301-redirects to cdn.jsdelivr.net; CSP is enforced on the final URL.
|
|
80
|
+
// CSP requirements for admin panel scripts, styles, and custom page iframe sources (Offline Zero-CDN)
|
|
80
81
|
csp: {
|
|
81
82
|
styleSrc: [
|
|
83
|
+
"'self'",
|
|
84
|
+
"'unsafe-inline'",
|
|
82
85
|
'https://cdn.quilljs.com',
|
|
83
86
|
'https://cdn.jsdelivr.net',
|
|
84
87
|
'https://unpkg.com',
|
|
85
88
|
'https://cdn.tailwindcss.com',
|
|
86
89
|
],
|
|
87
90
|
scriptSrc: [
|
|
91
|
+
"'self'",
|
|
92
|
+
"'unsafe-inline'",
|
|
93
|
+
"'unsafe-eval'",
|
|
88
94
|
'https://cdn.quilljs.com',
|
|
89
95
|
'https://cdn.jsdelivr.net',
|
|
90
96
|
'https://unpkg.com',
|
|
91
97
|
'https://cdn.tailwindcss.com',
|
|
92
98
|
],
|
|
93
|
-
connectSrc: ['https://unpkg.com', 'https://cdn.tailwindcss.com', 'https://cdn.jsdelivr.net'],
|
|
99
|
+
connectSrc: ["'self'", 'https://unpkg.com', 'https://cdn.tailwindcss.com', 'https://cdn.jsdelivr.net'],
|
|
94
100
|
frameSrc: ["'self'", 'data:', 'blob:', 'https:'],
|
|
95
101
|
},
|
|
96
102
|
enabled,
|
|
@@ -162,6 +168,15 @@ function adminPanelPlugin(options = {}) {
|
|
|
162
168
|
/^https:/i.test(String(process.env.BASE_URL || '').trim())
|
|
163
169
|
? true
|
|
164
170
|
: 'auto';
|
|
171
|
+
if (process.env.NODE_ENV === 'production') {
|
|
172
|
+
const warnMsg = '[webspresso:admin] Warning: Admin panel is using default MemoryStore in production. Please configure a persistent session store to prevent memory leaks.';
|
|
173
|
+
if (typeof process !== 'undefined' && typeof process.emitWarning === 'function') {
|
|
174
|
+
process.emitWarning(warnMsg, 'SecurityWarning');
|
|
175
|
+
} else {
|
|
176
|
+
console.warn(warnMsg);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
165
180
|
ctx.app.use(session({
|
|
166
181
|
secret,
|
|
167
182
|
resave: false,
|
|
@@ -189,22 +204,24 @@ function adminPanelPlugin(options = {}) {
|
|
|
189
204
|
const { app } = ctx;
|
|
190
205
|
|
|
191
206
|
const uploadUrlResolved =
|
|
192
|
-
uploadUrlOption || app.get('webspresso.uploadPath')
|
|
207
|
+
uploadUrlOption || (app && typeof app.get === 'function' ? app.get('webspresso.uploadPath') : null);
|
|
193
208
|
if (uploadUrlResolved) {
|
|
194
209
|
registry.configure({ uploadUrl: uploadUrlResolved });
|
|
195
210
|
}
|
|
196
211
|
|
|
197
212
|
// Check if admin_users table exists (migration run)
|
|
198
|
-
db
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
213
|
+
if (db?.knex?.schema?.hasTable) {
|
|
214
|
+
db.knex.schema.hasTable('admin_users').then((hasAdminTable) => {
|
|
215
|
+
if (!hasAdminTable) {
|
|
216
|
+
console.warn(
|
|
217
|
+
'\n⚠️ [admin-panel] admin_users table not found. Run: webspresso admin:setup\n' +
|
|
218
|
+
' Or create the table manually via migration. See: AdminUser model / getMigrationTemplate()\n'
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}).catch((err) => {
|
|
222
|
+
console.warn('[admin-panel] Could not check admin_users table:', err.message);
|
|
223
|
+
});
|
|
224
|
+
}
|
|
208
225
|
|
|
209
226
|
// Create and register AdminUser model
|
|
210
227
|
const { hasModel: hasGlobalModel, getModel: getGlobalModel } = require('../../core/orm/model');
|
|
@@ -313,6 +330,8 @@ function adminPanelPlugin(options = {}) {
|
|
|
313
330
|
// Settings API routes
|
|
314
331
|
ctx.addRoute('get', `${adminPath}/api/extensions/settings`, requireAuth, extensionHandlers.settingsGetHandler);
|
|
315
332
|
ctx.addRoute('post', `${adminPath}/api/extensions/settings`, requireAuth, extensionHandlers.settingsUpdateHandler);
|
|
333
|
+
ctx.addRoute('get', `${adminPath}/api/extensions/system-info`, requireAuth, extensionHandlers.systemInfoHandler);
|
|
334
|
+
ctx.addRoute('get', `${adminPath}/api/system-info`, requireAuth, extensionHandlers.systemInfoHandler);
|
|
316
335
|
|
|
317
336
|
// Custom pages API routes
|
|
318
337
|
ctx.addRoute('get', `${adminPath}/api/extensions/pages/:pageId/data`, requireAuth, pageHandlers.getPageData);
|
|
@@ -360,6 +379,30 @@ function adminPanelPlugin(options = {}) {
|
|
|
360
379
|
// Query API routes (auth required)
|
|
361
380
|
ctx.addRoute('get', `${adminPath}/api/models/:model/queries/:query`, requireAuth, apiHandlers.queryHandler);
|
|
362
381
|
|
|
382
|
+
// ==========================================
|
|
383
|
+
// Static Vendor Assets (Offline Zero-CDN)
|
|
384
|
+
// ==========================================
|
|
385
|
+
const vendorDir = path.join(__dirname, 'vendor');
|
|
386
|
+
ctx.addRoute('get', `${adminPath}/vendor/:file`, (req, res) => {
|
|
387
|
+
const fileName = path.basename(req.params.file);
|
|
388
|
+
const filePath = path.join(vendorDir, fileName);
|
|
389
|
+
|
|
390
|
+
if (!fs.existsSync(filePath)) {
|
|
391
|
+
return res.status(404).send('Vendor asset not found');
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (fileName.endsWith('.js')) {
|
|
395
|
+
res.type('application/javascript');
|
|
396
|
+
} else if (fileName.endsWith('.css')) {
|
|
397
|
+
res.type('text/css');
|
|
398
|
+
} else {
|
|
399
|
+
res.type('application/octet-stream');
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
res.setHeader('Cache-Control', 'public, max-age=86400');
|
|
403
|
+
res.sendFile(filePath);
|
|
404
|
+
});
|
|
405
|
+
|
|
363
406
|
// ==========================================
|
|
364
407
|
// HTML Endpoints
|
|
365
408
|
// ==========================================
|
|
@@ -465,9 +508,9 @@ function generateAdminPanelHtml(adminPath, registry) {
|
|
|
465
508
|
});
|
|
466
509
|
} catch (e) {}
|
|
467
510
|
})();
|
|
468
|
-
|
|
469
|
-
<script src="
|
|
470
|
-
<script src="
|
|
511
|
+
<script>window.__ADMIN_PATH__ = ${JSON.stringify(adminPath)};</script>
|
|
512
|
+
<script src="${adminPath}/vendor/mithril.min.js"></script>
|
|
513
|
+
<script src="${adminPath}/vendor/tailwind.min.js"></script>
|
|
471
514
|
<script>tailwind.config = { darkMode: 'class' };</script>
|
|
472
515
|
<style>
|
|
473
516
|
body { margin: 0; font-family: system-ui, -apple-system, sans-serif; }
|
|
@@ -484,6 +527,35 @@ function generateAdminPanelHtml(adminPath, registry) {
|
|
|
484
527
|
.dark .ql-snow .ql-stroke { stroke: #94a3b8; }
|
|
485
528
|
.dark .ql-snow .ql-fill { fill: #94a3b8; }
|
|
486
529
|
.dark .ql-picker { color: #cbd5e1; }
|
|
530
|
+
@media (min-width: 768px) {
|
|
531
|
+
.admin-table-sticky-check {
|
|
532
|
+
position: sticky;
|
|
533
|
+
left: 0;
|
|
534
|
+
z-index: 5;
|
|
535
|
+
box-shadow: 4px 0 8px -4px rgba(0, 0, 0, 0.08);
|
|
536
|
+
}
|
|
537
|
+
th.admin-table-sticky-check {
|
|
538
|
+
z-index: 15;
|
|
539
|
+
}
|
|
540
|
+
.admin-table-sticky-first {
|
|
541
|
+
position: sticky;
|
|
542
|
+
left: 40px;
|
|
543
|
+
z-index: 5;
|
|
544
|
+
box-shadow: 4px 0 8px -4px rgba(0, 0, 0, 0.08);
|
|
545
|
+
}
|
|
546
|
+
th.admin-table-sticky-first {
|
|
547
|
+
z-index: 15;
|
|
548
|
+
}
|
|
549
|
+
.admin-table-sticky-actions {
|
|
550
|
+
position: sticky;
|
|
551
|
+
right: 0;
|
|
552
|
+
z-index: 5;
|
|
553
|
+
box-shadow: -4px 0 8px -4px rgba(0, 0, 0, 0.08);
|
|
554
|
+
}
|
|
555
|
+
th.admin-table-sticky-actions {
|
|
556
|
+
z-index: 15;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
487
559
|
</style>
|
|
488
560
|
${registry.getStylesHtml()}
|
|
489
561
|
${registry.getScriptsHtml('head')}
|
|
@@ -530,5 +602,6 @@ function generateAdminPanelHtml(adminPath, registry) {
|
|
|
530
602
|
|
|
531
603
|
// Export registry and utilities for external use
|
|
532
604
|
module.exports = adminPanelPlugin;
|
|
605
|
+
module.exports.adminPanelPlugin = adminPanelPlugin;
|
|
533
606
|
module.exports.AdminRegistry = AdminRegistry;
|
|
534
607
|
module.exports.defaultRegistry = defaultRegistry;
|
|
@@ -315,45 +315,41 @@ function createCustomPage(pageConfig) {
|
|
|
315
315
|
const SettingsPage = {
|
|
316
316
|
oninit(vnode) {
|
|
317
317
|
vnode.state.config = null;
|
|
318
|
+
vnode.state.systemInfo = null;
|
|
318
319
|
vnode.state.loading = true;
|
|
319
320
|
vnode.state.saving = false;
|
|
321
|
+
vnode.state.checkingUpdates = false;
|
|
320
322
|
vnode.state.formData = {};
|
|
321
323
|
vnode.state.reloadBusy = false;
|
|
324
|
+
vnode.state.error = null;
|
|
322
325
|
|
|
323
|
-
vnode.state.
|
|
326
|
+
vnode.state.loadAll = (forceUpdateCheck = false) => {
|
|
324
327
|
vnode.state.reloadBusy = true;
|
|
325
328
|
vnode.state.error = null;
|
|
329
|
+
if (forceUpdateCheck) vnode.state.checkingUpdates = true;
|
|
326
330
|
m.redraw();
|
|
327
|
-
return
|
|
328
|
-
.
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
.
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
.finally(() => {
|
|
336
|
-
vnode.state.reloadBusy = false;
|
|
337
|
-
m.redraw();
|
|
338
|
-
});
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
api.get('/extensions/config')
|
|
342
|
-
.then(result => {
|
|
343
|
-
vnode.state.config = result;
|
|
344
|
-
vnode.state.formData = { ...result.settings };
|
|
345
|
-
vnode.state.loading = false;
|
|
346
|
-
m.redraw();
|
|
347
|
-
})
|
|
348
|
-
.catch(err => {
|
|
331
|
+
return Promise.all([
|
|
332
|
+
api.get('/extensions/config'),
|
|
333
|
+
api.get('/extensions/system-info' + (forceUpdateCheck ? '?force=true' : '')).catch(() => null)
|
|
334
|
+
]).then(([configRes, sysRes]) => {
|
|
335
|
+
vnode.state.config = configRes;
|
|
336
|
+
vnode.state.formData = { ...configRes.settings };
|
|
337
|
+
if (sysRes) vnode.state.systemInfo = sysRes;
|
|
338
|
+
}).catch(err => {
|
|
349
339
|
vnode.state.error = err.message;
|
|
340
|
+
}).finally(() => {
|
|
350
341
|
vnode.state.loading = false;
|
|
342
|
+
vnode.state.reloadBusy = false;
|
|
343
|
+
vnode.state.checkingUpdates = false;
|
|
351
344
|
m.redraw();
|
|
352
345
|
});
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
vnode.state.loadAll();
|
|
353
349
|
},
|
|
354
350
|
|
|
355
351
|
view(vnode) {
|
|
356
|
-
const { config, loading, saving, formData, error } = vnode.state;
|
|
352
|
+
const { config, systemInfo, loading, saving, checkingUpdates, formData, error, reloadBusy } = vnode.state;
|
|
357
353
|
|
|
358
354
|
if (loading) {
|
|
359
355
|
return m(Layout, m('div.flex.justify-center.py-12', m(Spinner)));
|
|
@@ -365,43 +361,147 @@ const SettingsPage = {
|
|
|
365
361
|
m('div.mb-6.flex.items-start.justify-between.gap-4', [
|
|
366
362
|
m('div', [
|
|
367
363
|
m('h1.text-2xl.font-bold.text-gray-900.dark:text-slate-100', 'Admin Settings'),
|
|
368
|
-
m('p.text-xs.text-gray-500.dark:text-slate-400.mt-1', '
|
|
364
|
+
m('p.text-xs.text-gray-500.dark:text-slate-400.mt-1', 'System overview and admin panel configuration'),
|
|
369
365
|
]),
|
|
370
366
|
m(RefreshIconButton, {
|
|
371
367
|
title: 'Reload settings from server',
|
|
372
|
-
disabled: saving,
|
|
373
|
-
spinning:
|
|
368
|
+
disabled: saving || reloadBusy,
|
|
369
|
+
spinning: reloadBusy,
|
|
374
370
|
onclick: () => {
|
|
375
|
-
vnode.state.
|
|
371
|
+
vnode.state.loadAll();
|
|
376
372
|
},
|
|
377
373
|
}),
|
|
378
374
|
]),
|
|
379
375
|
|
|
380
|
-
error && m('div.bg-red-50.border.border-red-200.rounded.p-4.text-red-700.mb-
|
|
376
|
+
error && m('div.bg-red-50.dark:bg-red-950/40.border.border-red-200.dark:border-red-800.rounded-lg.p-4.text-red-700.dark:text-red-300.mb-6', error),
|
|
377
|
+
|
|
378
|
+
// System Information Card
|
|
379
|
+
systemInfo ? m('div.bg-white.dark:bg-slate-800.rounded-xl.shadow-sm.border.border-gray-200.dark:border-slate-700.mb-6.overflow-hidden', [
|
|
380
|
+
m('div.px-6.py-4.border-b.border-gray-100.dark:border-slate-700.flex.items-center.justify-between.bg-gray-50/50.dark:bg-slate-800/80', [
|
|
381
|
+
m('div.flex.items-center.gap-2.5', [
|
|
382
|
+
m('div.w-8.h-8.rounded-lg.bg-indigo-50.dark:bg-indigo-950/60.text-indigo-600.dark:text-indigo-400.flex.items-center.justify-center', [
|
|
383
|
+
m('svg.w-4.h-4', { fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24' },
|
|
384
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z' })
|
|
385
|
+
)
|
|
386
|
+
]),
|
|
387
|
+
m('div', [
|
|
388
|
+
m('h2.text-base.font-semibold.text-gray-900.dark:text-slate-100', 'System Information'),
|
|
389
|
+
m('p.text-xs.text-gray-500.dark:text-slate-400', 'Runtime environment and version status')
|
|
390
|
+
])
|
|
391
|
+
]),
|
|
392
|
+
m('button.inline-flex.items-center.gap-1.5.px-3.py-1.5.text-xs.font-medium.text-indigo-600.dark:text-indigo-400.bg-indigo-50.dark:bg-indigo-950/50.hover:bg-indigo-100.dark:hover:bg-indigo-900/50.rounded-lg.transition-colors.disabled:opacity-50', {
|
|
393
|
+
disabled: checkingUpdates,
|
|
394
|
+
onclick: () => {
|
|
395
|
+
vnode.state.loadAll(true);
|
|
396
|
+
}
|
|
397
|
+
}, [
|
|
398
|
+
checkingUpdates ? m(Spinner) : m('svg.w-3.5.h-3.5', { fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24' },
|
|
399
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15' })
|
|
400
|
+
),
|
|
401
|
+
checkingUpdates ? 'Checking...' : 'Check for Updates'
|
|
402
|
+
])
|
|
403
|
+
]),
|
|
404
|
+
m('div.p-6.grid.grid-cols-1.md:grid-cols-2.lg:grid-cols-3.gap-5', [
|
|
405
|
+
// Webspresso Version
|
|
406
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
407
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Webspresso Framework'),
|
|
408
|
+
m('div.mt-1.5.flex.items-center.gap-2.flex-wrap', [
|
|
409
|
+
m('span.text-sm.font-semibold.text-gray-900.dark:text-slate-100', 'v' + (systemInfo.webspressoVersion || '0.0.1')),
|
|
410
|
+
systemInfo.hasUpdate
|
|
411
|
+
? m('span.inline-flex.items-center.px-2.py-0.5.rounded-full.text-[11px].font-semibold.bg-amber-100.text-amber-800.dark:bg-amber-950/60.dark:text-amber-300.border.border-amber-200.dark:border-amber-800', '⚡ Update: v' + systemInfo.latestVersion)
|
|
412
|
+
: m('span.inline-flex.items-center.px-2.py-0.5.rounded-full.text-[11px].font-semibold.bg-emerald-100.text-emerald-800.dark:bg-emerald-950/60.dark:text-emerald-300.border.border-emerald-200.dark:border-emerald-800', '✓ Up to date')
|
|
413
|
+
]),
|
|
414
|
+
systemInfo.hasUpdate && m('div.mt-2', [
|
|
415
|
+
m('code.text-[11px].bg-white.dark:bg-slate-800.text-indigo-600.dark:text-indigo-400.px-2.py-0.5.rounded.border.border-gray-200.dark:border-slate-700.select-all', 'npm i webspresso@latest')
|
|
416
|
+
])
|
|
417
|
+
]),
|
|
418
|
+
|
|
419
|
+
// Node.js Version
|
|
420
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
421
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Node.js Runtime'),
|
|
422
|
+
m('div.mt-1.5.text-sm.font-semibold.text-gray-900.dark:text-slate-100', systemInfo.nodeVersion || process.version)
|
|
423
|
+
]),
|
|
381
424
|
|
|
382
|
-
|
|
383
|
-
|
|
425
|
+
// Environment
|
|
426
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
427
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Environment'),
|
|
428
|
+
m('div.mt-1.5', [
|
|
429
|
+
m('span.inline-flex.items-center.px-2.5.py-0.5.rounded-full.text-xs.font-semibold', {
|
|
430
|
+
class: systemInfo.environment === 'production'
|
|
431
|
+
? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/60 dark:text-emerald-300'
|
|
432
|
+
: 'bg-blue-100 text-blue-800 dark:bg-blue-950/60 dark:text-blue-300'
|
|
433
|
+
}, systemInfo.environment || 'development')
|
|
434
|
+
])
|
|
435
|
+
]),
|
|
436
|
+
|
|
437
|
+
// Operating System
|
|
438
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
439
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'OS & Architecture'),
|
|
440
|
+
m('div.mt-1.5.text-sm.font-semibold.text-gray-900.dark:text-slate-100.truncate', { title: systemInfo.platform }, systemInfo.platform || 'Server')
|
|
441
|
+
]),
|
|
442
|
+
|
|
443
|
+
// Server Uptime
|
|
444
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
445
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Server Uptime'),
|
|
446
|
+
m('div.mt-1.5.text-sm.font-semibold.text-gray-900.dark:text-slate-100', systemInfo.uptimeFormatted || '0s')
|
|
447
|
+
]),
|
|
448
|
+
|
|
449
|
+
// Memory Usage
|
|
450
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
451
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Memory (Heap / RSS)'),
|
|
452
|
+
m('div.mt-1.5.text-sm.font-semibold.text-gray-900.dark:text-slate-100',
|
|
453
|
+
(systemInfo.memory?.heapUsed || '0 MB') + ' / ' + (systemInfo.memory?.heapTotal || '0 MB') + ' (' + (systemInfo.memory?.rss || '0 MB') + ')'
|
|
454
|
+
)
|
|
455
|
+
]),
|
|
456
|
+
|
|
457
|
+
// Database Engine
|
|
458
|
+
m('div.p-3.5.rounded-lg.bg-gray-50.dark:bg-slate-900/50.border.border-gray-100.dark:border-slate-800', [
|
|
459
|
+
m('div.text-xs.font-medium.text-gray-500.dark:text-slate-400', 'Database Client'),
|
|
460
|
+
m('div.mt-1.5.text-sm.font-semibold.text-gray-900.dark:text-slate-100', systemInfo.database?.client || 'knex')
|
|
461
|
+
])
|
|
462
|
+
])
|
|
463
|
+
]) : null,
|
|
464
|
+
|
|
465
|
+
// Admin Preferences Card
|
|
466
|
+
m('div.bg-white.dark:bg-slate-800.rounded-xl.shadow-sm.border.border-gray-200.dark:border-slate-700.overflow-hidden', [
|
|
467
|
+
m('div.px-6.py-4.border-b.border-gray-100.dark:border-slate-700.flex.items-center.gap-2.5.bg-gray-50/50.dark:bg-slate-800/80', [
|
|
468
|
+
m('div.w-8.h-8.rounded-lg.bg-blue-50.dark:bg-blue-950/60.text-blue-600.dark:text-blue-400.flex.items-center.justify-center', [
|
|
469
|
+
m('svg.w-4.h-4', { fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24' },
|
|
470
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4' })
|
|
471
|
+
)
|
|
472
|
+
]),
|
|
384
473
|
m('div', [
|
|
385
|
-
m('
|
|
386
|
-
m('
|
|
474
|
+
m('h2.text-base.font-semibold.text-gray-900.dark:text-slate-100', 'Panel Preferences'),
|
|
475
|
+
m('p.text-xs.text-gray-500.dark:text-slate-400', 'Customize admin title, theme colors, and table pagination')
|
|
476
|
+
])
|
|
477
|
+
]),
|
|
478
|
+
|
|
479
|
+
m('div.p-6.space-y-5', [
|
|
480
|
+
m('div', [
|
|
481
|
+
m('label.block.text-sm.font-medium.text-gray-700.dark:text-slate-300', 'Panel Title'),
|
|
482
|
+
m('input.mt-1.block.w-full.rounded-lg.border-gray-300.dark:border-slate-600.dark:bg-slate-900.dark:text-slate-100.shadow-sm.focus:border-blue-500.focus:ring-blue-500.text-sm.px-3.py-2', {
|
|
387
483
|
type: 'text',
|
|
388
484
|
value: formData.title || '',
|
|
485
|
+
placeholder: 'Admin Panel',
|
|
389
486
|
oninput: (e) => { formData.title = e.target.value; },
|
|
390
487
|
}),
|
|
391
488
|
]),
|
|
392
489
|
|
|
393
490
|
m('div', [
|
|
394
|
-
m('label.block.text-sm.font-medium.text-gray-700', 'Primary Color'),
|
|
395
|
-
m('
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
491
|
+
m('label.block.text-sm.font-medium.text-gray-700.dark:text-slate-300', 'Primary Accent Color'),
|
|
492
|
+
m('div.mt-1.5.flex.items-center.gap-3', [
|
|
493
|
+
m('input.w-10.h-10.rounded-lg.border.border-gray-300.dark:border-slate-600.cursor-pointer.p-0.5.bg-transparent', {
|
|
494
|
+
type: 'color',
|
|
495
|
+
value: formData.primaryColor || '#3B82F6',
|
|
496
|
+
oninput: (e) => { formData.primaryColor = e.target.value; },
|
|
497
|
+
}),
|
|
498
|
+
m('span.text-xs.font-mono.text-gray-600.dark:text-slate-400', formData.primaryColor || '#3B82F6'),
|
|
499
|
+
]),
|
|
400
500
|
]),
|
|
401
501
|
|
|
402
502
|
m('div', [
|
|
403
|
-
m('label.block.text-sm.font-medium.text-gray-700', 'Records Per Page'),
|
|
404
|
-
m('input.mt-1.block.w-32.rounded.border-gray-300
|
|
503
|
+
m('label.block.text-sm.font-medium.text-gray-700.dark:text-slate-300', 'Records Per Page'),
|
|
504
|
+
m('input.mt-1.block.w-32.rounded-lg.border-gray-300.dark:border-slate-600.dark:bg-slate-900.dark:text-slate-100.shadow-sm.focus:border-blue-500.focus:ring-blue-500.text-sm.px-3.py-2', {
|
|
405
505
|
type: 'number',
|
|
406
506
|
min: 5,
|
|
407
507
|
max: 100,
|
|
@@ -411,15 +511,14 @@ const SettingsPage = {
|
|
|
411
511
|
]),
|
|
412
512
|
]),
|
|
413
513
|
|
|
414
|
-
m('div.bg-gray-50
|
|
415
|
-
m('button.px-4.py-2.text-sm.font-medium.text-white.bg-blue-600.
|
|
514
|
+
m('div.bg-gray-50.dark:bg-slate-900/70.px-6.py-4.flex.justify-end.gap-3.border-t.border-gray-100.dark:border-slate-700', [
|
|
515
|
+
m('button.inline-flex.items-center.gap-2.px-4.py-2.text-sm.font-medium.text-white.bg-blue-600.hover:bg-blue-700.rounded-lg.shadow-sm.transition-colors.disabled:opacity-50', {
|
|
416
516
|
disabled: saving,
|
|
417
517
|
onclick: async () => {
|
|
418
518
|
vnode.state.saving = true;
|
|
419
519
|
m.redraw();
|
|
420
520
|
try {
|
|
421
521
|
await api.post('/extensions/settings', formData);
|
|
422
|
-
// Reload to apply changes
|
|
423
522
|
window.location.reload();
|
|
424
523
|
} catch (err) {
|
|
425
524
|
vnode.state.error = err.message;
|
|
@@ -427,7 +526,7 @@ const SettingsPage = {
|
|
|
427
526
|
m.redraw();
|
|
428
527
|
}
|
|
429
528
|
},
|
|
430
|
-
}, saving ? 'Saving...' : 'Save Settings'),
|
|
529
|
+
}, saving ? [m(Spinner), 'Saving...'] : 'Save Settings'),
|
|
431
530
|
]),
|
|
432
531
|
]),
|
|
433
532
|
]);
|
|
@@ -389,6 +389,90 @@ const MobileHeader = {
|
|
|
389
389
|
},
|
|
390
390
|
};
|
|
391
391
|
|
|
392
|
+
// Webspresso Version Check State
|
|
393
|
+
var versionCheckState = {
|
|
394
|
+
checked: false,
|
|
395
|
+
loading: false,
|
|
396
|
+
data: null,
|
|
397
|
+
dismissed: false,
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
async function checkWebspressoVersion(force) {
|
|
401
|
+
if (versionCheckState.loading) return;
|
|
402
|
+
if (versionCheckState.checked && !force) return;
|
|
403
|
+
versionCheckState.loading = true;
|
|
404
|
+
try {
|
|
405
|
+
const res = await api.get('/extensions/system-info' + (force ? '?force=true' : ''));
|
|
406
|
+
versionCheckState.data = res;
|
|
407
|
+
versionCheckState.checked = true;
|
|
408
|
+
if (res && res.latestVersion) {
|
|
409
|
+
try {
|
|
410
|
+
const dismissedVer = sessionStorage.getItem('webspresso_dismiss_update_' + res.latestVersion);
|
|
411
|
+
if (dismissedVer === 'true') {
|
|
412
|
+
versionCheckState.dismissed = true;
|
|
413
|
+
}
|
|
414
|
+
} catch (e) {}
|
|
415
|
+
}
|
|
416
|
+
} catch (err) {
|
|
417
|
+
// Silent fail for background check
|
|
418
|
+
} finally {
|
|
419
|
+
versionCheckState.loading = false;
|
|
420
|
+
m.redraw();
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Version Update Toast Notification
|
|
425
|
+
const VersionUpdateToast = {
|
|
426
|
+
oninit() {
|
|
427
|
+
if (!versionCheckState.checked && !versionCheckState.loading) {
|
|
428
|
+
checkWebspressoVersion();
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
view() {
|
|
432
|
+
const data = versionCheckState.data;
|
|
433
|
+
if (!data || !data.hasUpdate || versionCheckState.dismissed) return null;
|
|
434
|
+
|
|
435
|
+
return m('div.fixed.bottom-5.right-5.z-50.max-w-sm.bg-white.dark:bg-slate-900.border.border-indigo-200.dark:border-indigo-800.rounded-xl.shadow-2xl.p-4.transition-all', [
|
|
436
|
+
m('div.flex.items-start.gap-3', [
|
|
437
|
+
m('div.flex-shrink-0.w-9.h-9.rounded-lg.bg-indigo-100.dark:bg-indigo-950/80.text-indigo-600.dark:text-indigo-400.flex.items-center.justify-center.font-bold', [
|
|
438
|
+
m('svg.w-5.h-5', { fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24' },
|
|
439
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M13 10V3L4 14h7v7l9-11h-7z' })
|
|
440
|
+
)
|
|
441
|
+
]),
|
|
442
|
+
m('div.flex-1.min-w-0', [
|
|
443
|
+
m('div.flex.items-center.justify-between.gap-2', [
|
|
444
|
+
m('h4.text-sm.font-semibold.text-gray-900.dark:text-slate-100', 'Update Available'),
|
|
445
|
+
m('button.text-gray-400.hover:text-gray-600.dark:hover:text-slate-300.-mr-1.-mt-1.p-1.rounded-md.hover:bg-gray-100.dark:hover:bg-slate-800.transition-colors', {
|
|
446
|
+
title: 'Dismiss notification',
|
|
447
|
+
onclick: () => {
|
|
448
|
+
versionCheckState.dismissed = true;
|
|
449
|
+
if (data.latestVersion) {
|
|
450
|
+
try { sessionStorage.setItem('webspresso_dismiss_update_' + data.latestVersion, 'true'); } catch (e) {}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}, m('svg.w-4.h-4', { fill: 'none', stroke: 'currentColor', viewBox: '0 0 24 24' },
|
|
454
|
+
m('path', { 'stroke-linecap': 'round', 'stroke-linejoin': 'round', 'stroke-width': '2', d: 'M6 18L18 6M6 6l12 12' })
|
|
455
|
+
))
|
|
456
|
+
]),
|
|
457
|
+
m('p.text-xs.text-gray-600.dark:text-slate-300.mt-1', [
|
|
458
|
+
'Webspresso ',
|
|
459
|
+
m('span.font-bold.text-indigo-600.dark:text-indigo-400', 'v' + data.latestVersion),
|
|
460
|
+
' is available (current: v' + data.webspressoVersion + ').'
|
|
461
|
+
]),
|
|
462
|
+
m('div.mt-2.5.flex.items-center.gap-2', [
|
|
463
|
+
m('code.text-[11px].bg-gray-100.dark:bg-slate-800.text-gray-800.dark:text-slate-200.px-2.py-1.rounded.font-mono.border.border-gray-200.dark:border-slate-700.select-all', 'npm i webspresso@latest'),
|
|
464
|
+
m('a.text-xs.font-medium.text-indigo-600.dark:text-indigo-400.hover:underline.ml-auto', {
|
|
465
|
+
href: 'https://github.com/webspresso/webspresso/releases',
|
|
466
|
+
target: '_blank',
|
|
467
|
+
rel: 'noopener noreferrer',
|
|
468
|
+
}, 'Changelog')
|
|
469
|
+
])
|
|
470
|
+
])
|
|
471
|
+
])
|
|
472
|
+
]);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
|
|
392
476
|
// Layout Component (with sidebar)
|
|
393
477
|
const Layout = {
|
|
394
478
|
view(vnode) {
|
|
@@ -396,6 +480,7 @@ const Layout = {
|
|
|
396
480
|
m(MobileHeader),
|
|
397
481
|
m(Sidebar),
|
|
398
482
|
m('main.lg:ml-64.p-6.pt-20.lg:pt-6', vnode.children),
|
|
483
|
+
m(VersionUpdateToast),
|
|
399
484
|
]);
|
|
400
485
|
},
|
|
401
486
|
};
|
|
@@ -508,9 +508,12 @@ function createUserManagementApiHandlers(options) {
|
|
|
508
508
|
return res.json({ data: [] });
|
|
509
509
|
}
|
|
510
510
|
|
|
511
|
+
const repo = db.getRepository(modelName);
|
|
512
|
+
const tableName = repo?.model?.table || modelName;
|
|
513
|
+
|
|
511
514
|
const sessions = await db.knex('remember_tokens')
|
|
512
|
-
.select('remember_tokens.*', `${
|
|
513
|
-
.leftJoin(
|
|
515
|
+
.select('remember_tokens.*', `${tableName}.${fieldMap.email} as user_email`, `${tableName}.${fieldMap.name} as user_name`)
|
|
516
|
+
.leftJoin(tableName, 'remember_tokens.user_id', `${tableName}.id`)
|
|
514
517
|
.orderBy('remember_tokens.created_at', 'desc');
|
|
515
518
|
|
|
516
519
|
res.json({ data: sessions });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(){"use strict";function e(e,t,n,r,o,i){return{tag:e,key:t,attrs:n,children:r,text:o,dom:i,domSize:void 0,state:void 0,events:void 0,instance:void 0}}e.normalize=function(t){return Array.isArray(t)?e("[",void 0,void 0,e.normalizeChildren(t),void 0,void 0):null==t||"boolean"==typeof t?null:"object"==typeof t?t:e("#",void 0,void 0,String(t),void 0,void 0)},e.normalizeChildren=function(t){var n=[];if(t.length){for(var r=null!=t[0]&&null!=t[0].key,o=1;o<t.length;o++)if((null!=t[o]&&null!=t[o].key)!==r)throw new TypeError(!r||null==t[o]&&"boolean"!=typeof t[o]?"In fragments, vnodes must either all have keys or none have keys.":"In fragments, vnodes must either all have keys or none have keys. You may wish to consider using an explicit keyed empty fragment, m.fragment({key: ...}), instead of a hole.");for(o=0;o<t.length;o++)n[o]=e.normalize(t[o])}return n};var t=function(){var t,n=arguments[this],r=this+1;if(null==n?n={}:("object"!=typeof n||null!=n.tag||Array.isArray(n))&&(n={},r=this),arguments.length===r+1)t=arguments[r],Array.isArray(t)||(t=[t]);else for(t=[];r<arguments.length;)t.push(arguments[r++]);return e("",n.key,n,t)},n={}.hasOwnProperty,r=/(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g,o={};function i(e){for(var t in e)if(n.call(e,t))return!1;return!0}function l(l){if(null==l||"string"!=typeof l&&"function"!=typeof l&&"function"!=typeof l.view)throw Error("The selector must be either a string or a component.");var a=t.apply(1,arguments);return"string"==typeof l&&(a.children=e.normalizeChildren(a.children),"["!==l)?function(e,t){var r=t.attrs,o=n.call(r,"class"),l=o?r.class:r.className;if(t.tag=e.tag,t.attrs={},!i(e.attrs)&&!i(r)){var a={};for(var u in r)n.call(r,u)&&(a[u]=r[u]);r=a}for(var u in e.attrs)n.call(e.attrs,u)&&"className"!==u&&!n.call(r,u)&&(r[u]=e.attrs[u]);for(var u in null==l&&null==e.attrs.className||(r.className=null!=l?null!=e.attrs.className?String(e.attrs.className)+" "+String(l):l:null!=e.attrs.className?e.attrs.className:null),o&&(r.class=null),r)if(n.call(r,u)&&"key"!==u){t.attrs=r;break}return t}(o[l]||function(e){for(var t,n="div",i=[],l={};t=r.exec(e);){var a=t[1],u=t[2];if(""===a&&""!==u)n=u;else if("#"===a)l.id=u;else if("."===a)i.push(u);else if("["===t[3][0]){var s=t[6];s&&(s=s.replace(/\\(["'])/g,"$1").replace(/\\\\/g,"\\")),"class"===t[4]?i.push(s):l[t[4]]=""===s?s:s||!0}}return i.length>0&&(l.className=i.join(" ")),o[e]={tag:n,attrs:l}}(l),a):(a.tag=l,a)}if(l.trust=function(t){return null==t&&(t=""),e("<",void 0,void 0,t,void 0,void 0)},l.fragment=function(){var n=t.apply(0,arguments);return n.tag="[",n.children=e.normalizeChildren(n.children),n},(a=function(e){if(!(this instanceof a))throw new Error("Promise must be called with 'new'.");if("function"!=typeof e)throw new TypeError("executor must be a function.");var t=this,n=[],r=[],o=s(n,!0),i=s(r,!1),l=t._instance={resolvers:n,rejectors:r},u="function"==typeof setImmediate?setImmediate:setTimeout;function s(e,o){return function a(s){var f;try{if(!o||null==s||"object"!=typeof s&&"function"!=typeof s||"function"!=typeof(f=s.then))u((function(){o||0!==e.length||console.error("Possible unhandled promise rejection:",s);for(var t=0;t<e.length;t++)e[t](s);n.length=0,r.length=0,l.state=o,l.retry=function(){a(s)}}));else{if(s===t)throw new TypeError("Promise can't be resolved with itself.");c(f.bind(s))}}catch(e){i(e)}}}function c(e){var t=0;function n(e){return function(n){t++>0||e(n)}}var r=n(i);try{e(n(o),r)}catch(e){r(e)}}c(e)}).prototype.then=function(e,t){var n,r,o=this._instance;function i(e,t,i,l){t.push((function(t){if("function"!=typeof e)i(t);else try{n(e(t))}catch(e){r&&r(e)}})),"function"==typeof o.retry&&l===o.state&&o.retry()}var l=new a((function(e,t){n=e,r=t}));return i(e,o.resolvers,n,!0),i(t,o.rejectors,r,!1),l},a.prototype.catch=function(e){return this.then(null,e)},a.prototype.finally=function(e){return this.then((function(t){return a.resolve(e()).then((function(){return t}))}),(function(t){return a.resolve(e()).then((function(){return a.reject(t)}))}))},a.resolve=function(e){return e instanceof a?e:new a((function(t){t(e)}))},a.reject=function(e){return new a((function(t,n){n(e)}))},a.all=function(e){return new a((function(t,n){var r=e.length,o=0,i=[];if(0===e.length)t([]);else for(var l=0;l<e.length;l++)!function(l){function a(e){o++,i[l]=e,o===r&&t(i)}null==e[l]||"object"!=typeof e[l]&&"function"!=typeof e[l]||"function"!=typeof e[l].then?a(e[l]):e[l].then(a,n)}(l)}))},a.race=function(e){return new a((function(t,n){for(var r=0;r<e.length;r++)e[r].then(t,n)}))},"undefined"!=typeof window){void 0===window.Promise?window.Promise=a:window.Promise.prototype.finally||(window.Promise.prototype.finally=a.prototype.finally);var a=window.Promise}else if("undefined"!=typeof global){void 0===global.Promise?global.Promise=a:global.Promise.prototype.finally||(global.Promise.prototype.finally=a.prototype.finally);a=global.Promise}var u=function(t){var n,r=t&&t.document,o={svg:"http://www.w3.org/2000/svg",math:"http://www.w3.org/1998/Math/MathML"};function i(e){return e.attrs&&e.attrs.xmlns||o[e.tag]}function l(e,t){if(e.state!==t)throw new Error("'vnode.state' must not be modified.")}function a(e){var t=e.state;try{return this.apply(t,arguments)}finally{l(e,t)}}function u(){try{return r.activeElement}catch(e){return null}}function s(e,t,n,r,o,i,l){for(var a=n;a<r;a++){var u=t[a];null!=u&&c(e,u,o,l,i)}}function c(t,n,o,l,u){var f=n.tag;if("string"==typeof f)switch(n.state={},null!=n.attrs&&_(n.attrs,n,o),f){case"#":!function(e,t,n){t.dom=r.createTextNode(t.children),w(e,t.dom,n)}(t,n,u);break;case"<":d(t,n,l,u);break;case"[":!function(e,t,n,o,i){var l=r.createDocumentFragment();if(null!=t.children){var a=t.children;s(l,a,0,a.length,n,null,o)}t.dom=l.firstChild,t.domSize=l.childNodes.length,w(e,l,i)}(t,n,o,l,u);break;default:!function(e,t,n,o,l){var a=t.tag,u=t.attrs,c=u&&u.is,f=(o=i(t)||o)?c?r.createElementNS(o,a,{is:c}):r.createElementNS(o,a):c?r.createElement(a,{is:c}):r.createElement(a);t.dom=f,null!=u&&function(e,t,n){"input"===e.tag&&null!=t.type&&e.dom.setAttribute("type",t.type);var r=null!=t&&"input"===e.tag&&"file"===t.type;for(var o in t)C(e,o,null,t[o],n,r)}(t,u,o);if(w(e,f,l),!b(t)&&null!=t.children){var d=t.children;s(f,d,0,d.length,n,null,o),"select"===t.tag&&null!=u&&function(e,t){if("value"in t)if(null===t.value)-1!==e.dom.selectedIndex&&(e.dom.value=null);else{var n=""+t.value;e.dom.value===n&&-1!==e.dom.selectedIndex||(e.dom.value=n)}"selectedIndex"in t&&C(e,"selectedIndex",null,t.selectedIndex,void 0)}(t,u)}}(t,n,o,l,u)}else!function(t,n,r,o,i){(function(t,n){var r;if("function"==typeof t.tag.view){if(t.state=Object.create(t.tag),null!=(r=t.state.view).$$reentrantLock$$)return;r.$$reentrantLock$$=!0}else{if(t.state=void 0,null!=(r=t.tag).$$reentrantLock$$)return;r.$$reentrantLock$$=!0,t.state=null!=t.tag.prototype&&"function"==typeof t.tag.prototype.view?new t.tag(t):t.tag(t)}_(t.state,t,n),null!=t.attrs&&_(t.attrs,t,n);if(t.instance=e.normalize(a.call(t.state.view,t)),t.instance===t)throw Error("A view cannot return the vnode it received as argument");r.$$reentrantLock$$=null})(n,r),null!=n.instance?(c(t,n.instance,r,o,i),n.dom=n.instance.dom,n.domSize=null!=n.dom?n.instance.domSize:0):n.domSize=0}(t,n,o,l,u)}var f={caption:"table",thead:"table",tbody:"table",tfoot:"table",tr:"tbody",th:"tr",td:"tr",colgroup:"table",col:"colgroup"};function d(e,t,n,o){var i=t.children.match(/^\s*?<(\w+)/im)||[],l=r.createElement(f[i[1]]||"div");"http://www.w3.org/2000/svg"===n?(l.innerHTML='<svg xmlns="http://www.w3.org/2000/svg">'+t.children+"</svg>",l=l.firstChild):l.innerHTML=t.children,t.dom=l.firstChild,t.domSize=l.childNodes.length,t.instance=[];for(var a,u=r.createDocumentFragment();a=l.firstChild;)t.instance.push(a),u.appendChild(a);w(e,u,o)}function p(e,t,n,r,o,i){if(t!==n&&(null!=t||null!=n))if(null==t||0===t.length)s(e,n,0,n.length,r,o,i);else if(null==n||0===n.length)k(e,t,0,t.length);else{var l=null!=t[0]&&null!=t[0].key,a=null!=n[0]&&null!=n[0].key,u=0,f=0;if(!l)for(;f<t.length&&null==t[f];)f++;if(!a)for(;u<n.length&&null==n[u];)u++;if(l!==a)k(e,t,f,t.length),s(e,n,u,n.length,r,o,i);else if(a){for(var d,p,w,b,S,E=t.length-1,j=n.length-1;E>=f&&j>=u&&(w=t[E],b=n[j],w.key===b.key);)w!==b&&h(e,w,b,r,o,i),null!=b.dom&&(o=b.dom),E--,j--;for(;E>=f&&j>=u&&(d=t[f],p=n[u],d.key===p.key);)f++,u++,d!==p&&h(e,d,p,r,y(t,f,o),i);for(;E>=f&&j>=u&&u!==j&&d.key===b.key&&w.key===p.key;)g(e,w,S=y(t,f,o)),w!==p&&h(e,w,p,r,S,i),++u<=--j&&g(e,d,o),d!==b&&h(e,d,b,r,o,i),null!=b.dom&&(o=b.dom),f++,w=t[--E],b=n[j],d=t[f],p=n[u];for(;E>=f&&j>=u&&w.key===b.key;)w!==b&&h(e,w,b,r,o,i),null!=b.dom&&(o=b.dom),j--,w=t[--E],b=n[j];if(u>j)k(e,t,f,E+1);else if(f>E)s(e,n,u,j+1,r,o,i);else{var C,z,A=o,T=j-u+1,N=new Array(T),O=0,P=0,I=2147483647,$=0;for(P=0;P<T;P++)N[P]=-1;for(P=j;P>=u;P--){null==C&&(C=v(t,f,E+1));var L=C[(b=n[P]).key];null!=L&&(I=L<I?L:-1,N[P-u]=L,w=t[L],t[L]=null,w!==b&&h(e,w,b,r,o,i),null!=b.dom&&(o=b.dom),$++)}if(o=A,$!==E-f+1&&k(e,t,f,E+1),0===$)s(e,n,u,j+1,r,o,i);else if(-1===I)for(O=(z=function(e){var t=[0],n=0,r=0,o=0,i=m.length=e.length;for(o=0;o<i;o++)m[o]=e[o];for(o=0;o<i;++o)if(-1!==e[o]){var l=t[t.length-1];if(e[l]<e[o])m[o]=l,t.push(o);else{for(n=0,r=t.length-1;n<r;){var a=(n>>>1)+(r>>>1)+(n&r&1);e[t[a]]<e[o]?n=a+1:r=a}e[o]<e[t[n]]&&(n>0&&(m[o]=t[n-1]),t[n]=o)}}n=t.length,r=t[n-1];for(;n-- >0;)t[n]=r,r=m[r];return m.length=0,t}(N)).length-1,P=j;P>=u;P--)p=n[P],-1===N[P-u]?c(e,p,r,i,o):z[O]===P-u?O--:g(e,p,o),null!=p.dom&&(o=n[P].dom);else for(P=j;P>=u;P--)p=n[P],-1===N[P-u]&&c(e,p,r,i,o),null!=p.dom&&(o=n[P].dom)}}else{var R=t.length<n.length?t.length:n.length;for(u=u<f?u:f;u<R;u++)(d=t[u])===(p=n[u])||null==d&&null==p||(null==d?c(e,p,r,i,y(t,u+1,o)):null==p?x(e,d):h(e,d,p,r,y(t,u+1,o),i));t.length>R&&k(e,t,u,t.length),n.length>R&&s(e,n,u,n.length,r,o,i)}}}function h(t,n,r,o,l,u){var s=n.tag;if(s===r.tag){if(r.state=n.state,r.events=n.events,function(e,t){do{var n;if(null!=e.attrs&&"function"==typeof e.attrs.onbeforeupdate)if(void 0!==(n=a.call(e.attrs.onbeforeupdate,e,t))&&!n)break;if("string"!=typeof e.tag&&"function"==typeof e.state.onbeforeupdate)if(void 0!==(n=a.call(e.state.onbeforeupdate,e,t))&&!n)break;return!1}while(0);return e.dom=t.dom,e.domSize=t.domSize,e.instance=t.instance,e.attrs=t.attrs,e.children=t.children,e.text=t.text,!0}(r,n))return;if("string"==typeof s)switch(null!=r.attrs&&D(r.attrs,r,o),s){case"#":!function(e,t){e.children.toString()!==t.children.toString()&&(e.dom.nodeValue=t.children);t.dom=e.dom}(n,r);break;case"<":!function(e,t,n,r,o){t.children!==n.children?(S(e,t),d(e,n,r,o)):(n.dom=t.dom,n.domSize=t.domSize,n.instance=t.instance)}(t,n,r,u,l);break;case"[":!function(e,t,n,r,o,i){p(e,t.children,n.children,r,o,i);var l=0,a=n.children;if(n.dom=null,null!=a){for(var u=0;u<a.length;u++){var s=a[u];null!=s&&null!=s.dom&&(null==n.dom&&(n.dom=s.dom),l+=s.domSize||1)}1!==l&&(n.domSize=l)}}(t,n,r,o,l,u);break;default:!function(e,t,n,r){var o=t.dom=e.dom;r=i(t)||r,"textarea"===t.tag&&null==t.attrs&&(t.attrs={});(function(e,t,n,r){t&&t===n&&console.warn("Don't reuse attrs object, use new object for every redraw, this will throw in next major");if(null!=n){"input"===e.tag&&null!=n.type&&e.dom.setAttribute("type",n.type);var o="input"===e.tag&&"file"===n.type;for(var i in n)C(e,i,t&&t[i],n[i],r,o)}var l;if(null!=t)for(var i in t)null==(l=t[i])||null!=n&&null!=n[i]||z(e,i,l,r)})(t,e.attrs,t.attrs,r),b(t)||p(o,e.children,t.children,n,null,r)}(n,r,o,u)}else!function(t,n,r,o,i,l){if(r.instance=e.normalize(a.call(r.state.view,r)),r.instance===r)throw Error("A view cannot return the vnode it received as argument");D(r.state,r,o),null!=r.attrs&&D(r.attrs,r,o);null!=r.instance?(null==n.instance?c(t,r.instance,o,l,i):h(t,n.instance,r.instance,o,i,l),r.dom=r.instance.dom,r.domSize=r.instance.domSize):null!=n.instance?(x(t,n.instance),r.dom=void 0,r.domSize=0):(r.dom=n.dom,r.domSize=n.domSize)}(t,n,r,o,l,u)}else x(t,n),c(t,r,o,u,l)}function v(e,t,n){for(var r=Object.create(null);t<n;t++){var o=e[t];if(null!=o){var i=o.key;null!=i&&(r[i]=t)}}return r}var m=[];function y(e,t,n){for(;t<e.length;t++)if(null!=e[t]&&null!=e[t].dom)return e[t].dom;return n}function g(e,t,n){var o=r.createDocumentFragment();!function e(t,n,r){for(;null!=r.dom&&r.dom.parentNode===t;){if("string"!=typeof r.tag){if(null!=(r=r.instance))continue}else if("<"===r.tag)for(var o=0;o<r.instance.length;o++)n.appendChild(r.instance[o]);else if("["!==r.tag)n.appendChild(r.dom);else if(1===r.children.length){if(null!=(r=r.children[0]))continue}else for(o=0;o<r.children.length;o++){var i=r.children[o];null!=i&&e(t,n,i)}break}}(e,o,t),w(e,o,n)}function w(e,t,n){null!=n?e.insertBefore(t,n):e.appendChild(t)}function b(e){if(null==e.attrs||null==e.attrs.contenteditable&&null==e.attrs.contentEditable)return!1;var t=e.children;if(null!=t&&1===t.length&&"<"===t[0].tag){var n=t[0].children;e.dom.innerHTML!==n&&(e.dom.innerHTML=n)}else if(null!=t&&0!==t.length)throw new Error("Child node of a contenteditable must be trusted.");return!0}function k(e,t,n,r){for(var o=n;o<r;o++){var i=t[o];null!=i&&x(e,i)}}function x(e,t){var n,r,o,i=0,u=t.state;"string"!=typeof t.tag&&"function"==typeof t.state.onbeforeremove&&(null!=(o=a.call(t.state.onbeforeremove,t))&&"function"==typeof o.then&&(i=1,n=o));t.attrs&&"function"==typeof t.attrs.onbeforeremove&&(null!=(o=a.call(t.attrs.onbeforeremove,t))&&"function"==typeof o.then&&(i|=2,r=o));if(l(t,u),i){if(null!=n){var s=function(){1&i&&((i&=2)||c())};n.then(s,s)}if(null!=r){s=function(){2&i&&((i&=1)||c())};r.then(s,s)}}else j(t),E(e,t);function c(){l(t,u),j(t),E(e,t)}}function S(e,t){for(var n=0;n<t.instance.length;n++)e.removeChild(t.instance[n])}function E(e,t){for(;null!=t.dom&&t.dom.parentNode===e;){if("string"!=typeof t.tag){if(null!=(t=t.instance))continue}else if("<"===t.tag)S(e,t);else{if("["!==t.tag&&(e.removeChild(t.dom),!Array.isArray(t.children)))break;if(1===t.children.length){if(null!=(t=t.children[0]))continue}else for(var n=0;n<t.children.length;n++){var r=t.children[n];null!=r&&E(e,r)}}break}}function j(e){if("string"!=typeof e.tag&&"function"==typeof e.state.onremove&&a.call(e.state.onremove,e),e.attrs&&"function"==typeof e.attrs.onremove&&a.call(e.attrs.onremove,e),"string"!=typeof e.tag)null!=e.instance&&j(e.instance);else{var t=e.children;if(Array.isArray(t))for(var n=0;n<t.length;n++){var r=t[n];null!=r&&j(r)}}}function C(e,t,n,o,i,l){if(!("key"===t||"is"===t||null==o||A(t)||n===o&&!function(e,t){return"value"===t||"checked"===t||"selectedIndex"===t||"selected"===t&&e.dom===u()||"option"===e.tag&&e.dom.parentNode===r.activeElement}(e,t)&&"object"!=typeof o||"type"===t&&"input"===e.tag)){if("o"===t[0]&&"n"===t[1])return R(e,t,o);if("xlink:"===t.slice(0,6))e.dom.setAttributeNS("http://www.w3.org/1999/xlink",t.slice(6),o);else if("style"===t)$(e.dom,n,o);else if(T(e,t,i)){if("value"===t){if(("input"===e.tag||"textarea"===e.tag)&&e.dom.value===""+o&&(l||e.dom===u()))return;if("select"===e.tag&&null!==n&&e.dom.value===""+o)return;if("option"===e.tag&&null!==n&&e.dom.value===""+o)return;if(l&&""+o!="")return void console.error("`value` is read-only on file inputs!")}e.dom[t]=o}else"boolean"==typeof o?o?e.dom.setAttribute(t,""):e.dom.removeAttribute(t):e.dom.setAttribute("className"===t?"class":t,o)}}function z(e,t,n,r){if("key"!==t&&"is"!==t&&null!=n&&!A(t))if("o"===t[0]&&"n"===t[1])R(e,t,void 0);else if("style"===t)$(e.dom,n,null);else if(!T(e,t,r)||"className"===t||"title"===t||"value"===t&&("option"===e.tag||"select"===e.tag&&-1===e.dom.selectedIndex&&e.dom===u())||"input"===e.tag&&"type"===t){var o=t.indexOf(":");-1!==o&&(t=t.slice(o+1)),!1!==n&&e.dom.removeAttribute("className"===t?"class":t)}else e.dom[t]=null}function A(e){return"oninit"===e||"oncreate"===e||"onupdate"===e||"onremove"===e||"onbeforeremove"===e||"onbeforeupdate"===e}function T(e,t,n){return void 0===n&&(e.tag.indexOf("-")>-1||null!=e.attrs&&e.attrs.is||"href"!==t&&"list"!==t&&"form"!==t&&"width"!==t&&"height"!==t)&&t in e.dom}var N,O=/[A-Z]/g;function P(e){return"-"+e.toLowerCase()}function I(e){return"-"===e[0]&&"-"===e[1]?e:"cssFloat"===e?"float":e.replace(O,P)}function $(e,t,n){if(t===n);else if(null==n)e.style.cssText="";else if("object"!=typeof n)e.style.cssText=n;else if(null==t||"object"!=typeof t)for(var r in e.style.cssText="",n){null!=(o=n[r])&&e.style.setProperty(I(r),String(o))}else{for(var r in n){var o;null!=(o=n[r])&&(o=String(o))!==String(t[r])&&e.style.setProperty(I(r),o)}for(var r in t)null!=t[r]&&null==n[r]&&e.style.removeProperty(I(r))}}function L(){this._=n}function R(e,t,r){if(null!=e.events){if(e.events._=n,e.events[t]===r)return;null==r||"function"!=typeof r&&"object"!=typeof r?(null!=e.events[t]&&e.dom.removeEventListener(t.slice(2),e.events,!1),e.events[t]=void 0):(null==e.events[t]&&e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}else null==r||"function"!=typeof r&&"object"!=typeof r||(e.events=new L,e.dom.addEventListener(t.slice(2),e.events,!1),e.events[t]=r)}function _(e,t,n){"function"==typeof e.oninit&&a.call(e.oninit,t),"function"==typeof e.oncreate&&n.push(a.bind(e.oncreate,t))}function D(e,t,n){"function"==typeof e.onupdate&&n.push(a.bind(e.onupdate,t))}return L.prototype=Object.create(null),L.prototype.handleEvent=function(e){var t,n=this["on"+e.type];"function"==typeof n?t=n.call(e.currentTarget,e):"function"==typeof n.handleEvent&&n.handleEvent(e),this._&&!1!==e.redraw&&(0,this._)(),!1===t&&(e.preventDefault(),e.stopPropagation())},function(t,r,o){if(!t)throw new TypeError("DOM element being rendered to does not exist.");if(null!=N&&t.contains(N))throw new TypeError("Node is currently being rendered to and thus is locked.");var i=n,l=N,a=[],s=u(),c=t.namespaceURI;N=t,n="function"==typeof o?o:void 0;try{null==t.vnodes&&(t.textContent=""),r=e.normalizeChildren(Array.isArray(r)?r:[r]),p(t,t.vnodes,r,a,null,"http://www.w3.org/1999/xhtml"===c?void 0:c),t.vnodes=r,null!=s&&u()!==s&&"function"==typeof s.focus&&s.focus();for(var f=0;f<a.length;f++)a[f]()}finally{n=i,N=l}}}("undefined"!=typeof window?window:null),s=function(t,n,r){var o=[],i=!1,l=-1;function a(){for(l=0;l<o.length;l+=2)try{t(o[l],e(o[l+1]),u)}catch(e){r.error(e)}l=-1}function u(){i||(i=!0,n((function(){i=!1,a()})))}return u.sync=a,{mount:function(n,r){if(null!=r&&null==r.view&&"function"!=typeof r)throw new TypeError("m.mount expects a component, not a vnode.");var i=o.indexOf(n);i>=0&&(o.splice(i,2),i<=l&&(l-=2),t(n,[])),null!=r&&(o.push(n,r),t(n,e(r),u))},redraw:u}}(u,"undefined"!=typeof requestAnimationFrame?requestAnimationFrame:null,"undefined"!=typeof console?console:null),c=function(e){if("[object Object]"!==Object.prototype.toString.call(e))return"";var t=[];for(var n in e)r(n,e[n]);return t.join("&");function r(e,n){if(Array.isArray(n))for(var o=0;o<n.length;o++)r(e+"["+o+"]",n[o]);else if("[object Object]"===Object.prototype.toString.call(n))for(var o in n)r(e+"["+o+"]",n[o]);else t.push(encodeURIComponent(e)+(null!=n&&""!==n?"="+encodeURIComponent(n):""))}},f=Object.assign||function(e,t){for(var r in t)n.call(t,r)&&(e[r]=t[r])},d=function(e,t){if(/:([^\/\.-]+)(\.{3})?:/.test(e))throw new SyntaxError("Template parameter names must be separated by either a '/', '-', or '.'.");if(null==t)return e;var n=e.indexOf("?"),r=e.indexOf("#"),o=r<0?e.length:r,i=n<0?o:n,l=e.slice(0,i),a={};f(a,t);var u=l.replace(/:([^\/\.-]+)(\.{3})?/g,(function(e,n,r){return delete a[n],null==t[n]?e:r?t[n]:encodeURIComponent(String(t[n]))})),s=u.indexOf("?"),d=u.indexOf("#"),p=d<0?u.length:d,h=s<0?p:s,v=u.slice(0,h);n>=0&&(v+=e.slice(n,o)),s>=0&&(v+=(n<0?"?":"&")+u.slice(s,p));var m=c(a);return m&&(v+=(n<0&&s<0?"?":"&")+m),r>=0&&(v+=e.slice(r)),d>=0&&(v+=(r<0?"":"&")+u.slice(d)),v},p=function(e,t,r){var o=0;function i(e){return new t(e)}function l(e){return function(n,o){"string"!=typeof n?(o=n,n=n.url):null==o&&(o={});var l=new t((function(t,r){e(d(n,o.params),o,(function(e){if("function"==typeof o.type)if(Array.isArray(e))for(var n=0;n<e.length;n++)e[n]=new o.type(e[n]);else e=new o.type(e);t(e)}),r)}));if(!0===o.background)return l;var a=0;function u(){0==--a&&"function"==typeof r&&r()}return function e(t){var n=t.then;t.constructor=i;t.then=function(){a++;var r=n.apply(t,arguments);return r.then(u,(function(e){if(u(),0===a)throw e})),e(r)};return t}(l)}}function a(e,t){for(var r in e.headers)if(n.call(e.headers,r)&&r.toLowerCase()===t)return!0;return!1}return i.prototype=t.prototype,i.__proto__=t,{request:l((function(t,r,o,i){var l,u=null!=r.method?r.method.toUpperCase():"GET",s=r.body,c=(null==r.serialize||r.serialize===JSON.serialize)&&!(s instanceof e.FormData||s instanceof e.URLSearchParams),f=r.responseType||("function"==typeof r.extract?"":"json"),d=new e.XMLHttpRequest,p=!1,h=!1,v=d,m=d.abort;for(var y in d.abort=function(){p=!0,m.call(this)},d.open(u,t,!1!==r.async,"string"==typeof r.user?r.user:void 0,"string"==typeof r.password?r.password:void 0),c&&null!=s&&!a(r,"content-type")&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),"function"==typeof r.deserialize||a(r,"accept")||d.setRequestHeader("Accept","application/json, text/*"),r.withCredentials&&(d.withCredentials=r.withCredentials),r.timeout&&(d.timeout=r.timeout),d.responseType=f,r.headers)n.call(r.headers,y)&&d.setRequestHeader(y,r.headers[y]);d.onreadystatechange=function(e){if(!p&&4===e.target.readyState)try{var n,l=e.target.status>=200&&e.target.status<300||304===e.target.status||/^file:\/\//i.test(t),a=e.target.response;if("json"===f){if(!e.target.responseType&&"function"!=typeof r.extract)try{a=JSON.parse(e.target.responseText)}catch(e){a=null}}else f&&"text"!==f||null==a&&(a=e.target.responseText);if("function"==typeof r.extract?(a=r.extract(e.target,r),l=!0):"function"==typeof r.deserialize&&(a=r.deserialize(a)),l)o(a);else{var u=function(){try{n=e.target.responseText}catch(e){n=a}var t=new Error(n);t.code=e.target.status,t.response=a,i(t)};0===d.status?setTimeout((function(){h||u()})):u()}}catch(e){i(e)}},d.ontimeout=function(e){h=!0;var t=new Error("Request timed out");t.code=e.target.status,i(t)},"function"==typeof r.config&&(d=r.config(d,r,t)||d)!==v&&(l=d.abort,d.abort=function(){p=!0,l.call(this)}),null==s?d.send():"function"==typeof r.serialize?d.send(r.serialize(s)):s instanceof e.FormData||s instanceof e.URLSearchParams?d.send(s):d.send(JSON.stringify(s))})),jsonp:l((function(t,n,r,i){var l=n.callbackName||"_mithril_"+Math.round(1e16*Math.random())+"_"+o++,a=e.document.createElement("script");e[l]=function(t){delete e[l],a.parentNode.removeChild(a),r(t)},a.onerror=function(){delete e[l],a.parentNode.removeChild(a),i(new Error("JSONP request failed"))},a.src=t+(t.indexOf("?")<0?"?":"&")+encodeURIComponent(n.callbackKey||"callback")+"="+encodeURIComponent(l),e.document.documentElement.appendChild(a)}))}}("undefined"!=typeof window?window:null,a,s.redraw),h=s,v=function(){return l.apply(this,arguments)};v.m=l,v.trust=l.trust,v.fragment=l.fragment,v.Fragment="[",v.mount=h.mount;var m=l,y=a;function g(e){try{return decodeURIComponent(e)}catch(t){return e}}var w=function(e){if(""===e||null==e)return{};"?"===e.charAt(0)&&(e=e.slice(1));for(var t=e.split("&"),n={},r={},o=0;o<t.length;o++){var i=t[o].split("="),l=g(i[0]),a=2===i.length?g(i[1]):"";"true"===a?a=!0:"false"===a&&(a=!1);var u=l.split(/\]\[?|\[/),s=r;l.indexOf("[")>-1&&u.pop();for(var c=0;c<u.length;c++){var f=u[c],d=u[c+1],p=""==d||!isNaN(parseInt(d,10));if(""===f)null==n[l=u.slice(0,c).join()]&&(n[l]=Array.isArray(s)?s.length:0),f=n[l]++;else if("__proto__"===f)break;if(c===u.length-1)s[f]=a;else{var h=Object.getOwnPropertyDescriptor(s,f);null!=h&&(h=h.value),null==h&&(s[f]=h=p?[]:{}),s=h}}}return r},b=function(e){var t=e.indexOf("?"),n=e.indexOf("#"),r=n<0?e.length:n,o=t<0?r:t,i=e.slice(0,o).replace(/\/{2,}/g,"/");return i?("/"!==i[0]&&(i="/"+i),i.length>1&&"/"===i[i.length-1]&&(i=i.slice(0,-1))):i="/",{path:i,params:t<0?{}:w(e.slice(t+1,r))}},k=function(e){var t=b(e),n=Object.keys(t.params),r=[],o=new RegExp("^"+t.path.replace(/:([^\/.-]+)(\.{3}|\.(?!\.)|-)?|[\\^$*+.()|\[\]{}]/g,(function(e,t,n){return null==t?"\\"+e:(r.push({k:t,r:"..."===n}),"..."===n?"(.*)":"."===n?"([^/]+)\\.":"([^/]+)"+(n||""))}))+"$");return function(e){for(var i=0;i<n.length;i++)if(t.params[n[i]]!==e.params[n[i]])return!1;if(!r.length)return o.test(e.path);var l=o.exec(e.path);if(null==l)return!1;for(i=0;i<r.length;i++)e.params[r[i].k]=r[i].r?l[i+1]:decodeURIComponent(l[i+1]);return!0}},x=new RegExp("^(?:key|oninit|oncreate|onbeforeupdate|onupdate|onbeforeremove|onremove)$"),S=function(e,t){var r={};if(null!=t)for(var o in e)n.call(e,o)&&!x.test(o)&&t.indexOf(o)<0&&(r[o]=e[o]);else for(var o in e)n.call(e,o)&&!x.test(o)&&(r[o]=e[o]);return r},E={};function j(e){try{return decodeURIComponent(e)}catch(t){return e}}v.route=function(t,n){var r,o,i,l,a,u,s=null==t?null:"function"==typeof t.setImmediate?t.setImmediate:t.setTimeout,c=y.resolve(),p=!1,h=!1,v=0,g=E,w={onbeforeupdate:function(){return!(!(v=v?2:1)||E===g)},onremove:function(){t.removeEventListener("popstate",z,!1),t.removeEventListener("hashchange",C,!1)},view:function(){if(v&&E!==g){var t=[e(i,l.key,l)];return g&&(t=g.render(t[0])),t}}},x=T.SKIP={};function C(){p=!1;var e=t.location.hash;"#"!==T.prefix[0]&&(e=t.location.search+e,"?"!==T.prefix[0]&&"/"!==(e=t.location.pathname+e)[0]&&(e="/"+e));var s=e.concat().replace(/(?:%[a-f89][a-f0-9])+/gim,j).slice(T.prefix.length),d=b(s);function h(e){console.error(e),A(o,null,{replace:!0})}f(d.params,t.history.state),function e(t){for(;t<r.length;t++)if(r[t].check(d)){var f=r[t].component,p=r[t].route,m=f,y=u=function(r){if(y===u){if(r===x)return e(t+1);i=null==r||"function"!=typeof r.view&&"function"!=typeof r?"div":r,l=d.params,a=s,u=null,g=f.render?f:null,2===v?n.redraw():(v=2,n.redraw.sync())}};return void(f.view||"function"==typeof f?(f={},y(m)):f.onmatch?c.then((function(){return f.onmatch(d.params,s,p)})).then(y,s===o?null:h):y("div"))}if(s===o)throw new Error("Could not resolve default route "+o+".");A(o,null,{replace:!0})}(0)}function z(){p||(p=!0,s(C))}function A(e,n,r){if(e=d(e,n),h){z();var o=r?r.state:null,i=r?r.title:null;r&&r.replace?t.history.replaceState(o,i,T.prefix+e):t.history.pushState(o,i,T.prefix+e)}else t.location.href=T.prefix+e}function T(e,i,l){if(!e)throw new TypeError("DOM element being rendered to does not exist.");if(r=Object.keys(l).map((function(e){if("/"!==e[0])throw new SyntaxError("Routes must start with a '/'.");if(/:([^\/\.-]+)(\.{3})?:/.test(e))throw new SyntaxError("Route parameter names must be separated with either '/', '.', or '-'.");return{route:e,component:l[e],check:k(e)}})),o=i,null!=i){var a=b(i);if(!r.some((function(e){return e.check(a)})))throw new ReferenceError("Default route doesn't match any known routes.")}"function"==typeof t.history.pushState?t.addEventListener("popstate",z,!1):"#"===T.prefix[0]&&t.addEventListener("hashchange",C,!1),h=!0,n.mount(e,w),C()}return T.set=function(e,t,n){null!=u&&((n=n||{}).replace=!0),u=null,A(e,t,n)},T.get=function(){return a},T.prefix="#!",T.Link={view:function(e){var t,n,r,o=m(e.attrs.selector||"a",S(e.attrs,["options","params","selector","onclick"]),e.children);return(o.attrs.disabled=Boolean(o.attrs.disabled))?(o.attrs.href=null,o.attrs["aria-disabled"]="true"):(t=e.attrs.options,n=e.attrs.onclick,r=d(o.attrs.href,e.attrs.params),o.attrs.href=T.prefix+r,o.attrs.onclick=function(e){var o;"function"==typeof n?o=n.call(e.currentTarget,e):null==n||"object"!=typeof n||"function"==typeof n.handleEvent&&n.handleEvent(e),!1===o||e.defaultPrevented||0!==e.button&&0!==e.which&&1!==e.which||e.currentTarget.target&&"_self"!==e.currentTarget.target||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||(e.preventDefault(),e.redraw=!1,T.set(r,null,t))}),o}},T.param=function(e){return l&&null!=e?l[e]:l},T}("undefined"!=typeof window?window:null,h),v.render=u,v.redraw=h.redraw,v.request=p.request,v.jsonp=p.jsonp,v.parseQueryString=w,v.buildQueryString=c,v.parsePathname=b,v.buildPathname=d,v.vnode=e,v.PromisePolyfill=a,v.censor=S,"undefined"!=typeof module?module.exports=v:window.m=v}();
|