@wizzlethorpe/vaults 0.6.1 → 0.8.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 (102) hide show
  1. package/README.md +135 -17
  2. package/dist/build.js +433 -181
  3. package/dist/build.js.map +1 -1
  4. package/dist/commands/build.js +4 -4
  5. package/dist/commands/build.js.map +1 -1
  6. package/dist/commands/init.js +13 -10
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/password.js +3 -1
  9. package/dist/commands/password.js.map +1 -1
  10. package/dist/commands/patreon.js +30 -20
  11. package/dist/commands/patreon.js.map +1 -1
  12. package/dist/commands/preview.js +10 -8
  13. package/dist/commands/preview.js.map +1 -1
  14. package/dist/commands/push.js +11 -9
  15. package/dist/commands/push.js.map +1 -1
  16. package/dist/commands/role.js +5 -0
  17. package/dist/commands/role.js.map +1 -1
  18. package/dist/config.js +30 -15
  19. package/dist/config.js.map +1 -1
  20. package/dist/escape.js +29 -0
  21. package/dist/escape.js.map +1 -0
  22. package/dist/favicon.js +3 -36
  23. package/dist/favicon.js.map +1 -1
  24. package/dist/foundry-importer.js +61 -0
  25. package/dist/foundry-importer.js.map +1 -0
  26. package/dist/images.js +0 -30
  27. package/dist/images.js.map +1 -1
  28. package/dist/index.js +37 -4
  29. package/dist/index.js.map +1 -1
  30. package/dist/migrate/0.6-legacy-auth-settings.js +96 -0
  31. package/dist/migrate/0.6-legacy-auth-settings.js.map +1 -0
  32. package/dist/migrate/0.7-vaults-dir.js +70 -0
  33. package/dist/migrate/0.7-vaults-dir.js.map +1 -0
  34. package/dist/migrate/registry.js +6 -0
  35. package/dist/migrate/registry.js.map +1 -0
  36. package/dist/migrate/run.js +38 -0
  37. package/dist/migrate/run.js.map +1 -0
  38. package/dist/migrate/types.js +8 -0
  39. package/dist/migrate/types.js.map +1 -0
  40. package/dist/paths.js +66 -0
  41. package/dist/paths.js.map +1 -0
  42. package/dist/render/auth-template.js +23 -141
  43. package/dist/render/auth-template.js.map +1 -1
  44. package/dist/render/bases.js +56 -44
  45. package/dist/render/bases.js.map +1 -1
  46. package/dist/render/callouts.js +29 -10
  47. package/dist/render/callouts.js.map +1 -1
  48. package/dist/render/embed.js +124 -26
  49. package/dist/render/embed.js.map +1 -1
  50. package/dist/render/extensions.js +68 -0
  51. package/dist/render/extensions.js.map +1 -0
  52. package/dist/render/external-links.js +32 -0
  53. package/dist/render/external-links.js.map +1 -0
  54. package/dist/render/footer.js +37 -0
  55. package/dist/render/footer.js.map +1 -0
  56. package/dist/render/frontmatter.js +17 -0
  57. package/dist/render/frontmatter.js.map +1 -0
  58. package/dist/render/handlers/assets.js +123 -0
  59. package/dist/render/handlers/assets.js.map +1 -0
  60. package/dist/render/handlers/builtin/dice.js +78 -0
  61. package/dist/render/handlers/builtin/dice.js.map +1 -0
  62. package/dist/render/handlers/builtin/fm-code.js +50 -0
  63. package/dist/render/handlers/builtin/fm-code.js.map +1 -0
  64. package/dist/render/handlers/builtin/fm.js +83 -0
  65. package/dist/render/handlers/builtin/fm.js.map +1 -0
  66. package/dist/render/handlers/builtin/index.js +10 -0
  67. package/dist/render/handlers/builtin/index.js.map +1 -0
  68. package/dist/render/handlers/builtin/inline-format.js +26 -0
  69. package/dist/render/handlers/builtin/inline-format.js.map +1 -0
  70. package/dist/render/handlers/builtin/statblock.js +491 -0
  71. package/dist/render/handlers/builtin/statblock.js.map +1 -0
  72. package/dist/render/handlers/dispatch.js +182 -0
  73. package/dist/render/handlers/dispatch.js.map +1 -0
  74. package/dist/render/handlers/loader.js +90 -0
  75. package/dist/render/handlers/loader.js.map +1 -0
  76. package/dist/render/handlers/types.js +60 -0
  77. package/dist/render/handlers/types.js.map +1 -0
  78. package/dist/render/image-srcs.js +42 -0
  79. package/dist/render/image-srcs.js.map +1 -0
  80. package/dist/render/layout.js +62 -9
  81. package/dist/render/layout.js.map +1 -1
  82. package/dist/render/pipeline.js +37 -8
  83. package/dist/render/pipeline.js.map +1 -1
  84. package/dist/render/preview.js +10 -5
  85. package/dist/render/preview.js.map +1 -1
  86. package/dist/render/slug.js +5 -0
  87. package/dist/render/slug.js.map +1 -1
  88. package/dist/render/styles.js +118 -11
  89. package/dist/render/styles.js.map +1 -1
  90. package/dist/render/wikilink.js +15 -4
  91. package/dist/render/wikilink.js.map +1 -1
  92. package/dist/scan.js +1 -1
  93. package/dist/scan.js.map +1 -1
  94. package/dist/settings.js +25 -4
  95. package/dist/settings.js.map +1 -1
  96. package/dist/version.js +36 -0
  97. package/dist/version.js.map +1 -0
  98. package/package.json +12 -12
  99. package/dist/api.js +0 -42
  100. package/dist/api.js.map +0 -1
  101. package/dist/render/mcp-template.js +0 -239
  102. package/dist/render/mcp-template.js.map +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # vaults
