@dualmark/astro 0.2.0

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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/dist/endpoints/collection.cjs +24 -0
  4. package/dist/endpoints/collection.cjs.map +1 -0
  5. package/dist/endpoints/collection.d.cts +27 -0
  6. package/dist/endpoints/collection.d.ts +27 -0
  7. package/dist/endpoints/collection.js +22 -0
  8. package/dist/endpoints/collection.js.map +1 -0
  9. package/dist/endpoints/listing.cjs +34 -0
  10. package/dist/endpoints/listing.cjs.map +1 -0
  11. package/dist/endpoints/listing.d.cts +20 -0
  12. package/dist/endpoints/listing.d.ts +20 -0
  13. package/dist/endpoints/listing.js +32 -0
  14. package/dist/endpoints/listing.js.map +1 -0
  15. package/dist/endpoints/llms-txt.cjs +23 -0
  16. package/dist/endpoints/llms-txt.cjs.map +1 -0
  17. package/dist/endpoints/llms-txt.d.cts +12 -0
  18. package/dist/endpoints/llms-txt.d.ts +12 -0
  19. package/dist/endpoints/llms-txt.js +21 -0
  20. package/dist/endpoints/llms-txt.js.map +1 -0
  21. package/dist/endpoints/parameterized.cjs +18 -0
  22. package/dist/endpoints/parameterized.cjs.map +1 -0
  23. package/dist/endpoints/parameterized.d.cts +25 -0
  24. package/dist/endpoints/parameterized.d.ts +25 -0
  25. package/dist/endpoints/parameterized.js +16 -0
  26. package/dist/endpoints/parameterized.js.map +1 -0
  27. package/dist/endpoints/static.cjs +17 -0
  28. package/dist/endpoints/static.cjs.map +1 -0
  29. package/dist/endpoints/static.d.cts +11 -0
  30. package/dist/endpoints/static.d.ts +11 -0
  31. package/dist/endpoints/static.js +15 -0
  32. package/dist/endpoints/static.js.map +1 -0
  33. package/dist/index.cjs +316 -0
  34. package/dist/index.cjs.map +1 -0
  35. package/dist/index.d.cts +54 -0
  36. package/dist/index.d.ts +54 -0
  37. package/dist/index.js +307 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/middleware.cjs +22 -0
  40. package/dist/middleware.cjs.map +1 -0
  41. package/dist/middleware.d.cts +9 -0
  42. package/dist/middleware.d.ts +9 -0
  43. package/dist/middleware.js +19 -0
  44. package/dist/middleware.js.map +1 -0
  45. package/dist/types-BPk2cf2p.d.cts +64 -0
  46. package/dist/types-BPk2cf2p.d.ts +64 -0
  47. package/dist/virtual.cjs +10 -0
  48. package/dist/virtual.cjs.map +1 -0
  49. package/dist/virtual.d.cts +7 -0
  50. package/dist/virtual.d.ts +7 -0
  51. package/dist/virtual.js +8 -0
  52. package/dist/virtual.js.map +1 -0
  53. package/package.json +102 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,316 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var fs = require('fs');
