dogsbay 0.2.0-beta.19 → 0.2.0-beta.20

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.
@@ -17,7 +17,7 @@
17
17
  import { existsSync } from "node:fs";
18
18
  import { dirname, isAbsolute, resolve } from "node:path";
19
19
  import pc from "picocolors";
20
- import { emitAstroPages, emitPassthroughAstroPages, emitSiteConfig, emitConfigDerivedFiles, emitDeployArtifacts, emitAgentReadinessFiles, emitMissingTranslationStubs, emitSwitcherMap, emitTaxonomyRoutes, emitPluginRuntime, normalizeBasePath, basePathSegments, } from "@dogsbay/format-astro";
20
+ import { emitAstroPages, emitPassthroughAstroPages, emitSiteConfig, emitConfigDerivedFiles, emitDeployArtifacts, emitAgentReadinessFiles, emitMissingTranslationStubs, emitSwitcherMap, emitTaxonomyRoutes, emitPluginRuntime, normalizeBasePath, basePathSegments, resolvePrefixes, } from "@dogsbay/format-astro";
21
21
  import { collectPassthroughEntries } from "../passthrough-astro.js";
22
22
  import { configToAstroOptions, findConfig, loadConfig, resolveOutputDir, } from "../config/index.js";
23
23
  import { filterSourcesForMode, importContent, primaryModeFiltersAnything, } from "../import-content.js";
@@ -167,6 +167,11 @@ export async function siteBuild(cwd, options) {
167
167
  // generalize this to copy assets per-source.
168
168
  const astroOpts = configToAstroOptions(config);
169
169
  astroOpts.sourceDir = resolvedSources[0];
170
+ // siteRoot = repo root (where dogsbay.config.yml lives). Used by
171
+ // emitDeployArtifacts to drop GH Actions workflows at
172
+ // <siteRoot>/.github/ rather than inside the Astro subdir, where
173
+ // GitHub wouldn't find them.
174
+ astroOpts.projectDir = siteRoot;
170
175
  // Refresh src/data/site.json from the current config — purely
171
176
  // config-derived, so changes in dogsbay.config.yml propagate without
172
177
  // re-running site init.
@@ -245,9 +250,13 @@ export async function siteBuild(cwd, options) {
245
250
  labels: raw.labels,
246
251
  };
247
252
  }
253
+ // Pass the combined prefix as basePath to taxonomy — term URLs
254
+ // need to include both urlBase (host subpath) and dogsbay
255
+ // basePath so they resolve correctly under the served URL.
256
+ const taxoCombined = resolvePrefixes(config.site.url, config.site.basePath).combined;
248
257
  const emitted = emitTaxonomyRoutes(pages, outputDir, taxonomyConfigs, {
249
258
  section: config.content.section,
250
- basePath: config.site.basePath,
259
+ basePath: taxoCombined,
251
260
  });
252
261
  if (emitted.length > 0) {
253
262
  console.log(` Emitted taxonomy routes: ${emitted.join(", ")}`);
@@ -101,9 +101,12 @@ export async function siteInit(targetDir, options) {
101
101
  }
102
102
  // Emit the static scaffold into the configured output dir
103
103
  // (default ./astro). The project root keeps only the config and
104
- // human-edited files (content/, theme/, public/).
104
+ // human-edited files (content/, theme/, public/). projectDir
105
+ // (= absTarget) lets deploy emitters write artifacts that GitHub
106
+ // Actions reads from the repo root rather than the Astro subdir.
105
107
  const outputDir = resolveOutputDir(config, configPath);
106
108
  const astroOpts = configToAstroOptions(config);
109
+ astroOpts.projectDir = absTarget;
107
110
  if (options.local)
108
111
  astroOpts.local = true;
109
112
  emitSiteScaffold(outputDir, config.site.name, astroOpts, true);
@@ -260,38 +260,12 @@ function validateSite(site, sourcePath) {
260
260
  `or repeated slashes. Got ${JSON.stringify(s.basePath)}`);
261
261
  }
262
262
  }
263
- // Cross-field check: site.url must be host-only (no path) when
264
- // a non-empty basePath is set. Astro itself splits these as
265
- // `site` (origin) + `base` (path); double-counting the prefix
266
- // produces canonical URLs like https://example.com/docs/docs/.
267
- // Detect by parsing site.url as a URL and rejecting any non-`/`
268
- // pathname when basePath is configured.
269
- if (typeof s.url === "string" && s.url.length > 0) {
270
- let parsedUrl;
271
- try {
272
- parsedUrl = new URL(s.url);
273
- }
274
- catch {
275
- // Invalid URL — leave further checks for downstream Astro;
276
- // we only want to catch the host+path overlap here.
277
- }
278
- const basePath = typeof s.basePath === "string" ? s.basePath : undefined;
279
- const basePathIsSet = basePath !== undefined && basePath !== "" && basePath !== "/";
280
- if (parsedUrl && basePathIsSet) {
281
- const urlPath = parsedUrl.pathname.replace(/\/+$/, ""); // strip trailing /
282
- if (urlPath !== "" && urlPath !== "/") {
283
- const origin = `${parsedUrl.protocol}//${parsedUrl.host}`;
284
- throw new Error(`site.url must be host-only when site.basePath is set in ${sourcePath}; ` +
285
- `got ${JSON.stringify(s.url)}, expected ${JSON.stringify(origin)} ` +
286
- `with basePath ${JSON.stringify(basePath)}.\n\n` +
287
- `Astro splits these into:\n` +
288
- ` site: ${JSON.stringify(origin)}\n` +
289
- ` base: ${JSON.stringify(basePath)}\n` +
290
- `Without this fix, canonical URLs double-count the prefix ` +
291
- `(e.g. ${origin}${urlPath}${basePath}/).`);
292
- }
293
- }
294
- }
263
+ // site.url and site.basePath are now independent prefixes that
264
+ // compose at emit time. The path component of site.url drives
265
+ // Astro's `base` (where the served space sits in the host);
266
+ // basePath stays as content's filesystem position within that
267
+ // served space. See plans/astro-base-from-site-url.md and
268
+ // packages/format-astro/src/base-path.ts:resolvePrefixes.
295
269
  return s;