2
2
 
3
- Sync an Obsidian vault to a Cloudflare-hosted wiki. The CLI renders your notes locally to HTML and deploys them to your own Cloudflare Pages account. Supports role-based access (public, patron, dm, …) so different parts of the same vault can be visible to different audiences.
3
+ Sync an Obsidian vault to a Cloudflare-hosted wiki. The CLI renders your notes locally to HTML and deploys them to your own Cloudflare Pages account. Supports role-based access (public, patron, dm, …) so different parts of the same vault can be visible to different audiences. Patrons can be authenticated by password or by Patreon OAuth (linking roles to specific Patreon tier IDs).
4
4
 
5
5
  ## Install
6
6
 
@@ -28,6 +28,8 @@ vaults push # render + deploy to Cloudflare Pages
28
28
 
29
29
  The first push prompts for a Pages project name and runs `wrangler login` if you aren't authenticated. After that it just renders and deploys.
30
30
 
31
+ If you'd rather not `cd` into the vault every time, set `VAULT_PATH=~/Documents/MyVault` in your shell rc and run `vaults` from anywhere.
32
+
31
33
  ## How it works
32
34
 
33
35
  ```
@@ -40,25 +42,50 @@ Cloudflare Pages ← per-user, your account
40
42
  └── functions/_middleware.js ← auth gate (cookie/bearer based)
41
43
  ```
42
44
 
