blume 1.0.0 → 1.0.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # blume
2
2
 
3
+ ## 1.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ - d62dbd0: Harden the pre-paint inline scripts and the route-normalizing regexes against the issues CodeQL flagged.
8
+
9
+ The theme and banner scripts in `<head>` used to be built by interpolating config values into JavaScript source with `JSON.stringify`. JSON escaping isn't a code-context escape — `</script>` and U+2028/U+2029 pass straight through it — so a crafted `banner.id` or theme value could break out of the script. Both scripts are now constants and take their values from `data-*` attributes on their own `<script>` tag, which Astro HTML-escapes. `ReferenceLayout` had drifted to its own inline copies of both scripts; it now shares the same module as `RootLayout` and `PageLayout`.
10
+
11
+ Route and slug normalization used `/^\/+|\/+$/`-style patterns to trim leading and trailing separators. Those take quadratic time on a long run of the trimmed character, and they run on values that come from outside Blume (configured routes, OpenAPI spec URLs, the site origin), so a pathological config could hang the build. They're replaced by linear trimming helpers in `core/trim.ts`; behavior is unchanged.
12
+
13
+ ## 1.0.1
14
+
15
+ ### Patch Changes
16
+
17
+ - 6afb56a: Declare the `blume` bin as `bin/blume.mjs` instead of `./bin/blume.mjs`. The leading `./` is redundant and some package managers normalize it away when linking the binary; dropping it keeps the published manifest consistent with what installers actually write.
18
+
3
19
  ## 1.0.0
4
20
 
5
21
  ### Major Changes
package/dist/cli/index.js CHANGED
@@ -536,7 +536,7 @@ var normalizeBasePath = (input) => {
536
536
  if (!input) {
537
537
  return "";
538
538
  }
539
- const trimmed = input.trim().replaceAll(/^\/+|\/+$/gu, "").replaceAll(/\/{2,}/gu, "/");
539
+ const trimmed = input.trim().split("/").filter(Boolean).join("/");
540
540
  return trimmed === "" ? "" : `/${trimmed}`;
541
541
  };
542
542
  var isInternalPath = (target) => target.startsWith("/") && !target.startsWith("//");
@@ -4127,6 +4127,23 @@ var buildMcpData = async (project) => {
4127
4127
  };
4128
4128
  };
4129
4129
 
4130
+ // src/core/trim.ts
4131
+ var trimStart = (text, char) => {
4132
+ let start = 0;
4133
+ while (start < text.length && text[start] === char) {
4134
+ start += 1;
4135
+ }
4136
+ return text.slice(start);
4137
+ };
4138
+ var trimEnd = (text, char) => {
4139
+ let end = text.length;
4140
+ while (end > 0 && text[end - 1] === char) {
4141
+ end -= 1;
4142
+ }
4143
+ return text.slice(0, end);
4144
+ };
4145
+ var trimChar = (text, char) => trimEnd(trimStart(text, char), char);
4146
+
4130
4147
  // src/ai/mcp/tools.ts
4131
4148
  var READ_ONLY = { openWorldHint: false, readOnlyHint: true };
