mnfst 0.5.30 → 0.5.31

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.
@@ -18,7 +18,8 @@ async function ensureManifest() {
18
18
  }
19
19
 
20
20
  try {
21
- const response = await fetch('/manifest.json');
21
+ const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
22
+ const response = await fetch(manifestUrl);
22
23
  return await response.json();
23
24
  } catch (error) {
24
25
  return null;
@@ -221,6 +222,16 @@ function initializeAuthStore() {
221
222
  _updatingTeam: null, // Team ID being updated (null when not updating)
222
223
  _deletingTeam: null, // Team ID being deleted (null when not deleting)
223
224
  _creatingTeam: false, // Boolean flag for team creation
225
+ // Stub team convenience methods (replaced by teams.convenience.js; prevent "is not a function" before init)
226
+ isCreatingTeam() { return this._creatingTeam === true; },
227
+ isUpdatingTeam() { return false; },
228
+ isDeletingTeam() { return false; },
229
+ isInvitingMember() { return false; },
230
+ isUpdatingMember() { return false; },
231
+ isDeletingMember() { return false; },
232
+ isUpdatingRole() { return false; },
233
+ isDeletingRole() { return false; },
234
+ isCreatingRole() { return false; },
224
235
  // Member operation-specific loading states
225
236
  _updatingMember: null, // Membership ID being updated (null when not updating)
226
237
  _deletingMember: null, // Membership ID being deleted (null when not deleting)
@@ -1,5 +1,51 @@
1
1
  /* Manifest Components */
2
2
 
3
+ // Base URL for manifest-relative paths (e.g. "../" when viewing dist/index.html). Used by component loader, data loaders, localization.
4
+ window.getManifestBase = function getManifestBase() {
5
+ const href = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
6
+ const lastSlash = href.lastIndexOf('/');
7
+ return lastSlash >= 0 ? href.slice(0, lastSlash + 1) : '/';
8
+ };
9
+
10
+ // Absolute pathname prefix for the app root (e.g. "/src/dist"). Used by router for links and route matching.
11
+ // Prerender injects <meta name="manifest:router-base" content="/path"> from manifest.prerender.routerBase or root+output. If present, use it; else fall back to depth or manifest link.
12
+ window.getManifestBasePath = function getManifestBasePath() {
13
+ const baseMeta = document.querySelector('meta[name="manifest:router-base"]');
14
+ const content = baseMeta?.getAttribute('content');
15
+ if (content != null && content !== '') {
16
+ const base = '/' + String(content).replace(/^\/+|\/+$/g, '').trim();
17
+ return base || '';
18
+ }
19
+ const meta = document.querySelector('meta[name="manifest:router-base-depth"]');
20
+ const depth = meta ? parseInt(meta.getAttribute('content'), 10) : NaN;
21
+ if (!Number.isNaN(depth) && depth >= 0) {
22
+ const pathname = (window.location.pathname || '/').replace(/\/$/, '') || '/';
23
+ const segments = pathname.split('/').filter(Boolean);
24
+ if (depth === 0) {
25
+ try {
26
+ const link = document.querySelector('link[rel="manifest"]');
27
+ const href = (link?.getAttribute('href')) || '/manifest.json';
28
+ const url = new URL(href, window.location.href);
29
+ const basePath = url.pathname.replace(/\/[^/]*$/, '') || '/';
30
+ return basePath === '/' ? '' : basePath;
31
+ } catch {
32
+ return '';
33
+ }
34
+ }
35
+ const keep = Math.max(0, segments.length - depth);
36
+ return keep === 0 ? '' : '/' + segments.slice(0, keep).join('/');
37
+ }
38
+ try {
39
+ const link = document.querySelector('link[rel="manifest"]');
40
+ const href = (link?.getAttribute('href')) || '/manifest.json';
41
+ const url = new URL(href, window.location.href);
42
+ const pathname = url.pathname.replace(/\/[^/]*$/, '') || '/';
43
+ return pathname === '/' ? '' : pathname;
44
+ } catch {
45
+ return '';
46
+ }
47
+ };
48
+
3
49
  // Components registry
4
50
  window.ManifestComponentsRegistry = {
5
51
  manifest: null,
@@ -78,9 +124,11 @@ window.ManifestComponentsLoader = {
78
124
  console.warn('[Manifest] Component', name, 'not found in manifest.');
79
125
  return null;
80
126
  }
127
+ const base = (typeof window.getManifestBase === 'function' ? window.getManifestBase() : '') || '/';
128
+ const url = path.startsWith('/') || path.startsWith('http') ? path : base + path;
81
129
  const promise = (async () => {
82
130
  try {
83
- const response = await fetch('/' + path);
131
+ const response = await fetch(url);
84
132
  if (!response.ok) {
85
133
  console.warn('[Manifest] HTML file not found for component', name, 'at path:', path, '(HTTP', response.status + ')');
86
134
  return null;
@@ -10,7 +10,8 @@ async function ensureManifest() {
10
10
  }
11
11
 
12
12
  try {
13
- const response = await fetch('/manifest.json');
13
+ const manifestUrl = (document.querySelector('link[rel="manifest"]')?.getAttribute('href')) || '/manifest.json';
14
+ const response = await fetch(manifestUrl);
14
15
  return await response.json();
15
16
  } catch (error) {
16
17
  console.error('[Manifest Data] Failed to load manifest:', error);
@@ -1561,30 +1562,41 @@ function parseCSVToNestedObject(csvText, options = {}) {
1561
1562
  }
1562
1563
  }
1563
1564
 
1565
+ // Load a local file (JSON, YAML, CSV). Resolves manifest-relative paths when viewing from dist.
1566
+ function resolveDataPath(filePath) {
1567
+ if (!filePath || typeof filePath !== 'string' || filePath.startsWith('http')) {
1568
+ return filePath;
1569
+ }
1570
+ const base = typeof window.getManifestBase === 'function' ? window.getManifestBase() : '';
1571
+ const pathOnly = filePath.startsWith('/') ? filePath.slice(1) : filePath;
1572
+ return base ? base + pathOnly : filePath;
1573
+ }
1574
+
1564
1575
  // Load a local file (JSON, YAML, CSV)
1565
1576
  async function loadLocalFile(filePath, options = {}) {
1566
- const response = await fetch(filePath);
1577
+ const resolved = resolveDataPath(filePath);
1578
+ const response = await fetch(resolved);
1567
1579
 
1568
1580
  // Check if file exists
1569
1581
  if (!response.ok) {
1570
- throw new Error(`[Manifest Data] File not found: ${filePath} (${response.status})`);
1582
+ throw new Error(`[Manifest Data] File not found: ${resolved} (${response.status})`);
1571
1583
  }
1572
1584
 
1573
1585
  const contentType = response.headers.get('content-type');
1574
1586
 
1575
1587
  // Handle CSV files
1576
- if (filePath.endsWith('.csv') || contentType?.includes('text/csv')) {
1588
+ if (resolved.endsWith('.csv') || contentType?.includes('text/csv')) {
1577
1589
  const text = await response.text();
1578
1590
  const csvParser = await loadCSVParser();
1579
1591
  // Pass currentLocale if provided in options
1580
1592
  return parseCSVToNestedObject(text, { currentLocale: options.currentLocale });
1581
1593
  }
1582
1594
  // Handle JSON files
1583
- else if (contentType?.includes('application/json') || filePath.endsWith('.json')) {
1595
+ else if (contentType?.includes('application/json') || resolved.endsWith('.json')) {
1584
1596
  return await response.json();
1585
1597
  }
1586
1598
  // Handle YAML files
1587
- else if (contentType?.includes('text/yaml') || filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
1599
+ else if (contentType?.includes('text/yaml') || resolved.endsWith('.yaml') || resolved.endsWith('.yml')) {
1588
1600
  const text = await response.text();
1589
1601
  const yamlLib = await loadYamlLibrary();
1590
1602
  return yamlLib.load(text);
@@ -1612,6 +1624,7 @@ window.ManifestDataLoaders = {
1612
1624
  loadCSVParser,
1613
1625
  deepMergeWithFallback,
1614
1626
  parseCSVToNestedObject,
1627
+ resolveDataPath,
1615
1628
  loadLocalFile
1616
1629
  };
1617
1630
 
@@ -4868,18 +4881,24 @@ if (!window.ManifestDataRouteProxyUpdateQueue) {
4868
4881
 
4869
4882
  // Debounce all updates
4870
4883
  this.timeout = setTimeout(() => {
4871
- const proxiesToUpdate = Array.from(this.pending);
4872
- this.pending.clear();
4873
-
4874
- // Update all pending proxies
4875
- proxiesToUpdate.forEach(updateFn => {
4876
- try {
4877
- updateFn();
4878
- } catch (error) {
4879
- console.error('[Manifest Data] Error updating route proxy:', error);
4880
- }
4881
- });
4884
+ this.flushSync();
4882
4885
  }, 0);
4886
+ },
4887
+ // Run all pending proxy updates immediately (e.g. on route change so content updates without refresh)
4888
+ flushSync() {
4889
+ if (this.timeout) {
4890
+ clearTimeout(this.timeout);
4891
+ this.timeout = null;
4892
+ }
4893
+ const proxiesToUpdate = Array.from(this.pending);
4894
+ this.pending.clear();
4895
+ proxiesToUpdate.forEach(updateFn => {
4896
+ try {
4897
+ updateFn();
4898
+ } catch (error) {
4899
+ console.error('[Manifest Data] Error updating route proxy:', error);
4900
+ }
4901
+ });
4883
4902
  }
4884
4903
  };
4885
4904
  }
@@ -11538,8 +11557,14 @@ function setupUrlChangeListeners() {
11538
11557
 
11539
11558
  // Listen to router's route change event (primary integration point)
11540
11559
  window.addEventListener('manifest:route-change', (event) => {
11541
- const newUrl = event.detail?.to || window.location.pathname;
11560
+ const newUrl = event.detail?.to ?? window.ManifestRoutingNavigation?.getCurrentRoute?.() ?? window.location.pathname;
11542
11561
  updateCurrentUrl(newUrl);
11562
+ // Flush route proxies after other listeners have queued their updates, so $x.*.$route('path') content updates without refresh
11563
+ setTimeout(() => {
11564
+ if (window.ManifestDataRouteProxyUpdateQueue?.flushSync) {
11565
+ window.ManifestDataRouteProxyUpdateQueue.flushSync();
11566
+ }
11567
+ }, 0);
11543
11568
  });
11544
11569
 
11545
11570
  // Also listen for popstate (browser back/forward)
@@ -6,7 +6,7 @@ function initializeDropdownPlugin() {
6
6
  function ensureAlpineContext() {
7
7
  const body = document.body;
8
8
  if (!body.hasAttribute('x-data')) {
9
- body.setAttribute('x-data', '{}');
9
+ body.setAttribute('x-data', '{ tab: \'local-data\' }');
10
10
  }
11
11
  }
12
12
 
@@ -161,7 +161,10 @@ function initializeLocalizationPlugin() {
161
161
  // Check for single-file multi-locale CSV (e.g., {"locales": "/path/to/file.csv"})
162
162
  if (collection.locales && typeof collection.locales === 'string' && collection.locales.endsWith('.csv')) {
163
163
  try {
164
- const csvResponse = await fetch(collection.locales);
164
+ const base = typeof window.getManifestBase === 'function' ? window.getManifestBase() : '';
165
+ const localesPath = collection.locales.startsWith('/') ? collection.locales.slice(1) : collection.locales;
166
+ const localesUrl = (collection.locales.startsWith('http')) ? collection.locales : (base + localesPath);
167
+ const csvResponse = await fetch(localesUrl);
165
168
  if (csvResponse.ok) {
166
169
  const csvText = await csvResponse.text();
167
170
  // Parse CSV header to get locale columns
@@ -195,7 +198,10 @@ function initializeLocalizationPlugin() {
195
198
  } else if (typeof collection === 'string' && collection.endsWith('.csv')) {
196
199
  // Simple CSV file path - check if it has locale columns
197
200
  try {
198
- const csvResponse = await fetch(collection);
201
+ const base = typeof window.getManifestBase === 'function' ? window.getManifestBase() : '';
202
+ const csvPath = collection.startsWith('/') ? collection.slice(1) : collection;
203
+ const csvUrl = collection.startsWith('http') ? collection : (base + csvPath);
204
+ const csvResponse = await fetch(csvUrl);
199
205
  if (csvResponse.ok) {
200
206
  const csvText = await csvResponse.text();
201
207
  const lines = csvText.split('\n').filter(line => line.trim());
@@ -466,12 +466,12 @@ async function initializeMarkdownPlugin() {
466
466
  // If it's a file path, fetch the content (with caching)
467
467
  if (isFilePath) {
468
468
  try {
469
- // Ensure the path is absolute from project root
469
+ // Resolve path: relative paths are relative to manifest base (project root), not document root
470
470
  let resolvedPath = pathOrContent;
471
-
472
- // If it's a relative path (doesn't start with /), make it absolute from root
473
471
  if (!pathOrContent.startsWith('/')) {
474
- resolvedPath = '/' + pathOrContent;
472
+ const base = (typeof window.getManifestBase === 'function' ? window.getManifestBase() : '') || '';
473
+ const basePath = base.replace(/\/$/, '') || '';
474
+ resolvedPath = (basePath ? basePath + '/' : '/') + pathOrContent;
475
475
  }
476
476
 
477
477
  // Check cache first
@@ -159,13 +159,30 @@ window.ManifestRoutingPosition = {
159
159
 
160
160
  // Router navigation
161
161
 
162
- // Current route state
162
+ // Current route state (logical path, e.g. /gadget; not full pathname when app is in a subpath)
163
163
  let currentRoute = '/';
164
164
  let isInternalNavigation = false;
165
165
 
166
+ function getBasePath() {
167
+ return (typeof window.getManifestBasePath === 'function' ? window.getManifestBasePath() : '') || '';
168
+ }
169
+
170
+ function pathnameToLogical(pathname) {
171
+ const base = getBasePath();
172
+ if (!base || pathname === base || pathname === base + '/') return '/';
173
+ if (pathname.startsWith(base + '/')) {
174
+ let logical = pathname.slice(base.length) || '/';
175
+ if (logical === '/index.html' || logical === '/index') logical = '/';
176
+ return logical;
177
+ }
178
+ if (pathname === base + '/index.html' || pathname === base + '/index') return '/';
179
+ return pathname;
180
+ }
181
+
166
182
  // Handle route changes
167
183
  async function handleRouteChange() {
168
- const newRoute = window.location.pathname;
184
+ const pathname = window.location.pathname;
185
+ const newRoute = pathnameToLogical(pathname);
169
186
  if (newRoute === currentRoute) return;
170
187
 
171
188
  currentRoute = newRoute;
@@ -215,6 +232,36 @@ async function handleRouteChange() {
215
232
  }));
216
233
  }
217
234
 
235
+ // Resolve internal link to absolute pathname for pushState. Relative hrefs (e.g. "gadget") are resolved against the app base, not the current URL, so we never get additive paths like /src/dist/widget/gadget/widget/...
236
+ function resolveHref(href) {
237
+ if (!href || href.startsWith('#') || href.startsWith('mailto:') || href.startsWith('tel:')) return href;
238
+ try {
239
+ const base = getBasePath();
240
+ const baseUrl = base ? (window.location.origin + base + '/') : (window.location.origin + '/');
241
+ const url = new URL(href, baseUrl);
242
+ if (url.origin !== window.location.origin) return href;
243
+ let path = url.pathname.replace(/\/$/, '') || '/';
244
+ if (!base) return path.startsWith('/') ? path : '/' + path;
245
+ if (path === base || path.startsWith(base + '/')) return path;
246
+ // path may be above base (e.g. /gadget when base is /src/dist) or unrelated; take only the route part and put under base so we never stack.
247
+ if (path.startsWith('/')) {
248
+ const pathSegs = path.split('/').filter(Boolean);
249
+ const baseSegs = base.split('/').filter(Boolean);
250
+ let i = 0;
251
+ while (i < baseSegs.length && i < pathSegs.length && baseSegs[i] === pathSegs[i]) i++;
252
+ const routeSegs = pathSegs.slice(i);
253
+ if (routeSegs.length) return base + '/' + routeSegs.join('/');
254
+ }
255
+ const out = base + (path.startsWith('/') ? path : '/' + path);
256
+ return out.startsWith('/') ? out : '/' + out;
257
+ } catch {
258
+ const base = getBasePath();
259
+ const safe = (href || '').trim();
260
+ if (!safe) return base || '/';
261
+ return base ? (base + (safe.startsWith('/') ? safe : '/' + safe)) : (safe.startsWith('/') ? safe : '/' + safe);
262
+ }
263
+ }
264
+
218
265
  // Intercept link clicks to prevent page reloads
219
266
  function interceptLinkClicks() {
220
267
  // Use capture phase to intercept before other handlers
@@ -247,6 +294,7 @@ function interceptLinkClicks() {
247
294
  // Handle links with both route and anchor (e.g., /page#section)
248
295
  if (href.includes('#')) {
249
296
  const [path, hash] = href.split('#');
297
+ const fullHref = resolveHref(path) + (hash ? '#' + hash : '');
250
298
 
251
299
  event.preventDefault();
252
300
  event.stopPropagation();
@@ -255,8 +303,8 @@ function interceptLinkClicks() {
255
303
  // Set flag to prevent recursive calls
256
304
  isInternalNavigation = true;
257
305
 
258
- // Update URL without page reload
259
- history.pushState(null, '', href);
306
+ // Update URL without page reload (use base path when app is in a subpath)
307
+ history.pushState(null, '', fullHref);
260
308
 
261
309
  // Handle route change (but don't scroll to top since there's an anchor)
262
310
  handleRouteChange();
@@ -282,8 +330,9 @@ function interceptLinkClicks() {
282
330
  // Set flag to prevent recursive calls
283
331
  isInternalNavigation = true;
284
332
 
285
- // Update URL without page reload
286
- history.pushState(null, '', href);
333
+ // Update URL without page reload (use base path when app is in a subpath, e.g. /src/dist/gadget)
334
+ const fullHref = resolveHref(href);
335
+ history.pushState(null, '', fullHref);
287
336
 
288
337
  // Handle route change
289
338
  handleRouteChange();
@@ -296,8 +345,8 @@ function interceptLinkClicks() {
296
345
 
297
346
  // Initialize navigation
298
347
  function initializeNavigation() {
299
- // Set initial route
300
- currentRoute = window.location.pathname;
348
+ // Set initial route (logical path for matching)
349
+ currentRoute = pathnameToLogical(window.location.pathname);
301
350
 
302
351
  // Intercept link clicks
303
352
  interceptLinkClicks();
@@ -323,7 +372,10 @@ if (document.readyState === 'loading') {
323
372
  // Export navigation interface
324
373
  window.ManifestRoutingNavigation = {
325
374
  initialize: initializeNavigation,
326
- getCurrentRoute: () => currentRoute
375
+ getCurrentRoute: () => currentRoute,
376
+ getBasePath,
377
+ resolveHref,
378
+ pathnameToLogical
327
379
  };
328
380
 
329
381
  // Router visibility
@@ -456,8 +508,8 @@ function initializeVisibility() {
456
508
  // Add x-cloak to route elements to prevent flash
457
509
  addXCloakToRouteElements();
458
510
 
459
- // Process initial visibility
460
- const currentPath = window.location.pathname;
511
+ // Process initial visibility (use logical path when app is in a subpath)
512
+ const currentPath = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
461
513
  const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/^\/|\/$/g, '');
462
514
  processRouteVisibility(normalizedPath);
463
515
 
@@ -471,7 +523,7 @@ function initializeVisibility() {
471
523
  // Add x-cloak to any new route elements
472
524
  addXCloakToRouteElements();
473
525
 
474
- const currentPath = window.location.pathname;
526
+ const currentPath = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
475
527
  const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/^\/|\/$/g, '');
476
528
  processRouteVisibility(normalizedPath);
477
529
  });
@@ -687,7 +739,7 @@ function initializeHeadContent() {
687
739
  function processHeadContentAfterComponentsReady() {
688
740
  // Process initial head content after a longer delay to let components settle
689
741
  setTimeout(() => {
690
- const currentPath = window.location.pathname;
742
+ const currentPath = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
691
743
  const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/^\/|\/$/g, '');
692
744
 
693
745
  // Debug: Check if about component exists
@@ -706,7 +758,7 @@ function initializeHeadContent() {
706
758
 
707
759
  // Function to process head content immediately (for projects without components)
708
760
  function processHeadContentImmediately() {
709
- const currentPath = window.location.pathname;
761
+ const currentPath = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
710
762
  const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/^\/|\/$/g, '');
711
763
  processAllHeadContent(normalizedPath);
712
764
  }
@@ -740,7 +792,7 @@ function initializeHeadContent() {
740
792
  // Wait a bit for components to settle after route change
741
793
  setTimeout(() => {
742
794
  // Process head content immediately to catch components before they're reverted
743
- const currentPath = window.location.pathname;
795
+ const currentPath = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
744
796
  const normalizedPath = currentPath === '/' ? '/' : currentPath.replace(/^\/|\/$/g, '');
745
797
 
746
798
  // Debug: Check if about component exists
@@ -1126,9 +1178,9 @@ function initializeRouterMagic() {
1126
1178
  return;
1127
1179
  }
1128
1180
 
1129
- // Create a reactive object for route data
1181
+ // Create a reactive object for route data (use logical path when app is in a subpath)
1130
1182
  const route = Alpine.reactive({
1131
- current: window.location.pathname,
1183
+ current: window.ManifestRoutingNavigation?.getCurrentRoute() || window.location.pathname,
1132
1184
  segments: [],
1133
1185
  params: {},
1134
1186
  matches: null
@@ -1136,7 +1188,7 @@ function initializeRouterMagic() {
1136
1188
 
1137
1189
  // Update route when route changes
1138
1190
  const updateRoute = () => {
1139
- const currentRoute = window.ManifestRoutingNavigation?.getCurrentRoute() || window.location.pathname;
1191
+ const currentRoute = window.ManifestRoutingNavigation?.getCurrentRoute() ?? window.location.pathname;
1140
1192
 
1141
1193
  // Strip localization codes and other injected segments to get the logical route
1142
1194
  let logicalRoute = currentRoute;
@@ -294,16 +294,11 @@ function ensureTooltipPluginInitialized() {
294
294
 
295
295
  tooltipPluginInitialized = true;
296
296
  initializeTooltipPlugin();
297
-
298
- // If elements with x-tooltip already exist, process them
299
- if (window.Alpine && typeof window.Alpine.initTree === 'function') {
300
- const existingTooltipElements = document.querySelectorAll('[x-tooltip]');
301
- existingTooltipElements.forEach(el => {
302
- if (!el.__x) {
303
- window.Alpine.initTree(el);
304
- }
305
- });
306
- }
297
+ // Do not call Alpine.initTree() on [x-tooltip] elements here. That initializes
298
+ // them in isolation and breaks scope (e.g. "tab is not defined"). Alpine will
299
+ // process the full tree from the root, so [x-tooltip] elements get the correct
300
+ // scope. Dynamically loaded components are already initialized by the component
301
+ // processor with initTree on the swapped-in root.
307
302
  }
308
303
 
309
304
  // Expose on window for loader to call if needed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mnfst",
3
- "version": "0.5.30",
3
+ "version": "0.5.31",
4
4
  "private": false,
5
5
  "workspaces": [
6
6
  "templates/starter"
@@ -19,6 +19,9 @@
19
19
  "start:src": "cd src && browser-sync start --config bs-config.js",
20
20
  "start:docs": "cd docs && browser-sync start --config bs-config.js",
21
21
  "start:starter": "cd templates/starter && browser-sync start --config bs-config.js --port 3001",
22
+ "prerender": "node src/prerender.mjs --root src",
23
+ "prerender:docs": "node src/prerender.mjs --root docs",
24
+ "prerender:starter": "node src/prerender.mjs --root templates/starter",
22
25
  "publish:starter": "cd packages/create-starter && npm publish --auth-type=web",
23
26
  "prepublishOnly": "npm run build",
24
27
  "test": "echo 'No tests configured'",
@@ -30,8 +33,8 @@
30
33
  "@rollup/plugin-terser": "^0.4.4",
31
34
  "browser-sync": "^3.0.3",
32
35
  "cssnano": "^7.1.1",
33
- "fs-extra": "^11.2.0",
34
- "prompts": "^2.4.2",
36
+ "glob": "^11.0.2",
37
+ "puppeteer": "^24.15.0",
35
38
  "rimraf": "^5.0.0",
36
39
  "rollup": "^4.24.2"
37
40
  },
@@ -55,9 +58,5 @@
55
58
  },
56
59
  "bugs": {
57
60
  "url": "https://github.com/andrewmatlock/manifest/issues"
58
- },
59
- "dependencies": {
60
- "commander": "^14.0.1",
61
- "glob": "^11.0.2"
62
61
  }
63
62
  }