@yysng/astro-boilerplate 1.1.4 → 1.1.6

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/package.json CHANGED
@@ -1,18 +1,23 @@
1
1
  {
2
2
  "name": "@yysng/astro-boilerplate",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Astro + Sanity Boilerplate with AEO Layers 1–5",
5
5
  "type": "module",
6
6
  "exports": {
7
- ".": "./src/index.js"
7
+ ".": "./src/index.js",
8
+ "./components/*": "./src/components/*",
9
+ "./layouts/*": "./src/layouts/*",
10
+ "./styles/*": "./src/styles/*",
11
+ "./lib/*": "./src/lib/*",
12
+ "./utils/*": "./src/utils/*"
8
13
  },
9
14
  "main": "./src/index.js",
10
15
  "files": [
11
16
  "src"
12
17
  ],
13
18
  "peerDependencies": {
19
+ "@portabletext/to-html": "^4.0.1",
14
20
  "astro": "^5.0.0",
15
- "sanity": "^4.0.0",
16
- "@portabletext/to-html": "^4.0.1"
21
+ "sanity": "^4.0.0"
17
22
  }
18
23
  }
@@ -24,7 +24,9 @@ const {
24
24
  jsonld = null, // page-level schemas
25
25
  extraJson = [], // FAQPage, ItemList, etc.
26
26
  breadcrumbs = null, // BreadcrumbList (JSON-LD)
27
- geo = null // { placename, region, latitude, longitude }
27
+ geo = null, // { placename, region, latitude, longitude }
28
+
29
+ gtmId = null, // ✅ ADD THIS
28
30
  } = Astro.props;
29
31
 
30
32
  /* ------------------------------------------------------------
@@ -180,4 +182,15 @@ graph = graph.filter((item, idx, arr) => {
180
182
  })}
181
183
  ></script>
182
184
  )}
185
+
186
+ {gtmId && (
187
+ <script>
188
+ {`(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
189
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
190
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
191
+ 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
192
+ })(window,document,'script','dataLayer','${gtmId}');`}
193
+ </script>
194
+ )}
195
+
183
196
  </head>
@@ -13,6 +13,6 @@ export const CONTENT_REGISTRY = {
13
13
  },
14
14
  testimonials: {
15
15
  file: "testimonials.json",
16
- section: "TertimonialSection"
16
+ section: "TestimonialSection"
17
17
  }
18
18
  };
@@ -4,14 +4,83 @@ import { CONTENT_REGISTRY } from "./registry.js";
4
4
  import { schemas } from "./schemas.js";
5
5
  import { getContentRoot } from "./config.js";
6
6
 
7
- export async function updateContent(key, data) {
7
+
8
+ function logAuditEvent({ section, incoming, merged }) {
9
+ const timestamp = new Date().toISOString();
10
+
11
+ console.log("[AI-EDIT]", {
12
+ section,
13
+ timestamp,
14
+ incoming, // what AI attempted to change
15
+ result: merged // final persisted state
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Merge only defined values from `incoming` into `existing`.
21
+ * - Undefined fields do NOT overwrite existing values
22
+ * - Nested objects (e.g. CTA) are merged recursively
23
+ */
24
+ function mergeDefined(existing, incoming) {
25
+ const result = { ...existing };
26
+
27
+ for (const key of Object.keys(incoming)) {
28
+ const value = incoming[key];
29
+
30
+ // Skip undefined (true partial update behavior)
31
+ if (value === undefined) continue;
32
+
33
+ // Recursively merge objects (but not arrays)
34
+ if (
35
+ typeof value === "object" &&
36
+ value !== null &&
37
+ !Array.isArray(value)
38
+ ) {
39
+ result[key] = mergeDefined(existing[key] || {}, value);
40
+ } else {
41
+ result[key] = value;
42
+ }
43
+ }
44
+
45
+ return result;
46
+ }
47
+
48
+ export async function updateContent(key, incoming) {
49
+ if (!incoming || typeof incoming !== "object") {
50
+ throw new Error("Incoming content must be an object");
51
+ }
52
+
8
53
  const entry = CONTENT_REGISTRY[key];
9
- if (!entry) throw new Error(`Unknown content key: ${key}`);
54
+ if (!entry) {
55
+ throw new Error(`Unknown content key: ${key}`);
56
+ }
10
57
 
11
58
  const schema = schemas[key];
12
- if (!schema) throw new Error(`No schema for ${key}`);
13
- schema.validate(data);
59
+ if (!schema) {
60
+ throw new Error(`No schema defined for content key: ${key}`);
61
+ }
14
62
 
15
63
  const filePath = path.join(getContentRoot(), entry.file);
16
- await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
64
+
65
+ let existing = {};
66
+ try {
67
+ const raw = await fs.readFile(filePath, "utf-8");
68
+ existing = JSON.parse(raw);
69
+ } catch {}
70
+
71
+ const merged = mergeDefined(existing, incoming);
72
+
73
+ schema.validate(merged);
74
+
75
+ logAuditEvent({
76
+ section: key,
77
+ incoming,
78
+ merged
79
+ });
80
+
81
+ await fs.writeFile(
82
+ filePath,
83
+ JSON.stringify(merged, null, 2),
84
+ "utf-8"
85
+ );
17
86
  }