296
270
  }
297
271
  const VALID_FROM = [
@@ -1,4 +1,4 @@
1
- import { normalizeBasePath } from "@dogsbay/format-astro";
1
+ import { normalizeBasePath, resolvePrefixes } from "@dogsbay/format-astro";
2
2
  import { plugin as mkdocsPlugin } from "@dogsbay/format-mkdocs/cli";
3
3
  import { plugin as astroPlugin } from "@dogsbay/format-astro/cli";
4
4
  import { plugin as obsidianPlugin } from "@dogsbay/format-obsidian/cli";
@@ -396,16 +396,17 @@ function buildImportOptions(config, source) {
396
396
  if (config.taxonomies) {
397
397
  opts.taxonomyNames = Object.keys(config.taxonomies);
398
398
  }
399
- // Pass site.basePath through as `hrefPrefix` so nav-builders
400
- // produce hrefs matching where pages will actually be emitted.
401
- // `normalizeBasePath(undefined)` returns the platform default
402
- // (`/docs`) so we ALWAYS thread a value — leaving it unset would
403
- // force every importer to invent its own fallback (which they did,
404
- // inconsistently). Importers that care about basePath are free to
405
- // ignore it, but the default makes "namespace-prefixed nav builds
406
- // correctly" the path of least resistance. See
407
- // plans/configurable-base-path.md and the api-docs example in
408
- // plans/openapi-builtin.md.
409
- opts.hrefPrefix = normalizeBasePath(config.site.basePath);
399
+ // Pass the COMBINED URL prefix (urlBase from site.url's path +
400
+ // site.basePath) as `hrefPrefix` so nav-builders produce hrefs
401
+ // matching the served URL of each page. Two prefix layers
402
+ // because subpath-mounted deploys (GH Pages project pages,
403
+ // multi-mount Cloudflare under one Worker) add a host-level
404
+ // prefix on top of dogsbay's basePath. See
405
+ // plans/astro-base-from-site-url.md.
406
+ //
407
+ // Back-compat: when site.url is origin-only (no path), urlBase
408
+ // is empty and combined === basePath, so existing sites see no
409
+ // change.
410
+ opts.hrefPrefix = resolvePrefixes(config.site.url, config.site.basePath).combined;
410
411
  return opts;
411
412
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dogsbay",
3
- "version": "0.2.0-beta.19",
3
+ "version": "0.2.0-beta.20",
4
4
  "description": "CLI for Dogsbay — scaffold, build, and serve documentation sites with markdown / MkDocs / Obsidian / OpenAPI sources",
5
5
  "type": "module",
6
6
  "bin": {
@@ -32,14 +32,14 @@
32
32
  "picocolors": "^1.1.0",
33
33
  "prompts": "^2.4.2",
34
34
  "yaml": "^2.8.3",
35
- "@dogsbay/format-astro": "0.2.0-beta.19",
36
- "@dogsbay/format-obsidian": "0.2.0-beta.19",
37
- "@dogsbay/format-mkdocs": "0.2.0-beta.19",
38
- "@dogsbay/format-mdx": "0.2.0-beta.19",
39
- "@dogsbay/format-starlight": "0.2.0-beta.19",
40
- "@dogsbay/format-dogsbay-md": "0.2.0-beta.19",
41
- "@dogsbay/format-openapi": "0.2.0-beta.19",
42
- "@dogsbay/types": "0.2.0-beta.19"
35
+ "@dogsbay/format-mkdocs": "0.2.0-beta.20",
36
+ "@dogsbay/format-astro": "0.2.0-beta.20",
37
+ "@dogsbay/format-mdx": "0.2.0-beta.20",
38
+ "@dogsbay/format-obsidian": "0.2.0-beta.20",
39
+ "@dogsbay/format-dogsbay-md": "0.2.0-beta.20",
40
+ "@dogsbay/format-starlight": "0.2.0-beta.20",
41
+ "@dogsbay/format-openapi": "0.2.0-beta.20",
42
+ "@dogsbay/types": "0.2.0-beta.20"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "^22.0.0",