Release 1.0.10 with subpath deployment and modal menu invokes.

Add app_base/router_base config, compat path helpers, and scoped service worker
registration so apps can mount under a URL prefix. Wire invoke_type modal through
a handler registry and open the notification center from the standard menu flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Amer Agovic
2026-06-16 16:44:32 -05:00
parent 5810008fa5
commit aa872bdd6b
9 changed files with 381 additions and 33 deletions
+38
View File
@@ -0,0 +1,38 @@
import { describe, it } from 'node:test';
import assert from 'node:assert';
import {
getViteBasePath,
prefixPublicAssetPath,
stripRouterBase,
withRouterBase
} from '../src/platform/compat.js';
import { initEnv, getConfigSync, CONFIG_KEYS } from '../src/platform/env.js';
describe('compat path helpers', () => {
it('normalizes vite base paths', () => {
assert.strictEqual(getViteBasePath('/'), '/');
assert.strictEqual(getViteBasePath('/admin'), '/admin/');
assert.strictEqual(getViteBasePath('/admin/'), '/admin/');
});
it('maps internal routes to public URLs and back', () => {
assert.strictEqual(withRouterBase('/home', '/admin'), '/admin/home');
assert.strictEqual(withRouterBase('/', '/admin'), '/admin/');
assert.strictEqual(stripRouterBase('/admin/home', '/admin'), '/home');
assert.strictEqual(stripRouterBase('/admin/', '/admin'), '/');
assert.strictEqual(stripRouterBase('/admin', '/admin'), '/');
assert.strictEqual(stripRouterBase('/home', '/admin'), '/');
});
it('prefixes public asset paths but not /api', () => {
assert.strictEqual(prefixPublicAssetPath('/brand-logo.svg', '/admin'), '/admin/brand-logo.svg');
assert.strictEqual(prefixPublicAssetPath('/api', '/admin'), '/api');
assert.strictEqual(prefixPublicAssetPath('/admin/logo.svg', '/admin'), '/admin/logo.svg');
});
it('seeds router base into env config', () => {
initEnv({ id: 'demo', app_base: '/admin' });
assert.strictEqual(getConfigSync(CONFIG_KEYS.APP_BASE), '/admin');
assert.strictEqual(getConfigSync(CONFIG_KEYS.ROUTER_BASE), '/admin');
});
});
+29
View File
@@ -15,6 +15,8 @@ import {
isProduction,
isServiceWorkerEnabledSync,
resolveServiceWorkerEnabled,
resolveProfileBases,
normalizeRouterBase,
CONFIG_KEYS
} from '../src/platform/env.js';
import { getProvider } from '../src/platform/storage.js';
@@ -201,6 +203,33 @@ describe('env.js', () => {
});
});
describe('profile base paths', () => {
test('resolveProfileBases defaults to root', () => {
assert.deepStrictEqual(resolveProfileBases({}), { app_base: '/', router_base: '/' });
});
test('resolveProfileBases mirrors a single configured base', () => {
assert.deepStrictEqual(resolveProfileBases({ app_base: '/admin/' }), {
app_base: '/admin',
router_base: '/admin'
});
});
test('resolveProfileBases allows separate router base', () => {
assert.deepStrictEqual(resolveProfileBases({ app_base: '/admin', router_base: '/console' }), {
app_base: '/admin',
router_base: '/console'
});
});
test('initEnv seeds APP_BASE and ROUTER_BASE', () => {
initEnv({ id: 'demo', router_base: 'ops' });
assert.strictEqual(getConfigSync(CONFIG_KEYS.ROUTER_BASE), '/ops');
assert.strictEqual(getConfigSync(CONFIG_KEYS.APP_BASE), '/ops');
assert.strictEqual(normalizeRouterBase('/ops/'), '/ops');
});
});
describe('isDevelopment and isProduction', () => {
test('should be functions', () => {
assert.strictEqual(typeof isDevelopment, 'function');