6
+ var url = require('url');
7
+ var path = require('path');
8
+ var converters = require('@dualmark/converters');
9
+
10
+ // src/integration.ts
11
+
12
+ // src/config-validation.ts
13
+ var DualmarkConfigError = class extends Error {
14
+ constructor(message) {
15
+ super(message);
16
+ this.name = "DualmarkConfigError";
17
+ }
18
+ };
19
+ function resolveConfig(input) {
20
+ if (!input || typeof input !== "object") {
21
+ throw new DualmarkConfigError("Dualmark config must be an object");
22
+ }
23
+ if (typeof input.siteUrl !== "string" || !input.siteUrl) {
24
+ throw new DualmarkConfigError("Dualmark config: siteUrl is required (e.g. 'https://example.com')");
25
+ }
26
+ try {
27
+ new URL(input.siteUrl);
28
+ } catch {
29
+ throw new DualmarkConfigError(`Dualmark config: siteUrl is not a valid URL: ${input.siteUrl}`);
30
+ }
31
+ if (input.siteUrl.endsWith("/")) {
32
+ throw new DualmarkConfigError(`Dualmark config: siteUrl must not end with '/': ${input.siteUrl}`);
33
+ }
34
+ const collections = input.collections ?? {};
35
+ for (const [name, c] of Object.entries(collections)) {
36
+ if (!c.converter) {
37
+ throw new DualmarkConfigError(`Dualmark config: collection '${name}' is missing 'converter'`);
38
+ }
39
+ if (c.route && c.route.startsWith("/")) {
40
+ throw new DualmarkConfigError(
41
+ `Dualmark config: collection '${name}' route should not start with '/' (got '${c.route}')`
42
+ );
43
+ }
44
+ }
45
+ const staticPages = input.staticPages ?? [];
46
+ for (const sp of staticPages) {
47
+ if (!sp.pattern.startsWith("/")) {
48
+ throw new DualmarkConfigError(
49
+ `Dualmark config: staticPages.pattern must start with '/' (got '${sp.pattern}')`
50
+ );
51
+ }
52
+ if (typeof sp.render !== "function") {
53
+ throw new DualmarkConfigError(
54
+ `Dualmark config: staticPages.render for '${sp.pattern}' must be a function`
55
+ );
56
+ }
57
+ }
58
+ const parameterizedRoutes = input.parameterizedRoutes ?? [];
59
+ for (const pr of parameterizedRoutes) {
60
+ if (!pr.pattern.includes("[")) {
61
+ throw new DualmarkConfigError(
62
+ `Dualmark config: parameterizedRoutes.pattern must contain at least one [param] (got '${pr.pattern}')`
63
+ );
64
+ }
65
+ }
66
+ return {
67
+ siteUrl: input.siteUrl,
68
+ collections,
69
+ staticPages,
70
+ parameterizedRoutes,
71
+ llmsTxt: input.llmsTxt,
72
+ middleware: {
73
+ injectLinkHeader: input.middleware?.injectLinkHeader !== false
74
+ },
75
+ headers: {
76
+ cacheControl: input.headers?.cacheControl ?? "public, max-age=3600",
77
+ noindex: input.headers?.noindex !== false
78
+ }
79
+ };
80
+ }
81
+
82
+ // src/integration.ts
83
+ var GENERATED_DIR_NAME = ".dualmark-generated";
84
+ function rel(from, to) {
85
+ const r = path.relative(from, to);
86
+ return r.split(path.sep).join("/");
87
+ }
88
+ function createDualmarkIntegration(input) {
89
+ let resolved;
90
+ try {
91
+ resolved = resolveConfig(input);
92
+ } catch (e) {
93
+ if (e instanceof DualmarkConfigError) throw e;
94
+ throw e;
95
+ }
96
+ return {
97
+ name: "@dualmark/astro",
98
+ hooks: {
99
+ "astro:config:setup"(opts) {
100
+ const root = url.fileURLToPath(opts.config.root);
101
+ const generatedDir = path.join(root, "node_modules", GENERATED_DIR_NAME);
102
+ if (!fs.existsSync(generatedDir)) fs.mkdirSync(generatedDir, { recursive: true });
103
+ fs.writeFileSync(
104
+ path.join(generatedDir, "config.mjs"),
105
+ `export default ${JSON.stringify(
106
+ {
107
+ siteUrl: resolved.siteUrl,
108
+ cacheControl: resolved.headers.cacheControl,
109
+ noindex: resolved.headers.noindex
110
+ },
111
+ null,
112
+ 2
113
+ )};
114
+ `,
115
+ "utf8"
116
+ );
117
+ const routes = [];
118
+ for (const [collectionName, c] of Object.entries(resolved.collections)) {
119
+ const route = c.route ?? collectionName;
120
+ const slugSeg = c.slugStrategy === "single" ? "[slug]" : "[...slug]";
121
+ const detailPattern = `/${route}/${slugSeg}.md`;
122
+ const listingPattern = `/${route}.md`;
123
+ if (typeof c.converter !== "string") {
124
+ opts.logger.warn(
125
+ `[@dualmark/astro] Collection '${collectionName}' uses an inline converter function \u2014 this isn't yet serializable into a generated route. Use a built-in converter name (e.g. 'blog') for now.`
126
+ );
127
+ continue;
128
+ }
129
+ const converterImport = `import { resolveBuiltInConverter } from "@dualmark/astro";`;
130
+ const detailSource = `${converterImport}
131
+ import { makeCollectionDetailEndpoint } from "@dualmark/astro/endpoints/collection";
132
+ import { getCollection } from "astro:content";
133
+ import dualmarkConfig from "./config.mjs";
134
+
135
+ const converter = resolveBuiltInConverter({
136
+ name: ${JSON.stringify(c.converter)},
137
+ collectionName: ${JSON.stringify(collectionName)},
138
+ baseConfig: { siteUrl: dualmarkConfig.siteUrl },
139
+ });
140
+
141
+ const endpoint = makeCollectionDetailEndpoint({
142
+ collectionName: ${JSON.stringify(collectionName)},
143
+ converter,
144
+ getCollection: (name, filter) => getCollection(name, filter),
145
+ responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },
146
+ });
147
+
148
+ export const getStaticPaths = endpoint.getStaticPaths;
149
+ export const GET = endpoint.GET;
150
+ `;
151
+ const listingSource = `import { makeListingEndpoint } from "@dualmark/astro/endpoints/listing";
152
+ import { getCollection } from "astro:content";
153
+ import dualmarkConfig from "./config.mjs";
154
+
155
+ const endpoint = makeListingEndpoint({
156
+ collectionName: ${JSON.stringify(collectionName)},
157
+ siteUrl: dualmarkConfig.siteUrl,
158
+ basePath: ${JSON.stringify("/" + route)},
159
+ title: ${JSON.stringify(c.listingMetadata?.title ?? collectionName)},
160
+ description: ${JSON.stringify(c.listingMetadata?.description ?? `All ${collectionName} entries.`)},
161
+ getCollection: (name, filter) => getCollection(name, filter),
162
+ responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },
163
+ });
164
+
165
+ export const GET = endpoint.GET;
166
+ `;
167
+ routes.push(
168
+ { pattern: detailPattern, fileName: `collection-${collectionName}-detail.mjs`, source: detailSource }
169
+ );
170
+ if (c.emitListing !== false) {
171
+ routes.push({
172
+ pattern: listingPattern,
173
+ fileName: `collection-${collectionName}-listing.mjs`,
174
+ source: listingSource
175
+ });
176
+ }
177
+ }
178
+ for (let i = 0; i < resolved.staticPages.length; i++) {
179
+ const sp = resolved.staticPages[i];
180
+ if (!sp) continue;
181
+ const safe = sp.pattern.replace(/[^a-z0-9]/gi, "_");
182
+ const fileName = `static-${i}-${safe}.mjs`;
183
+ const renderModulePath = path.join(generatedDir, `static-${i}-${safe}-render.mjs`);
184
+ fs.writeFileSync(
185
+ renderModulePath,
186
+ `export default ${sp.render.toString()};
187
+ `,
188
+ "utf8"
189
+ );
190
+ const source = `import { makeStaticEndpoint } from "@dualmark/astro/endpoints/static";
191
+ import dualmarkConfig from "./config.mjs";
192
+ import render from "./${rel(generatedDir, renderModulePath)}";
193
+
194
+ const endpoint = makeStaticEndpoint({
195
+ render,
196
+ responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },
197
+ });
198
+
199
+ export const GET = endpoint.GET;
200
+ `;
201
+ const mdPattern = sp.pattern === "/" ? "/index.md" : sp.pattern.replace(/\/$/, "") + ".md";
202
+ routes.push({ pattern: mdPattern, fileName, source });
203
+ }
204
+ for (let i = 0; i < resolved.parameterizedRoutes.length; i++) {
205
+ const pr = resolved.parameterizedRoutes[i];
206
+ if (!pr) continue;
207
+ const safe = pr.pattern.replace(/[^a-z0-9]/gi, "_");
208
+ const renderModulePath = path.join(generatedDir, `param-${i}-${safe}-render.mjs`);
209
+ const pathsModulePath = path.join(generatedDir, `param-${i}-${safe}-paths.mjs`);
210
+ fs.writeFileSync(renderModulePath, `export default ${pr.render.toString()};
211
+ `, "utf8");
212
+ fs.writeFileSync(pathsModulePath, `export default ${pr.getStaticPaths.toString()};
213
+ `, "utf8");
214
+ const source = `import { makeParameterizedEndpoint } from "@dualmark/astro/endpoints/parameterized";
215
+ import dualmarkConfig from "./config.mjs";
216
+ import render from "./${rel(generatedDir, renderModulePath)}";
217
+ import getStaticPaths from "./${rel(generatedDir, pathsModulePath)}";
218
+
219
+ const endpoint = makeParameterizedEndpoint({
220
+ getStaticPaths: () => getStaticPaths(),
221
+ render,
222
+ responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },
223
+ });
224
+
225
+ export const getStaticPaths = endpoint.getStaticPaths;
226
+ export const GET = endpoint.GET;
227
+ `;
228
+ const pattern = pr.pattern.startsWith("/") ? pr.pattern + ".md" : `/${pr.pattern}.md`;
229
+ routes.push({
230
+ pattern,
231
+ fileName: `param-${i}-${safe}.mjs`,
232
+ source
233
+ });
234
+ }
235
+ if (resolved.llmsTxt?.enabled) {
236
+ const sections = resolved.llmsTxt.sections ?? [];
237
+ const source = `import { makeLlmsTxtEndpoint } from "@dualmark/astro/endpoints/llms-txt";
238
+
239
+ const endpoint = makeLlmsTxtEndpoint({
240
+ brandName: ${JSON.stringify(resolved.llmsTxt.brandName ?? "Site")},
241
+ description: ${JSON.stringify(resolved.llmsTxt.description ?? "")},
242
+ sections: ${JSON.stringify(sections)},
243
+ });
244
+
245
+ export const GET = endpoint.GET;
246
+ `;
247
+ routes.push({ pattern: "/llms.txt", fileName: `llms-txt.mjs`, source });
248
+ }
249
+ for (const r of routes) {
250
+ const filePath = path.join(generatedDir, r.fileName);
251
+ fs.writeFileSync(filePath, r.source, "utf8");
252
+ opts.injectRoute({
253
+ pattern: r.pattern,
254
+ entrypoint: filePath,
255
+ prerender: true
256
+ });
257
+ }
258
+ if (resolved.middleware.injectLinkHeader && opts.addMiddleware) {
259
+ opts.addMiddleware({
260
+ order: "post",
261
+ entrypoint: "@dualmark/astro/middleware"
262
+ });
263
+ }
264
+ opts.logger.info(
265
+ `[@dualmark/astro] Injected ${routes.length} route(s) and ${resolved.middleware.injectLinkHeader ? "1" : "0"} middleware`
266
+ );
267
+ }
268
+ }
269
+ };
270
+ }
271
+ function dualmarkAstro(config) {
272
+ return createDualmarkIntegration(config);
273
+ }
274
+ function resolveBuiltInConverter(args) {
275
+ const basePath = `/${args.collectionName}`;
276
+ const cfg = { ...args.baseConfig, basePath };
277
+ switch (args.name) {
278
+ case "blog":
279
+ return converters.blogConverter(cfg);
280
+ case "case-study":
281
+ return converters.caseStudyConverter(cfg);
282
+ case "changelog":
283
+ return converters.changelogConverter(cfg);
284
+ case "compare":
285
+ return converters.compareConverter({ ...cfg, ourBrandColumn: "Us" });
286
+ case "docs":
287
+ return converters.docsConverter(cfg);
288
+ case "feature":
289
+ return converters.featureConverter(cfg);
290
+ case "glossary":
291
+ return converters.glossaryConverter(cfg);
292
+ case "legal":
293
+ return converters.legalConverter(cfg);
294
+ case "pricing":
295
+ return converters.pricingConverter(cfg);
296
+ case "pseo":
297
+ return converters.pseoConverter(cfg);
298
+ case "tool":
299
+ return converters.toolConverter(cfg);
300
+ case "video":
301
+ return converters.videoConverter(cfg);
302
+ default:
303
+ throw new Error(
304
+ `Dualmark: unknown built-in converter '${args.name}'. Valid names: blog, case-study, changelog, compare, docs, feature, glossary, legal, pricing, pseo, tool, video. Or pass a function.`
305
+ );
306
+ }
307
+ }
308
+
309
+ exports.DualmarkConfigError = DualmarkConfigError;
310
+ exports.createDualmarkIntegration = createDualmarkIntegration;
311
+ exports.default = dualmarkAstro;
312
+ exports.dualmark = dualmarkAstro;
313
+ exports.resolveBuiltInConverter = resolveBuiltInConverter;
314
+ exports.resolveConfig = resolveConfig;
315
+ //# sourceMappingURL=index.cjs.map
316
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config-validation.ts","../src/integration.ts","../src/converter-registry.ts"],"names":["relative","sep","fileURLToPath","join","existsSync","writeFileSync","blogConverter","caseStudyConverter","changelogConverter","compareConverter","docsConverter","featureConverter","glossaryConverter","legalConverter","pricingConverter","pseoConverter","toolConverter","videoConverter"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { DualmarkAstroConfig, ResolvedDualmarkConfig } from \"./types.js\";\n\nexport class DualmarkConfigError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DualmarkConfigError\";\n }\n}\n\nexport function resolveConfig(input: DualmarkAstroConfig): ResolvedDualmarkConfig {\n if (!input || typeof input !== \"object\") {\n throw new DualmarkConfigError(\"Dualmark config must be an object\");\n }\n if (typeof input.siteUrl !== \"string\" || !input.siteUrl) {\n throw new DualmarkConfigError(\"Dualmark config: siteUrl is required (e.g. 'https://example.com')\");\n }\n try {\n new URL(input.siteUrl);\n } catch {\n throw new DualmarkConfigError(`Dualmark config: siteUrl is not a valid URL: ${input.siteUrl}`);\n }\n if (input.siteUrl.endsWith(\"/\")) {\n throw new DualmarkConfigError(`Dualmark config: siteUrl must not end with '/': ${input.siteUrl}`);\n }\n\n const collections = input.collections ?? {};\n for (const [name, c] of Object.entries(collections)) {\n if (!c.converter) {\n throw new DualmarkConfigError(`Dualmark config: collection '${name}' is missing 'converter'`);\n }\n if (c.route && c.route.startsWith(\"/\")) {\n throw new DualmarkConfigError(\n `Dualmark config: collection '${name}' route should not start with '/' (got '${c.route}')`,\n );\n }\n }\n\n const staticPages = input.staticPages ?? [];\n for (const sp of staticPages) {\n if (!sp.pattern.startsWith(\"/\")) {\n throw new DualmarkConfigError(\n `Dualmark config: staticPages.pattern must start with '/' (got '${sp.pattern}')`,\n );\n }\n if (typeof sp.render !== \"function\") {\n throw new DualmarkConfigError(\n `Dualmark config: staticPages.render for '${sp.pattern}' must be a function`,\n );\n }\n }\n\n const parameterizedRoutes = input.parameterizedRoutes ?? [];\n for (const pr of parameterizedRoutes) {\n if (!pr.pattern.includes(\"[\")) {\n throw new DualmarkConfigError(\n `Dualmark config: parameterizedRoutes.pattern must contain at least one [param] (got '${pr.pattern}')`,\n );\n }\n }\n\n return {\n siteUrl: input.siteUrl,\n collections,\n staticPages,\n parameterizedRoutes,\n llmsTxt: input.llmsTxt,\n middleware: {\n injectLinkHeader: input.middleware?.injectLinkHeader !== false,\n },\n headers: {\n cacheControl: input.headers?.cacheControl ?? \"public, max-age=3600\",\n noindex: input.headers?.noindex !== false,\n },\n };\n}\n","import { mkdirSync, writeFileSync, existsSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport { resolveConfig, DualmarkConfigError } from \"./config-validation.js\";\nimport type { DualmarkAstroConfig, ResolvedDualmarkConfig } from \"./types.js\";\n\ninterface AstroIntegrationLogger {\n info: (msg: string) => void;\n warn: (msg: string) => void;\n error: (msg: string) => void;\n}\n\ninterface InjectedRoute {\n pattern: string;\n entrypoint: string | URL;\n prerender?: boolean;\n}\n\ninterface AstroIntegrationMiddleware {\n order: \"pre\" | \"post\";\n entrypoint: string | URL;\n}\n\ninterface ConfigSetupHookOptions {\n config: { root: URL; srcDir?: URL };\n command: string;\n isRestart?: boolean;\n injectRoute: (route: InjectedRoute) => void;\n addMiddleware?: (mw: AstroIntegrationMiddleware) => void;\n logger: AstroIntegrationLogger;\n updateConfig?: (cfg: unknown) => unknown;\n}\n\nexport interface AstroIntegrationLike {\n name: string;\n hooks: {\n \"astro:config:setup\": (opts: ConfigSetupHookOptions) => void | Promise<void>;\n };\n}\n\nconst GENERATED_DIR_NAME = \".dualmark-generated\";\n\ninterface RouteSpec {\n pattern: string;\n fileName: string;\n source: string;\n}\n\nfunction rel(from: string, to: string): string {\n const r = relative(from, to);\n return r.split(sep).join(\"/\");\n}\n\nexport function createDualmarkIntegration(input: DualmarkAstroConfig): AstroIntegrationLike {\n let resolved: ResolvedDualmarkConfig;\n try {\n resolved = resolveConfig(input);\n } catch (e) {\n if (e instanceof DualmarkConfigError) throw e;\n throw e;\n }\n\n return {\n name: \"@dualmark/astro\",\n hooks: {\n \"astro:config:setup\"(opts) {\n const root = fileURLToPath(opts.config.root);\n const generatedDir = join(root, \"node_modules\", GENERATED_DIR_NAME);\n if (!existsSync(generatedDir)) mkdirSync(generatedDir, { recursive: true });\n\n writeFileSync(\n join(generatedDir, \"config.mjs\"),\n `export default ${JSON.stringify(\n {\n siteUrl: resolved.siteUrl,\n cacheControl: resolved.headers.cacheControl,\n noindex: resolved.headers.noindex,\n },\n null,\n 2,\n )};\\n`,\n \"utf8\",\n );\n\n const routes: RouteSpec[] = [];\n\n for (const [collectionName, c] of Object.entries(resolved.collections)) {\n const route = c.route ?? collectionName;\n const slugSeg = c.slugStrategy === \"single\" ? \"[slug]\" : \"[...slug]\";\n const detailPattern = `/${route}/${slugSeg}.md`;\n const listingPattern = `/${route}.md`;\n if (typeof c.converter !== \"string\") {\n opts.logger.warn(\n `[@dualmark/astro] Collection '${collectionName}' uses an inline converter function — this isn't yet serializable into a generated route. Use a built-in converter name (e.g. 'blog') for now.`,\n );\n continue;\n }\n const converterImport = `import { resolveBuiltInConverter } from \"@dualmark/astro\";`;\n const detailSource = `${converterImport}\nimport { makeCollectionDetailEndpoint } from \"@dualmark/astro/endpoints/collection\";\nimport { getCollection } from \"astro:content\";\nimport dualmarkConfig from \"./config.mjs\";\n\nconst converter = resolveBuiltInConverter({\n name: ${JSON.stringify(c.converter)},\n collectionName: ${JSON.stringify(collectionName)},\n baseConfig: { siteUrl: dualmarkConfig.siteUrl },\n});\n\nconst endpoint = makeCollectionDetailEndpoint({\n collectionName: ${JSON.stringify(collectionName)},\n converter,\n getCollection: (name, filter) => getCollection(name, filter),\n responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },\n});\n\nexport const getStaticPaths = endpoint.getStaticPaths;\nexport const GET = endpoint.GET;\n`;\n\n const listingSource = `import { makeListingEndpoint } from \"@dualmark/astro/endpoints/listing\";\nimport { getCollection } from \"astro:content\";\nimport dualmarkConfig from \"./config.mjs\";\n\nconst endpoint = makeListingEndpoint({\n collectionName: ${JSON.stringify(collectionName)},\n siteUrl: dualmarkConfig.siteUrl,\n basePath: ${JSON.stringify(\"/\" + route)},\n title: ${JSON.stringify(c.listingMetadata?.title ?? collectionName)},\n description: ${JSON.stringify(c.listingMetadata?.description ?? `All ${collectionName} entries.`)},\n getCollection: (name, filter) => getCollection(name, filter),\n responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },\n});\n\nexport const GET = endpoint.GET;\n`;\n\n routes.push(\n { pattern: detailPattern, fileName: `collection-${collectionName}-detail.mjs`, source: detailSource },\n );\n if (c.emitListing !== false) {\n routes.push({\n pattern: listingPattern,\n fileName: `collection-${collectionName}-listing.mjs`,\n source: listingSource,\n });\n }\n }\n\n for (let i = 0; i < resolved.staticPages.length; i++) {\n const sp = resolved.staticPages[i];\n if (!sp) continue;\n const safe = sp.pattern.replace(/[^a-z0-9]/gi, \"_\");\n const fileName = `static-${i}-${safe}.mjs`;\n const renderModulePath = join(generatedDir, `static-${i}-${safe}-render.mjs`);\n writeFileSync(\n renderModulePath,\n `export default ${sp.render.toString()};\\n`,\n \"utf8\",\n );\n const source = `import { makeStaticEndpoint } from \"@dualmark/astro/endpoints/static\";\nimport dualmarkConfig from \"./config.mjs\";\nimport render from \"./${rel(generatedDir, renderModulePath)}\";\n\nconst endpoint = makeStaticEndpoint({\n render,\n responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },\n});\n\nexport const GET = endpoint.GET;\n`;\n const mdPattern = sp.pattern === \"/\" ? \"/index.md\" : sp.pattern.replace(/\\/$/, \"\") + \".md\";\n routes.push({ pattern: mdPattern, fileName, source });\n }\n\n for (let i = 0; i < resolved.parameterizedRoutes.length; i++) {\n const pr = resolved.parameterizedRoutes[i];\n if (!pr) continue;\n const safe = pr.pattern.replace(/[^a-z0-9]/gi, \"_\");\n const renderModulePath = join(generatedDir, `param-${i}-${safe}-render.mjs`);\n const pathsModulePath = join(generatedDir, `param-${i}-${safe}-paths.mjs`);\n writeFileSync(renderModulePath, `export default ${pr.render.toString()};\\n`, \"utf8\");\n writeFileSync(pathsModulePath, `export default ${pr.getStaticPaths.toString()};\\n`, \"utf8\");\n const source = `import { makeParameterizedEndpoint } from \"@dualmark/astro/endpoints/parameterized\";\nimport dualmarkConfig from \"./config.mjs\";\nimport render from \"./${rel(generatedDir, renderModulePath)}\";\nimport getStaticPaths from \"./${rel(generatedDir, pathsModulePath)}\";\n\nconst endpoint = makeParameterizedEndpoint({\n getStaticPaths: () => getStaticPaths(),\n render,\n responseOptions: { cacheControl: dualmarkConfig.cacheControl, noindex: dualmarkConfig.noindex },\n});\n\nexport const getStaticPaths = endpoint.getStaticPaths;\nexport const GET = endpoint.GET;\n`;\n const pattern = pr.pattern.startsWith(\"/\") ? pr.pattern + \".md\" : `/${pr.pattern}.md`;\n routes.push({\n pattern,\n fileName: `param-${i}-${safe}.mjs`,\n source,\n });\n }\n\n if (resolved.llmsTxt?.enabled) {\n const sections = resolved.llmsTxt.sections ?? [];\n const source = `import { makeLlmsTxtEndpoint } from \"@dualmark/astro/endpoints/llms-txt\";\n\nconst endpoint = makeLlmsTxtEndpoint({\n brandName: ${JSON.stringify(resolved.llmsTxt.brandName ?? \"Site\")},\n description: ${JSON.stringify(resolved.llmsTxt.description ?? \"\")},\n sections: ${JSON.stringify(sections)},\n});\n\nexport const GET = endpoint.GET;\n`;\n routes.push({ pattern: \"/llms.txt\", fileName: `llms-txt.mjs`, source });\n }\n\n for (const r of routes) {\n const filePath = join(generatedDir, r.fileName);\n writeFileSync(filePath, r.source, \"utf8\");\n opts.injectRoute({\n pattern: r.pattern,\n entrypoint: filePath,\n prerender: true,\n });\n }\n\n if (resolved.middleware.injectLinkHeader && opts.addMiddleware) {\n opts.addMiddleware({\n order: \"post\",\n entrypoint: \"@dualmark/astro/middleware\",\n });\n }\n\n opts.logger.info(\n `[@dualmark/astro] Injected ${routes.length} route(s) and ${\n resolved.middleware.injectLinkHeader ? \"1\" : \"0\"\n } middleware`,\n );\n\n void resolve;\n },\n },\n };\n}\n\nexport default function dualmarkAstro(config: DualmarkAstroConfig): AstroIntegrationLike {\n return createDualmarkIntegration(config);\n}\n","import {\n blogConverter,\n caseStudyConverter,\n changelogConverter,\n compareConverter,\n docsConverter,\n featureConverter,\n glossaryConverter,\n legalConverter,\n pricingConverter,\n pseoConverter,\n toolConverter,\n videoConverter,\n type BaseConverterConfig,\n type CollectionEntry,\n type Converter,\n} from \"@dualmark/converters\";\n\nexport type BuiltInConverterName =\n | \"blog\"\n | \"case-study\"\n | \"changelog\"\n | \"compare\"\n | \"docs\"\n | \"feature\"\n | \"glossary\"\n | \"legal\"\n | \"pricing\"\n | \"pseo\"\n | \"tool\"\n | \"video\";\n\nexport interface ResolveConverterArgs {\n name: string;\n collectionName: string;\n baseConfig: BaseConverterConfig;\n}\n\nexport function resolveBuiltInConverter(\n args: ResolveConverterArgs,\n): Converter<CollectionEntry<unknown>> {\n const basePath = `/${args.collectionName}`;\n const cfg = { ...args.baseConfig, basePath };\n switch (args.name as BuiltInConverterName) {\n case \"blog\":\n return blogConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"case-study\":\n return caseStudyConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"changelog\":\n return changelogConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"compare\":\n return compareConverter({ ...cfg, ourBrandColumn: \"Us\" }) as Converter<CollectionEntry<unknown>>;\n case \"docs\":\n return docsConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"feature\":\n return featureConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"glossary\":\n return glossaryConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"legal\":\n return legalConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"pricing\":\n return pricingConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"pseo\":\n return pseoConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"tool\":\n return toolConverter(cfg) as Converter<CollectionEntry<unknown>>;\n case \"video\":\n return videoConverter(cfg) as Converter<CollectionEntry<unknown>>;\n default:\n throw new Error(\n `Dualmark: unknown built-in converter '${args.name}'. Valid names: blog, case-study, changelog, compare, docs, feature, glossary, legal, pricing, pseo, tool, video. Or pass a function.`,\n );\n }\n}\n"]}
@@ -0,0 +1,54 @@
1
+ import { D as DualmarkAstroConfig, R as ResolvedDualmarkConfig } from './types-BPk2cf2p.cjs';
2
+ export { C as CollectionConfig, P as ParameterizedRouteConfig, S as SlugStrategy, a as StaticPageConfig } from './types-BPk2cf2p.cjs';
3
+ import { BaseConverterConfig, Converter, CollectionEntry } from '@dualmark/converters';
4
+ import '@dualmark/core';
5
+
6
+ interface AstroIntegrationLogger {
7
+ info: (msg: string) => void;
8
+ warn: (msg: string) => void;
9
+ error: (msg: string) => void;
10
+ }
11
+ interface InjectedRoute {
12
+ pattern: string;
13
+ entrypoint: string | URL;
14
+ prerender?: boolean;
15
+ }
16
+ interface AstroIntegrationMiddleware {
17
+ order: "pre" | "post";
18
+ entrypoint: string | URL;
19
+ }
20
+ interface ConfigSetupHookOptions {
21
+ config: {
22
+ root: URL;
23
+ srcDir?: URL;
24
+ };
25
+ command: string;
26
+ isRestart?: boolean;
27
+ injectRoute: (route: InjectedRoute) => void;
28
+ addMiddleware?: (mw: AstroIntegrationMiddleware) => void;
29
+ logger: AstroIntegrationLogger;
30
+ updateConfig?: (cfg: unknown) => unknown;
31
+ }
32
+ interface AstroIntegrationLike {
33
+ name: string;
34
+ hooks: {
35
+ "astro:config:setup": (opts: ConfigSetupHookOptions) => void | Promise<void>;
36
+ };
37
+ }
38
+ declare function createDualmarkIntegration(input: DualmarkAstroConfig): AstroIntegrationLike;
39
+ declare function dualmarkAstro(config: DualmarkAstroConfig): AstroIntegrationLike;
40
+
41
+ declare class DualmarkConfigError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ declare function resolveConfig(input: DualmarkAstroConfig): ResolvedDualmarkConfig;
45
+
46
+ type BuiltInConverterName = "blog" | "case-study" | "changelog" | "compare" | "docs" | "feature" | "glossary" | "legal" | "pricing" | "pseo" | "tool" | "video";
47
+ interface ResolveConverterArgs {
48
+ name: string;
49
+ collectionName: string;
50
+ baseConfig: BaseConverterConfig;
51
+ }
52
+ declare function resolveBuiltInConverter(args: ResolveConverterArgs): Converter<CollectionEntry<unknown>>;
53
+
54
+ export { type AstroIntegrationLike, type BuiltInConverterName, DualmarkAstroConfig, DualmarkConfigError, ResolvedDualmarkConfig, createDualmarkIntegration, dualmarkAstro as default, dualmarkAstro as dualmark, resolveBuiltInConverter, resolveConfig };
@@ -0,0 +1,54 @@
1
+ import { D as DualmarkAstroConfig, R as ResolvedDualmarkConfig } from './types-BPk2cf2p.js';
2
+ export { C as CollectionConfig, P as ParameterizedRouteConfig, S as SlugStrategy, a as StaticPageConfig } from './types-BPk2cf2p.js';
3
+ import { BaseConverterConfig, Converter, CollectionEntry } from '@dualmark/converters';
4
+ import '@dualmark/core';
5
+
6
+ interface AstroIntegrationLogger {
7
+ info: (msg: string) => void;
8
+ warn: (msg: string) => void;
9
+ error: (msg: string) => void;
10
+ }
11
+ interface InjectedRoute {
12
+ pattern: string;
13
+ entrypoint: string | URL;
14
+ prerender?: boolean;
15
+ }
16
+ interface AstroIntegrationMiddleware {
17
+ order: "pre" | "post";
18
+ entrypoint: string | URL;
19
+ }
20
+ interface ConfigSetupHookOptions {
21
+ config: {
22
+ root: URL;
23
+ srcDir?: URL;
24
+ };
25
+ command: string;
26
+ isRestart?: boolean;
27
+ injectRoute: (route: InjectedRoute) => void;
28
+ addMiddleware?: (mw: AstroIntegrationMiddleware) => void;
29
+ logger: AstroIntegrationLogger;
30
+ updateConfig?: (cfg: unknown) => unknown;
31
+ }
32
+ interface AstroIntegrationLike {
33
+ name: string;
34
+ hooks: {
35
+ "astro:config:setup": (opts: ConfigSetupHookOptions) => void | Promise<void>;
36
+ };
37
+ }
38
+ declare function createDualmarkIntegration(input: DualmarkAstroConfig): AstroIntegrationLike;
39
+ declare function dualmarkAstro(config: DualmarkAstroConfig): AstroIntegrationLike;
40
+
41
+ declare class DualmarkConfigError extends Error {
42
+ constructor(message: string);
43
+ }
44
+ declare function resolveConfig(input: DualmarkAstroConfig): ResolvedDualmarkConfig;
45
+
46
+ type BuiltInConverterName = "blog" | "case-study" | "changelog" | "compare" | "docs" | "feature" | "glossary" | "legal" | "pricing" | "pseo" | "tool" | "video";
47
+ interface ResolveConverterArgs {
48
+ name: string;
49
+ collectionName: string;
50
+ baseConfig: BaseConverterConfig;
51
+ }
52
+ declare function resolveBuiltInConverter(args: ResolveConverterArgs): Converter<CollectionEntry<unknown>>;
53
+
54
+ export { type AstroIntegrationLike, type BuiltInConverterName, DualmarkAstroConfig, DualmarkConfigError, ResolvedDualmarkConfig, createDualmarkIntegration, dualmarkAstro as default, dualmarkAstro as dualmark, resolveBuiltInConverter, resolveConfig };