nebula-cms 0.1.4 → 0.1.5

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 CHANGED
@@ -56,7 +56,7 @@ import NebulaCMS from 'nebula-cms/client';
56
56
  <title>Nebula CMS</title>
57
57
  </head>
58
58
  <body>
59
- <NebulaCMS client:only="svelte" />
59
+ <NebulaCMS client:load />
60
60
  </body>
61
61
  </html>
62
62
  ```
@@ -113,25 +113,34 @@
113
113
  /*
114
114
  * Loads content for the file or draft view. Both branches gate on `backend.ready`
115
115
  * so they re-run when the directory handle is restored on page load.
116
+ * Route is captured as a const so TS can narrow the discriminated union
117
+ * through `view` checks — the getter re-access pattern defeats narrowing.
116
118
  */
117
119
  $effect(() => {
118
- if (backend.ready && nav.route.view === 'file' && content.list.length > 0) {
120
+ const currentRoute = nav.route;
121
+ if (
122
+ backend.ready &&
123
+ currentRoute.view === 'file' &&
124
+ content.list.length > 0
125
+ ) {
119
126
  const item = content.list.find(
120
- (i) => stripExtension(i.filename) === nav.route.slug,
127
+ (i) => stripExtension(i.filename) === currentRoute.slug,
121
128
  );
122
129
  if (!item) return;
123
130
 
124
131
  // preloadFile is async — it checks IDB for a draft first
125
- preloadFile(nav.route.collection, item.filename, item.data).then(() => {
126
- // If preloadFile loaded a draft (body already present), skip disk read
127
- const editorFile = getEditorFile();
128
- if (editorFile?.draftId) return;
132
+ preloadFile(currentRoute.collection, item.filename, item.data).then(
133
+ () => {
134
+ // If preloadFile loaded a draft (body already present), skip disk read
135
+ const editorFile = getEditorFile();
136
+ if (editorFile?.draftId) return;
129
137
 
130
- loadFileBody(nav.route.collection, item.filename);
131
- });
132
- } else if (backend.ready && nav.route.view === 'draft') {
133
- loadDraftById(nav.route.draftId, nav.route.collection);
134
- } else if (nav.route.view !== 'file' && nav.route.view !== 'draft') {
138
+ loadFileBody(currentRoute.collection, item.filename);
139
+ },
140
+ );
141
+ } else if (backend.ready && currentRoute.view === 'draft') {
142
+ loadDraftById(currentRoute.draftId, currentRoute.collection);
143
+ } else if (currentRoute.view !== 'file' && currentRoute.view !== 'draft') {
135
144
  clearEditor();
136
145
  }
137
146
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Admin.svelte.d.ts","sourceRoot":"","sources":["../../src/client/Admin.svelte.ts"],"names":[],"mappings":"AAuCA,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,eAAe,CAAC;AACvB,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AAiNxB,QAAA,MAAM,KAAK,2DAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Admin.svelte.d.ts","sourceRoot":"","sources":["../../src/client/Admin.svelte.ts"],"names":[],"mappings":"AAuCA,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,iBAAiB,CAAC;AACzB,OAAO,eAAe,CAAC;AACvB,OAAO,uBAAuB,CAAC;AAC/B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AA0NxB,QAAA,MAAM,KAAK,2DAAwC,CAAC;AACpD,KAAK,KAAK,GAAG,UAAU,CAAC,OAAO,KAAK,CAAC,CAAC;AACtC,eAAe,KAAK,CAAC"}
@@ -20,8 +20,7 @@
20
20
  // The dialog element ref for imperative showModal/close
21
21
  let dialogEl = $state<HTMLDialogElement | null>(null);
22
22
 
23
- // The slug input value, initialized from slugified title
24
- let slug = $state(slugify(title));
23
+ let slug = $derived(slugify(title));
25
24
 
26
25
  // Validation error message
27
26
  const error = $derived.by(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"FilenameDialog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/components/dialogs/FilenameDialog.svelte.ts"],"names":[],"mappings":"AAME;;GAEG;AACH,UAAU,KAAK;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAE5B,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEtC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAoEH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"FilenameDialog.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/components/dialogs/FilenameDialog.svelte.ts"],"names":[],"mappings":"AAME;;GAEG;AACH,UAAU,KAAK;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAE5B,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAEtC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAmEH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -54,10 +54,8 @@
54
54
  // Search query for filtering items by label
55
55
  let searchQuery = $state('');
56
56
 
57
- // Current sort mode, initialized from localStorage if storageKey is provided
58
- let sortMode = $state<SortMode>(
59
- storageKey ? readSortMode(storageKey) : 'alpha',
60
- );
57
+ // Current sort mode the $effect below sets the correct value reactively
58
+ let sortMode = $state<SortMode>('alpha');
61
59
 
62
60
  // Re-read sort mode when storageKey changes (switching collections)
63
61
  $effect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"AdminSidebar.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/components/sidebar/AdminSidebar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,WAAW,EAIjB,MAAM,qBAAqB,CAAC;AAU7B,UAAU,KAAK;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,KAAK,EAAE,WAAW,EAAE,CAAC;IAErB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAwJH,QAAA,MAAM,YAAY;iBADuD,OAAO,WAAW;MACjC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"AdminSidebar.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/components/sidebar/AdminSidebar.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EACH,KAAK,WAAW,EAIjB,MAAM,qBAAqB,CAAC;AAU7B,UAAU,KAAK;IAEb,KAAK,EAAE,MAAM,CAAC;IAEd,KAAK,EAAE,WAAW,EAAE,CAAC;IAErB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAsJH,QAAA,MAAM,YAAY;iBADuD,OAAO,WAAW;MACjC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"router.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/js/state/router.svelte.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAQ3D,eAAO,MAAM,GAAG;oBAED,UAAU;CAGxB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAIvD;AAgDD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3C;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAEjE;AAKD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAwCjC"}
1
+ {"version":3,"file":"router.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/js/state/router.svelte.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAgB3D,eAAO,MAAM,GAAG;oBAED,UAAU;CAGxB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAIvD;AAgDD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3C;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAEjE;AAKD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAwCjC"}
@@ -6,8 +6,14 @@
6
6
  import config from 'virtual:nebula/config';
7
7
  // Build-time constant — configured via the Astro integration
8
8
  const basePath = config.basePath;
9
- // Current route, reactive via Svelte 5 runes
10
- let route = $state(parsePathname(location.pathname));
9
+ /*
10
+ * Current route, reactive via Svelte 5 runes.
11
+ * Defaults to 'home' during SSR where location is unavailable;
12
+ * the client re-initializes from the real pathname on hydration.
13
+ */
14
+ let route = $state(typeof location !== 'undefined'
15
+ ? parsePathname(location.pathname)
16
+ : { view: 'home' });
11
17
  export const nav = {
12
18
  // Current parsed admin route.
13
19
  get route() {
@@ -122,7 +128,7 @@ export function initRouter() {
122
128
  return;
123
129
  }
124
130
  event.intercept({
125
- handler() {
131
+ async handler() {
126
132
  route = parsePathname(url.pathname);
127
133
  },
128
134
  });
@@ -1 +1 @@
1
- {"version":3,"file":"state.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/js/state/state.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EACL,MAAM,EAEN,aAAa,EAEd,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAGjC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAGF,KAAK,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvD,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;AAE3C,eAAO,MAAM,WAAW,UAA8B,CAAC;AAUvD,eAAO,MAAM,aAAa,eAAuC,CAAC;AAQlE,eAAO,MAAM,OAAO;mBAEN,WAAW;oBAIV,OAAO;yBAIF,eAAe;CAGlC,CAAC;AAEF,eAAO,MAAM,OAAO;mBAEN,WAAW,EAAE;sBAIV,OAAO;oBAIT,MAAM,GAAG,IAAI;CAG3B,CAAC;AAoEF;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA6CpD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAcvD;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAehD;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAYvD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAGzD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAMN"}
1
+ {"version":3,"file":"state.svelte.d.ts","sourceRoot":"","sources":["../../../../src/client/js/state/state.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,EACL,MAAM,EAEN,aAAa,EAEd,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AAGjC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAAC;AAGF,KAAK,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvD,KAAK,WAAW,GAAG,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC;AAE3C,eAAO,MAAM,WAAW,UAA8B,CAAC;AAoBvD,eAAO,MAAM,aAAa,EAErB,aAAa,CAAC;AAQnB,eAAO,MAAM,OAAO;mBAEN,WAAW;oBAIV,OAAO;yBAIF,eAAe;CAGlC,CAAC;AAEF,eAAO,MAAM,OAAO;mBAEN,WAAW,EAAE;sBAIV,OAAO;oBAIT,MAAM,GAAG,IAAI;CAG3B,CAAC;AAoEF;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CA6CpD;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAcvD;AAED;;;GAGG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAOf;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAehD;AAYD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAYvD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAGzD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAMN"}
@@ -14,10 +14,19 @@ export const collections = Object.keys(schemas).sort();
14
14
  /*
15
15
  * Uses .js extension because svelte-package does not rewrite URL string literals;
16
16
  * the dist output must reference the compiled .js file, not the source .ts file.
17
+ *
18
+ * Guarded for SSR: SharedWorker only exists in browsers. All code paths
19
+ * that use sharedWorker/storageClient run exclusively on the client
20
+ * (inside onMount, event handlers, or user-initiated actions).
17
21
  */
18
- const sharedWorker = new SharedWorker(new URL('../storage/workers/storage.js', import.meta.url), { type: 'module', name: 'cms-storage' });
19
- // Main-thread StorageClient for editor and draft-merge I/O.
20
- export const storageClient = new StorageClient(sharedWorker.port);
22
+ const sharedWorker = typeof SharedWorker !== 'undefined'
23
+ ? new SharedWorker(new URL('../storage/workers/storage.js', import.meta.url), { type: 'module', name: 'cms-storage' })
24
+ : null;
25
+ /*
26
+ * Main-thread StorageClient for editor and draft-merge I/O.
27
+ * Null during SSR but typed as non-null because every caller is client-only.
28
+ */
29
+ export const storageClient = (sharedWorker ? new StorageClient(sharedWorker.port) : null);
21
30
  let backendType = $state(null);
22
31
  let backendReady = $state(false);
23
32
  let permissionState = $state('denied');
@@ -0,0 +1,39 @@
1
+ /*
2
+ * Type augmentations for browser APIs not fully covered by installed @types packages.
3
+ * The side-effect import makes this a module file so `declare global` adds to the
4
+ * global scope and `declare module` augments (rather than redeclares) the target.
5
+ */
6
+
7
+ import 'svelte/elements';
8
+
9
+ /*
10
+ //////////////////////////////
11
+ // Navigation API
12
+ //////////////////////////////
13
+ */
14
+
15
+ /*
16
+ * @types/dom-navigation provides the Navigation class and augments Window,
17
+ * but omits the global variable declaration that lets code use bare
18
+ * `navigation` (like bare `document` or `location`).
19
+ */
20
+ declare global {
21
+ var navigation: Navigation;
22
+ }
23
+
24
+ /*
25
+ //////////////////////////////
26
+ // Interest Invokers API
27
+ //////////////////////////////
28
+ */
29
+
30
+ /*
31
+ * No @types package exists for this spec.
32
+ * See: https://open-ui.org/components/interest-invokers.explainer/
33
+ */
34
+ declare module 'svelte/elements' {
35
+ // Extends all HTML elements with the interestfor attribute
36
+ interface HTMLAttributes<T> {
37
+ interestfor?: string;
38
+ }
39
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nebula-cms",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "A native CMS for Astro",
5
5
  "type": "module",
6
6
  "repository": {
@@ -56,7 +56,11 @@
56
56
  "@sveltejs/package": "^2.5.7",
57
57
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
58
58
  "@testing-library/svelte": "^5.3.1",
59
- "vitest": "^4.1.2",
59
+ "@types/dom-navigation": "^1.0.7",
60
+ "@types/js-yaml": "^4.0.9",
61
+ "@types/node": "^25.5.2",
62
+ "@types/sharedworker": "^0.0.223",
63
+ "@types/wicg-file-system-access": "^2023.10.7",
60
64
  "@vitest/browser": "^4.1.2",
61
65
  "@vitest/browser-playwright": "^4.1.2",
62
66
  "@vitest/coverage-v8": "^4.1.2",
@@ -68,12 +72,15 @@
68
72
  "prettier-plugin-astro": "^0.14.1",
69
73
  "prettier-plugin-svelte": "^3.5.1",
70
74
  "svelte": "^5.54.1",
71
- "typescript": "^5.9.3"
75
+ "svelte-check": "^4.4.6",
76
+ "typescript": "^5.9.3",
77
+ "vitest": "^4.1.2"
72
78
  },
73
79
  "scripts": {
74
80
  "prebuild": "node scripts/subset-icons.mjs",
75
81
  "build": "svelte-package --input src --output dist",
76
82
  "lint": "prettier -c .",
83
+ "check": "svelte-check",
77
84
  "fix": "prettier --write .",
78
85
  "test": "vitest run",
79
86
  "test:continuous": "vitest"