smoodly 0.0.50 → 0.0.51

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.
@@ -275,10 +275,13 @@ export function createAdminOps(deps) {
275
275
  effects?.revalidate?.(addressesTag());
276
276
  };
277
277
  /** A collection's list units: every entry write, since a non-versioned collection's published read is its live
278
- * row. An entry write can give an address a document or take it away, so the addresses tag fires with it. */
279
- const expireCollection = (name) => {
278
+ * row. An entry write can give an address a document or take it away, so the addresses tag fires with it —
279
+ * except on a save that changed no slug (`addresses: false`): an autosave of fields moves no address, and a
280
+ * tag that fired per keystroke would re-render every cached miss and code-owned page for nothing. */
281
+ const expireCollection = (name, options = {}) => {
280
282
  effects?.revalidate?.(collectionTag(name));
281
- effects?.revalidate?.(addressesTag());
283
+ if (options.addresses !== false)
284
+ effects?.revalidate?.(addressesTag());
282
285
  };
283
286
  /** A node and every descendant, node first, in listPages() order. */
284
287
  const subtreeIds = async (id) => {
@@ -908,7 +911,7 @@ export function createAdminOps(deps) {
908
911
  if (below.length > 0)
909
912
  await fanOut(below);
910
913
  }
911
- expireCollection(collection);
914
+ expireCollection(collection, { addresses: slugChanged }); // the slug is the address; nothing else in a save moves one
912
915
  return ok(entry);
913
916
  }),
914
917
  setStatus: (collection, id, locale, status, expected) => guard(async () => {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- // The site-route seam (spec 2026-09-05 §5): the two route files call
3
- // renderSmoodlyPath; everything else — request gating, draft mode, 404s,
2
+ // The site-route seam (spec 2026-09-05 §5): the starters' one route file calls
3
+ // renderSmoodlyPath; everything else — the build-only gate, draft mode, 404s,
4
4
  // the editor bridge (through the lazy canvas stub) — lives here, over the
5
5
  // framework-free site layer. The reads are the read layer's units, keyed
6
6
  // by (locale, path, target) and tagged by id (../reads.ts), run by Next's
@@ -112,7 +112,7 @@ export function createPageRenderer(options) {
112
112
  const target = await site.locate(locale, path);
113
113
  // No document to tag: a redirect row, a miss or a code-owned page. Next caches the response like a
114
114
  // page, so it hears the addresses tag (reads.ts missUnit, decision 4).
115
- const tagAddress = () => nextReads.run(missUnit(site, locale, path));
115
+ const tagAddress = () => nextReads.run(missUnit(site));
116
116
  if (target?.redirect) {
117
117
  await tagAddress();
118
118
  await redirectTo(target, locale, params);
@@ -132,7 +132,9 @@ export function createPageRenderer(options) {
132
132
  return (_jsxs(_Fragment, { children: [draft ? _jsx("meta", { name: DRAFT_META_NAME }) : null, editor ? _jsx("style", { "data-smoodly-bridge": "", children: BRIDGE_CSS }) : null, editor ? _jsx(CanvasBridgeSlot, {}) : null, draft && !editor && !version ? previewPill({ route: options.previewRoute }) : null, render(hit, editor, locale)] }));
133
133
  }
134
134
  async function metadata(pathFor, opts, accept) {
135
- // generateMetadata runs alongside the page render, so it gates too.
135
+ // generateMetadata runs alongside the page render, so it gates too. It runs no miss unit: Next renders
136
+ // metadata and page in one work-unit store, so the route entry's tags are the union of both, and no
137
+ // metadata-only render path exists in the App Router (plan 2026-10-09 next cached routes).
136
138
  await buildGate();
137
139
  const locale = opts?.locale ?? site.locales.default;
138
140
  const path = pathFor(locale);
package/dist/reads.d.ts CHANGED
@@ -60,8 +60,9 @@ export declare function hitUnit(site: SmoodlySite, target: PathTarget, locale: s
60
60
  /** An address with no document to tag — a miss, a redirect row or a code-owned page. The unit reads
61
61
  * nothing: it exists so a cached response hears the `addresses` tag, which every address-changing
62
62
  * operation fires (revalidate.ts). Next runs it (its route cache stores a 404 like a page); Astro never
63
- * caches such a response and does not call it. */
64
- export declare function missUnit(site: SmoodlySite, locale: string, path: string): ReadUnit<null>;
63
+ * caches such a response and does not call it. One key for every address: the tag reaches the route
64
+ * entry before the lookup, so a per-address key would only write one data-cache row per scanned 404. */
65
+ export declare function missUnit(site: SmoodlySite): ReadUnit<null>;
65
66
  /** Astro's route read of an address: one lookup outside draft mode — the tags come with the document, so no
66
67
  * locate comes first; in draft mode, locate then load as the editing tables need (spec 2026-10-07 delivery
67
68
  * model §3). A redirect row answers as a redirect; a code-owned page answers where no record lives. */
package/dist/reads.js CHANGED
@@ -31,9 +31,10 @@ export function hitUnit(site, target, locale, path, version) {
31
31
  /** An address with no document to tag — a miss, a redirect row or a code-owned page. The unit reads
32
32
  * nothing: it exists so a cached response hears the `addresses` tag, which every address-changing
33
33
  * operation fires (revalidate.ts). Next runs it (its route cache stores a 404 like a page); Astro never
34
- * caches such a response and does not call it. */
35
- export function missUnit(site, locale, path) {
36
- return { key: ["smoodly-miss", site.cacheKey, locale, path], tags: [addressesTag()], read: async () => null };
34
+ * caches such a response and does not call it. One key for every address: the tag reaches the route
35
+ * entry before the lookup, so a per-address key would only write one data-cache row per scanned 404. */
36
+ export function missUnit(site) {
37
+ return { key: ["smoodly-miss", site.cacheKey], tags: [addressesTag()], read: async () => null };
37
38
  }
38
39
  /** Astro's route read of an address: one lookup outside draft mode — the tags come with the document, so no
39
40
  * locate comes first; in draft mode, locate then load as the editing tables need (spec 2026-10-07 delivery
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const SMOODLY_VERSION = "0.0.50";
1
+ export declare const SMOODLY_VERSION = "0.0.51";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by scripts/write-version.mjs from package.json — do not edit.
2
- export const SMOODLY_VERSION = "0.0.50";
2
+ export const SMOODLY_VERSION = "0.0.51";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smoodly",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "Open-source, code-first CMS for Astro and Next.js on Supabase: define a component once, it becomes a typed, editable building block.",
5
5
  "license": "MIT",
6
6
  "repository": {