@boopkit/cap-web 0.5.2 → 0.5.4

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/capability.json CHANGED
@@ -4,13 +4,13 @@
4
4
  "type": "application",
5
5
  "package": "@boopkit/cap-web",
6
6
  "dependencies": [
7
- "express-handlebars",
8
- "heroicons",
9
- "tailwindcss"
7
+ "express-handlebars@^8",
8
+ "heroicons@^2",
9
+ "tailwindcss@^4"
10
10
  ],
11
11
  "devDependencies": [
12
- "@tailwindcss/cli",
13
- "@types/express-handlebars"
12
+ "@tailwindcss/cli@^4",
13
+ "@types/express-handlebars@^6"
14
14
  ],
15
15
  "files": [
16
16
  "views/",
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAyE3D,CAAC"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAyBA;;GAEG;AACH,eAAO,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,CAiG3D,CAAC"}
package/dist/helpers.js CHANGED
@@ -43,6 +43,28 @@ exports.helpers = {
43
43
  return str;
44
44
  return str.slice(0, len) + '…';
45
45
  },
46
+ /**
47
+ * URL-encode a value for a query parameter: {{urlencode next}}
48
+ *
49
+ * Handlebars escapes an interpolated value for HTML, which is not the same as
50
+ * escaping it for a URL. `href="?next={{next}}"` with a return path of
51
+ * `/a&b=c` renders `next=/a&b=c`, and the browser reads that as
52
+ * `next=/a` plus a stray `b=c` — the visitor lands on the wrong page. Any
53
+ * template that interpolates a value into a query string needs this helper.
54
+ *
55
+ * This *encodes*; it does not sanitise. Deciding whether a return path is
56
+ * acceptable belongs to whatever gates it (cap-oauth-client's
57
+ * `validateReturnPath`, say) — stripping characters here would put a second,
58
+ * quietly divergent copy of that judgement in the view layer.
59
+ *
60
+ * The result is deliberately not a SafeString: `encodeURIComponent` leaves
61
+ * only alphanumerics and `-_.!~*'()%`, of which Handlebars escapes just the
62
+ * apostrophe, and `'` decodes back to `'` before the browser parses the
63
+ * URL. So the value round-trips, and the attribute keeps its HTML escaping.
64
+ */
65
+ urlencode: (value) => typeof value === 'string' || typeof value === 'number'
66
+ ? encodeURIComponent(String(value))
67
+ : '',
46
68
  /** Uppercase: {{upper text}} */
47
69
  upper: (str) => (typeof str === 'string' ? str.toUpperCase() : ''),
48
70
  /** Lowercase: {{lower text}} */
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boopkit/cap-web",
3
- "version": "0.5.2",
3
+ "version": "0.5.4",
4
4
  "description": "Express view engine configuration, Handlebars helpers, and static asset middleware",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,6 +35,7 @@ Handlebars via `express-handlebars`. Templates in `views/`, layouts in `views/la
35
35
  |--------|---------|
36
36
  | `json` | JSON stringify with formatting |
37
37
  | `truncate` | Truncate string with ellipsis |
38
+ | `urlencode` | Percent-encode a value for a query parameter: `href="/signup?next={{urlencode next}}"`. Handlebars escapes for HTML, not for a URL, so a value interpolated straight into a query string is truncated at its first `&`. |
38
39
  | `fmt_dollars` | Currency formatting |
39
40
  | `fmt_percent` | Percentage formatting |
40
41
  | `fmt_date` | Human-readable date (e.g., "March 28, 2026") |
@@ -96,6 +96,7 @@ When considering whether to reuse existing components:
96
96
  - `icon` — inline SVG icon from heroicons: `{{icon "user" "24/outline"}}` or with CSS class: `{{icon "check" "24/solid" class="w-5 h-5 text-green-600"}}`. Styles: `24/outline`, `24/solid`, `20/solid`, `16/solid`. Icons are read from `node_modules/heroicons/` and cached.
97
97
  - `json` — JSON stringify: `{{json obj}}`
98
98
  - `truncate` — truncate string: `{{truncate text 100}}`
99
+ - `urlencode` — percent-encode a value for a query parameter: `<a href="/signup?next={{urlencode next}}">`. Handlebars escapes an interpolated value for HTML, not for a URL, so `?next={{next}}` renders a return path of `/a&b=c` as `next=/a&amp;b&#x3D;c` and the browser reads `next=/a`. Use this helper for **every** value that lands in a query string; it encodes rather than validates, so whatever gates the value keeps doing that job.
99
100
  - `upper` / `lower` — case conversion
100
101
  - `eq` — strict equality check (also available from handlebars-helpers)
101
102
 
@@ -192,7 +193,7 @@ When designing report/analytics UIs, prefer a **paper-like** presentation:
192
193
  See also:
193
194
  - [development.skill.md](development.skill.md) for Spartan Code Philosophy
194
195
  - [../reference/web-development.ref.md](../reference/web-development.ref.md) for current implementation examples
195
- - [../reference/boop-guide.ref.md](../reference/boop-guide.ref.md) for CSS extension model (`@theme` tokens, package styles, cascade overrides)
196
+ - [`reference/boop-guide.ref.md`](../../reference/boop-guide.ref.md) for the CSS extension model (`@theme` tokens, package styles, cascade overrides)
196
197
 
197
198
  ## Visually verify before declaring done
198
199