4132
4149
  var MCP_TOOLS = [
@@ -4159,7 +4176,7 @@ var MCP_TOOLS = [
4159
4176
  // src/ai/mcp/discovery.ts
4160
4177
  var serverUrl = (input) => {
4161
4178
  const path = withBasePath(input.base, input.route);
4162
- return input.site ? `${input.site.replace(/\/+$/u, "")}${path}` : path;
4179
+ return input.site ? `${trimEnd(input.site, "/")}${path}` : path;
4163
4180
  };
4164
4181
  var buildMcpDiscovery = (input) => ({
4165
4182
  servers: [
@@ -4829,17 +4846,14 @@ import { isAbsolute as isAbsolute5, join as join16, resolve as resolve5 } from "
4829
4846
 
4830
4847
  // src/openapi/references.ts
4831
4848
  var NON_SLUG = /[^a-z0-9]+/gu;
4832
- var SLUG_EDGES = /^-+|-+$/gu;
4833
- var ROUTE_EDGES = /^\/+|\/+$/gu;
4834
- var TRAILING_SLASH = /\/+$/u;
4835
- var slugify = (text) => text.toLowerCase().replace(NON_SLUG, "-").replace(SLUG_EDGES, "");
4849
+ var slugify = (text) => trimChar(text.toLowerCase().replace(NON_SLUG, "-"), "-");
4836
4850
  var normalizeRoute = (route) => {
4837
4851
  const trimmed = route.trim();
4838
4852
  const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
4839
- const noTrailing = withSlash.replace(TRAILING_SLASH, "");
4853
+ const noTrailing = trimEnd(withSlash, "/");
4840
4854
  return noTrailing === "" ? "/" : noTrailing;
4841
4855
  };
4842
- var routeSlug = (route) => slugify(route.replace(ROUTE_EDGES, "")) || "reference";
4856
+ var routeSlug = (route) => slugify(trimChar(route, "/")) || "reference";
4843
4857
  var sourcesOf = (block) => {
4844
4858
  const sources = [...block.sources];
4845
4859
  if (block.spec) {
@@ -5010,8 +5024,8 @@ var loadWithCache = async (name, cache, fetchEntries, refresh = true) => {
5010
5024
 
5011
5025
  // src/openapi/model.ts
5012
5026
  var NON_SLUG2 = /[^a-z0-9]+/gu;
5013
- var SLUG_EDGES2 = /^-+|-+$/gu;
5014
- var slugify2 = (text) => text.toLowerCase().replace(NON_SLUG2, "-").replace(SLUG_EDGES2, "");
5027
+ var SLUG_EDGES = /^-+|-+$/gu;
5028
+ var slugify2 = (text) => text.toLowerCase().replace(NON_SLUG2, "-").replace(SLUG_EDGES, "");
5015
5029
  var HTTP_METHODS = [
5016
5030
  "get",
5017
5031
  "put",
@@ -8153,12 +8167,9 @@ export function GET({ props }) {
8153
8167
  });
8154
8168
  }
8155
8169
  `;
8156
- var mcpPageFile = (route) => {
8157
- const clean = route.replace(/^\/+/u, "").replace(/\/+$/u, "");
8158
- return `${clean}.ts`;
8159
- };
8170
+ var mcpPageFile = (route) => `${trimChar(route, "/")}.ts`;
8160
8171
  var mcpEndpointTemplate = (route) => {
8161
- const clean = route.replace(/^\/+/u, "").replace(/\/+$/u, "");
8172
+ const clean = trimChar(route, "/");
8162
8173
  const up = "../".repeat(clean.split("/").length);
8163
8174
  return `// Generated by Blume. Do not edit.
8164
8175
  import type { APIRoute } from "astro";
@@ -9095,9 +9106,9 @@ ${dark}`;
9095
9106
 
9096
9107
  // src/openapi/scalar.ts
9097
9108
  var URL_SPEC2 = /^https?:\/\//u;
9098
- var ROUTE_EDGES2 = /^\/+|\/+$/gu;
9109
+ var ROUTE_EDGES = /^\/+|\/+$/gu;
9099
9110
  var referencePagePath = (route) => {
9100
- const segments = route.replace(ROUTE_EDGES2, "");
9111
+ const segments = route.replace(ROUTE_EDGES, "");
9101
9112
  return `${segments === "" ? "index" : segments}.astro`;
9102
9113
  };
9103
9114
  var darkModeConfig = (mode) => {
@@ -13836,5 +13847,5 @@ process.on("unhandledRejection", (error) => {
13836
13847
  });
13837
13848
  runMain(main);
13838
13849
 
13839
- //# debugId=066FB7264FFC708364756E2164756E21
13850
+ //# debugId=5F5E50EAF35B586A64756E2164756E21
13840
13851
  //# sourceMappingURL=index.js.map