43
- - **Per-tier deploys.** A page tagged `role: dm` in its frontmatter only ships to the dm variant. Public visitors *cannot* fetch it; the file structurally doesn't exist in their variant.
44
- - **Images are gated too.** Only images embedded by visible pages are copied into a given variant.
45
- - **Incremental sync.** External clients (the [Foundry VTT module](https://github.com/wizzlethorpe/vaults-foundry)) can pull changes via `/_manifest.json` + `/_batch` endpoints; the CLI computes content hashes so the diff is minimal.
45
+ - **Per-tier deploys.** A page tagged `role: dm` in its frontmatter only includes to the dm variant. Public visitors *cannot* fetch it; the file structurally doesn't exist in their variant.
46
+ - **Inline gating with callouts.** Drop a `> [!dm]` callout in an otherwise public page; the entire block is stripped from the public deploy. Same for any other configured role.
47
+ - **Images and media are gated too.** Only images, audio, video, PDFs, and EPUBs embedded by visible pages are copied into a given variant. Unknown extensions are skipped by default (toggle `include_unknown_files`).
48
+ - **Incremental sync.** External clients (the [Foundry VTT module](https://github.com/wizzlethorpe/vaults)) probe `/_manifest.json` to discover the deploy's name, auth requirements, and role order, then pull `/_batch` (text) and `/_batch-images` (binary) for changed content. Manifest hashes fold in per-page frontmatter, so a role flip or title rename triggers a sync without a body diff.
49
+ - **Bases support.** `.base` files render as cards / table / list inside the wiki, just like inside Obsidian.
50
+ - **Social meta.** OG / Twitter card tags are auto-generated. Pages without an explicit `image:` frontmatter use the first body embed (toggle with `auto_image`).
46
51
 
47
52
  ## Commands
48
53
 
54
+ ### Build / deploy
55
+
49
56
  | Command | What it does |
50
57
  |---|---|
51
58
  | `vaults init` | Write a `settings.md` with sensible defaults. |
52
59
  | `vaults build` | Render the vault to a local directory (no deploy). |
53
60
  | `vaults preview` | Render + serve locally via `wrangler pages dev` so you can click around with auth working. |
54
61
  | `vaults push` | Render + deploy to Cloudflare Pages. |
62
+ | `vaults push --dry-run` | Render without deploying. |
63
+ | `vaults push --rotate-secret` | Generate a fresh `SESSION_SECRET`, invalidating every issued auth token at once. |
64
+ | `vaults push --all-warnings` / `vaults build --all-warnings` | Don't truncate the broken-link / missing-image report. |
65
+
66
+ ### Roles and passwords
67
+
68
+ | Command | What it does |
69
+ |---|---|
55
70
  | `vaults role add <name>` | Add an access tier. The first role becomes the default (no password). |
56
71
  | `vaults role remove <name>` | Remove an access tier. |
57
72
  | `vaults role list` | List configured roles. |
58
73
  | `vaults role promote <name>` / `demote <name>` | Reorder tiers. |
59
74
  | `vaults password <role>` | Set or change a role's password (PBKDF2-SHA256). |
60
- | `vaults push --rotate-secret` | Generate a fresh `SESSION_SECRET`, invalidating every issued auth token at once. |
61
- | `vaults push --all-warnings` / `vaults build --all-warnings` | Don't truncate the broken-link / missing-image report. |
75
+
76
+ ### Patreon OAuth (optional)
77
+
78
+ Link roles to Patreon tier IDs, so any patron at that tier can sign in with Patreon and pick up the corresponding role. Coexists with passwords; either grants the role.
79
+
80
+ | Command | What it does |
81
+ |---|---|
82
+ | `vaults patreon configure` | Prompts for Patreon OAuth client credentials and walks you through picking a campaign. The client secret is stored as a Wrangler secret on next push. |
83
+ | `vaults patreon link <role> <tier-id>` | Map a role to a numeric Patreon tier ID. |
84
+ | `vaults patreon unlink <role>` | Remove a role's tier mapping (password access stays). |
85
+ | `vaults patreon status` | Show current configuration and tier mappings. |
86
+ | `vaults patreon clear` | Remove the entire Patreon configuration. |
87
+
88
+ You'll need to register a Patreon OAuth client at <https://www.patreon.com/portal/registration> and add `https://your-deploy-url/auth/patreon/callback` as a redirect URI before running `configure`.
62
89
 
63
90
  Run any command with `--help` for the full flag list.
64
91
 
@@ -71,18 +98,20 @@ Run any command with `--help` for the full flag list.
71
98
  vault_name: My Wiki
72
99
  default_role: public
73
100
  accent_color: "#7a4a8c"
74
- accent_color_dark: "#b58af5"
101
+ bg_color: "#1a1a2e"
75
102
  favicon: assets/icons/wiki.png
76
103
  inline_title: true
77
- default_image_width: 50vw
104
+ default_image_width: 300px
78
105
  center_images: true
106
+ auto_image: true
107
+ include_unknown_files: false
79
108
  ignore:
80
109
  - Templates/**
81
110
  - "*.draft.md"
82
111
  ---
83
112
  ```
84
113
 
85
- Open it in Obsidian; the frontmatter shows up as a Properties form.
114
+ Open it in Obsidian; the frontmatter shows up as a Properties form. Unknown keys are warned about and stripped on next push, so the file stays canonical. Auth config (roles, passwords, OAuth credentials) is **not** in `settings.md`; it lives in `.vaults/config.json` (with secrets in `.vaults/.env`) and is managed by the CLI.
86
115
 
87
116
  ## Page frontmatter
88
117
 
@@ -95,30 +124,119 @@ title: Optional override # default: filename or first H1
95
124
  aliases: # extra names that resolve to this page from wikilinks
96
125
  - Pale Mountains
97
126
  - The Pale Mountains
127
+ image: assets/banner.webp # optional cover image (OG / Twitter / Bases / Foundry)
128
+ foundry: # optional Foundry instantiation
129
+ base: Compendium.dnd5e.monsters.Actor.bandit # template UUID, OR Type[:subtype] for blank doc
130
+ data: # deep-merge overlay
131
+ system.attributes.hp.value: 22
98
132
  ---
99
133
  ```
100
134
 
101
135
  Wikilinks (`[[Page]]`, `[[Page|alias]]`, `[[NPCs/Page#section]]`), image embeds (`![[image.png]]`), transclusions (`![[Page]]`), and Obsidian callouts all render the same way they do in Obsidian.
102
136
 
137
+ ## Custom handlers
138
+
139
+ Vault authors can extend the renderer with custom inline-code and code-block transforms. Drop a Node ESM module into `.vaults/handlers/<name>.mjs` that exports a `handler` (or `handlers: Handler[]`); vaults-cli loads them at build time and runs them over every page.
140
+
141
+ - **Inline handler**: matches inline code like `` `prefix: content` ``.
142
+ - **Code-block handler**: matches fenced ` ```language ` blocks.
143
+
144
+ Both return either `{ markdown }` (re-processed through the rest of the pipeline) or `{ html }` (sanitized and inserted as-is).
145
+
146
+ ```js
147
+ // .vaults/handlers/seealso.mjs
148
+ export const handler = {
149
+ codeBlock: "seealso",
150
+ render: (content) => ({
151
+ markdown: content
152
+ .split(/\r?\n/)
153
+ .filter(Boolean)
154
+ .map((p) => `- [[${p.trim()}]]`)
155
+ .join("\n"),
156
+ }),
157
+ };
158
+ ```
159
+
160
+ ### Browser-side assets
161
+
162
+ If your handler needs to include browser-side JavaScript or CSS, declare them with the `assets` field. Paths are relative to the handler file. Every declared asset across all handlers is concatenated into one `_handlers.js` and one `_handlers.css` at the deploy root, deduped by absolute path so a shared utility file is only included once.
163
+
164
+ ```js
165
+ // .vaults/handlers/widget.mjs
166
+ export const handler = {
167
+ codeBlock: "widget",
168
+ assets: {
169
+ scripts: ["./widget.runtime.js"],
170
+ styles: ["./widget.css"],
171
+ },
172
+ render: (content) => ({
173
+ html: `<div class="widget" data-config="${content}"></div>`,
174
+ }),
175
+ };
176
+ ```
177
+
178
+ ```js
179
+ // .vaults/handlers/widget.runtime.js
180
+ (function () {
181
+ document.querySelectorAll('.widget').forEach((el) => {
182
+ // wire up el.dataset.config into something interactive
183
+ });
184
+ })();
185
+ ```
186
+
187
+ The deployed page references `/_handlers.js` (deferred) and `/_handlers.css`; the runtime then finds and hydrates the handler's HTML. Wrap your runtime in an IIFE to avoid global pollution.
188
+
189
+ **File-naming convention.** Handler module files end in `.mjs`. Browser-side runtime / CSS files end in `.js` / `.css`. The loader only treats `.mjs` files as handler modules; `.js` files in the same directory are picked up only if a handler's `assets.scripts` references them.
190
+
191
+ ### Built-ins
192
+
193
+ - **`dice:` (inline)** — `` `dice: 1d20+5` `` renders as a clickable button on the deploy that re-rolls on click. Mirrors [Obsidian Dice Roller](https://github.com/javalent/dice-roller) syntax.
194
+
195
+ User handlers can override built-ins of the same name. Trust model: handlers run with the same permissions as the rest of the build, so only run `vaults push` on vaults whose contents you trust.
196
+
103
197
  ## Auth
104
198
 
105
- Multi-role deploys ship with a small Cloudflare Pages Function (`_middleware.js`) that:
199
+ Multi-role deploys include with a small Cloudflare Pages Function (`_middleware.js`) that:
106
200
 
107
201
  - **Gates per-role variants** via a signed cookie (`SameSite=None; Secure; Partitioned`).
108
- - **Issues bearer tokens** through an OAuth-style `/connect` flow used by the [Foundry module](https://github.com/wizzlethorpe/vaults-foundry).
202
+ - **Issues bearer tokens** through an OAuth-style `/connect` flow used by the [Foundry module](https://github.com/wizzlethorpe/vaults).
203
+ - **Handles Patreon login** at `/auth/patreon/login` and `/auth/patreon/callback` when configured.
109
204
  - **Exposes** `/_batch` (text) and `/_batch-images` (binary) for bulk content sync.
205
+ - **Publishes** `/_manifest.json` with the deploy's name, role order, and auth requirements so external clients can probe the deploy before picking an auth flow.
110
206
 
111
207
  Tokens are stateless HMAC-signed JWTs; revocation = rotate `SESSION_SECRET` via `vaults push --rotate-secret`.
112
208
 
209
+ Single-role (public-only) deploys skip the middleware entirely; everything serves as plain static assets.
210
+
113
211
  ## Files this CLI manages locally
114
212
 
115
- | File | Tracked in git? | What it holds |
116
- |---|---|---|
117
- | `settings.md` | yes | User-editable settings. |
118
- | `.vaultrc.json` | **no** | CLI-managed: `SESSION_SECRET`, role password hashes, project name, cached settings. |
119
- | `.vault-cache/` | **no** | Build cache: rendered output, image webp cache. |
213
+ ```
214
+ MyVault/
215
+ ├── settings.md user-editable settings (Obsidian Properties UI)
216
+ ├── …content…
217
+ ├── .env ← secrets only (SESSION_SECRET, PATREON_CLIENT_SECRET) gitignored
218
+ └── .vaults/ ← all vaults-cli internal state lives here
219
+ ├── .gitignore ← keeps cache + config out of git automatically
220
+ ├── config.json ← CLI-managed: roles, password hashes, project name, Patreon config
221
+ ├── cache/ ← build cache (rendered HTML, image webp cache)
222
+ └── handlers/ ← optional: custom inline / code-block handlers
223
+ ```
224
+
225
+ `settings.md` lives at the vault root (and only there) so Obsidian renders it as an editable Properties form. Everything else is internal and tucked under `.vaults/`. `vaults init` writes `.vaults/.gitignore` automatically; if your vault is a git repo, this is enough to keep the cache + secrets-bearing config from being tracked.
226
+
227
+ ## Migrations
228
+
229
+ vaults-cli runs schema and layout migrations automatically before every `build` / `push` / `preview`. They're idempotent: already-migrated vaults pay only the cost of a few `stat()` calls.
230
+
231
+ To run them manually or inspect what would change:
232
+
233
+ ```bash
234
+ vaults migrate --list # show all known migrations
235
+ vaults migrate --dry-run # show what would apply on this vault
236
+ vaults migrate # apply pending migrations
237
+ ```
120
238
 
121
- `vaults init` adds `.vaultrc.json` and `.vault-cache` to `.gitignore` if your vault is a git repo.
239
+ If you're upgrading from a pre-0.7 vault, the first run of any command will move `.vaultrc.json` → `.vaults/config.json` and `.vault-cache/` `.vaults/cache/` and write a `.vaults/.gitignore`. Renames are atomic on the same filesystem so even large caches migrate instantly.
122
240
 
123
241
  ## License
124
242