@strifeapp/astro 1.0.30-beta.0 → 1.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.
- package/LICENSE +15 -0
- package/README.md +144 -51
- package/dist/LivePreview.astro +17 -0
- package/dist/edit-mode-middleware.d.ts +9 -0
- package/dist/edit-mode-middleware.d.ts.map +1 -0
- package/dist/edit-mode-middleware.js +5 -0
- package/dist/edit-mode-token.d.ts +34 -0
- package/dist/edit-mode-token.d.ts.map +1 -0
- package/dist/edit-mode.d.ts +16 -0
- package/dist/edit-mode.d.ts.map +1 -0
- package/dist/edit-mode.js +71 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -10
- package/dist/localized-content-index.js +258 -47
- package/dist/secrets-codec.d.ts +54 -0
- package/dist/secrets-codec.d.ts.map +1 -0
- package/dist/vite-plugin-strife-store-Tvau120y.js +143 -0
- package/dist/vite-plugin-strife-store-entry.js +1 -1
- package/dist/vite-plugin-strife-store.d.ts.map +1 -1
- package/package.json +51 -18
- package/dist/vite-plugin-strife-store-DkxIFvv2.js +0 -89
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Strife
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
10
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
11
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
12
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
13
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
14
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
15
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,86 +1,179 @@
|
|
|
1
1
|
# @strifeapp/astro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@strifeapp/astro)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Official [Strife](https://strife.app) integration for [Astro](https://astro.build). It connects your Astro site to a Strife (RavenDB-backed) content store and exposes an initialized document store to your pages through a `strife:store` virtual module — resolved at runtime, so the same build runs against any environment and secrets are never baked into the bundle.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Contents
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- [Installation](#installation)
|
|
10
|
+
- [Requirements](#requirements)
|
|
11
|
+
- [Usage](#usage)
|
|
12
|
+
- [Reading content](#reading-content)
|
|
13
|
+
- [TypeScript: typing `strife:store`](#typescript-typing-strifestore)
|
|
14
|
+
- [Direct Vite plugin](#direct-vite-plugin)
|
|
15
|
+
- [Configuration](#configuration)
|
|
16
|
+
- [Environment variables](#environment-variables)
|
|
17
|
+
- [Generating `STRIFE_SECRET`](#generating-strife_secret)
|
|
18
|
+
- [Platform size limits](#platform-size-limits)
|
|
19
|
+
- [How it works](#how-it-works)
|
|
20
|
+
- [License](#license)
|
|
10
21
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
├── vite-plugin-strife-store-entry.ts # Entry point for standalone plugin export
|
|
16
|
-
├── env.ts # Environment variable loader
|
|
17
|
-
├── indexMapping.js # RavenDB index mapping functions (JavaScript!)
|
|
18
|
-
└── services/
|
|
19
|
-
└── ImageService.ts # Image service (needs implementation)
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx astro add @strifeapp/astro
|
|
20
26
|
```
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
Or install manually and add the integration to your config yourself:
|
|
23
29
|
|
|
24
30
|
```bash
|
|
25
|
-
npm install
|
|
26
|
-
npm run build
|
|
31
|
+
npm install @strifeapp/astro
|
|
27
32
|
```
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
## Requirements
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
- **Astro 5 or 6** — `astro` is a peer dependency (`^5.0.0 || ^6.0.0`). Astro 5+ is required because the integration uses [`astro:env`](https://docs.astro.build/en/guides/environment-variables/) for runtime-safe secret resolution.
|
|
37
|
+
- **Node 22.12+**.
|
|
38
|
+
- A **Strife / RavenDB content store** and a **client certificate** registered with it (PFX, any key type — RSA or ECDSA).
|
|
32
39
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- `STRIFE_DATABASE_URLS` - Comma-separated list of RavenDB URLs
|
|
36
|
-
- `STRIFE_DATABASE` - Database name
|
|
37
|
-
- `STRIFE_CERTIFICATE` - Base64-encoded PFX certificate (optional for development)
|
|
38
|
-
- `STRIFE_CERTIFICATE_PASSWORD` - Certificate password (optional for development)
|
|
40
|
+
`ravendb` is installed as a dependency; you do not need to install it yourself.
|
|
39
41
|
|
|
40
42
|
## Usage
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
Register the integration in your Astro config:
|
|
43
45
|
|
|
44
46
|
```typescript
|
|
45
47
|
import { defineConfig } from 'astro/config';
|
|
46
|
-
import
|
|
48
|
+
import strife from '@strifeapp/astro';
|
|
47
49
|
|
|
48
50
|
export default defineConfig({
|
|
49
51
|
integrations: [
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
urls: ['https://your-ravendb.com'],
|
|
52
|
+
strife({
|
|
53
|
+
// All fields are optional; environment variables take precedence (see Configuration).
|
|
54
|
+
urls: ['https://your-ravendb.example.com'],
|
|
53
55
|
database: 'your-database',
|
|
54
|
-
collections: [
|
|
55
|
-
{ name: 'Posts' },
|
|
56
|
-
{ name: 'Pages' },
|
|
57
|
-
],
|
|
56
|
+
collections: [{ name: 'Posts' }, { name: 'Pages' }],
|
|
58
57
|
}),
|
|
59
58
|
],
|
|
60
59
|
});
|
|
61
60
|
```
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
### Reading content
|
|
63
|
+
|
|
64
|
+
Read from the store anywhere in your site through the `strife:store` virtual module:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
---
|
|
68
|
+
import { store } from 'strife:store';
|
|
69
|
+
|
|
70
|
+
const session = store.openSession();
|
|
71
|
+
// The integration deploys a `Content_ByUrl` index for URL-based lookups.
|
|
72
|
+
const page = await session
|
|
73
|
+
.query({ indexName: 'Content_ByUrl' })
|
|
74
|
+
.whereEquals('url', Astro.url.pathname)
|
|
75
|
+
.firstOrNull();
|
|
76
|
+
---
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### TypeScript: typing `strife:store`
|
|
80
|
+
|
|
81
|
+
Typed ambient declarations for the `strife:store` virtual module are not bundled in this release. Until a typed surface is published, add your own declaration (e.g. in `src/env.d.ts`):
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
declare module 'strife:store' {
|
|
85
|
+
import type { DocumentStore } from 'ravendb';
|
|
86
|
+
export const store: DocumentStore;
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Direct Vite plugin
|
|
91
|
+
|
|
92
|
+
The underlying Vite plugin is also exported standalone:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { vitePluginStrifeStore } from '@strifeapp/astro/vite-plugin-strife-store';
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Configuration
|
|
99
|
+
|
|
100
|
+
`strife(options?)` accepts:
|
|
101
|
+
|
|
102
|
+
| Option | Type | Description |
|
|
103
|
+
| --- | --- | --- |
|
|
104
|
+
| `urls` | `string[]` | RavenDB server URLs. |
|
|
105
|
+
| `database` | `string` | Database name. |
|
|
106
|
+
| `collections` | `{ name: string }[]` | Collections to index (default: `Posts`). |
|
|
107
|
+
|
|
108
|
+
> **Credentials are not build-time options.** `certificate` and `password` are **not** accepted as integration options — passing them would bake the secret into the built bundle. Provide them at runtime via `STRIFE_SECRET` or the `STRIFE_CERTIFICATE` / `STRIFE_CERTIFICATE_PASSWORD` env vars (below). The integration strips any `certificate`/`password` it receives as options before generating the store module.
|
|
109
|
+
|
|
110
|
+
### Environment variables
|
|
111
|
+
|
|
112
|
+
The integration registers `STRIFE_*` as [`astro:env`](https://docs.astro.build/en/guides/environment-variables/) **server secret** variables, so you do not need `import 'dotenv/config'` or any other loader — just set them:
|
|
113
|
+
|
|
114
|
+
| Variable | Maps to |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `STRIFE_SECRET` | All of the below, packed into one value (see [Generating `STRIFE_SECRET`](#generating-strife_secret)) |
|
|
117
|
+
| `STRIFE_DATABASE_URLS` | `urls` (comma-separated) |
|
|
118
|
+
| `STRIFE_DATABASE` | `database` |
|
|
119
|
+
| `STRIFE_CERTIFICATE` | base64-encoded PFX (optional in development) |
|
|
120
|
+
| `STRIFE_CERTIFICATE_PASSWORD` | certificate password |
|
|
121
|
+
|
|
122
|
+
Set them in a local `.env` for development, or in your host's environment (Vercel project settings, Kubernetes secrets, etc.) for deployment. Because they are `astro:env` server secrets, they are **read at runtime via `getSecret` and never inlined into the built bundle**.
|
|
123
|
+
|
|
124
|
+
`STRIFE_SECRET` is a single, compact value that bundles the URLs, database, certificate, and password — convenient when one secret is easier to manage than four. It is **additive**: when set, each field it carries takes priority; when unset, the four individual variables work exactly as before.
|
|
125
|
+
|
|
126
|
+
**Resolution order, per field:** `STRIFE_SECRET` → individual `STRIFE_*` env var → non-secret integration option (`urls`/`database` only) → built-in default.
|
|
127
|
+
|
|
128
|
+
> Reading via `astro:env` (rather than `process.env`) is deliberate: in `astro dev`, Astro does **not** populate `process.env` from `.env`, so a `process.env`-based read would be empty locally. `astro:env`'s `getSecret` reads `.env` in dev and the host environment in production, with no extra setup.
|
|
129
|
+
|
|
130
|
+
### Generating `STRIFE_SECRET`
|
|
131
|
+
|
|
132
|
+
`STRIFE_SECRET` has the form `v1.<meta>.<cert>`: a version tag, your `urls`/`database`/`password` as base64url-encoded JSON, and your PFX certificate as base64url-encoded **raw bytes** (encoded once — ~33% smaller than embedding an already-base64 cert in JSON). The format is key-algorithm-agnostic: the same `STRIFE_SECRET` works whether the certificate inside is RSA or ECDSA.
|
|
133
|
+
|
|
134
|
+
The blob format is stable, so you can generate it yourself in a few lines: base64url-encode `JSON.stringify({ urls, database, password })`, base64url-encode the raw `.pfx` bytes, and join them as `v1.<meta>.<cert>`. Contributors working in the [repository](https://github.com/wieldyapp/wieldy) can use the bundled helper:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# password via env var (recommended)
|
|
138
|
+
STRIFE_PFX_PASSWORD='your-cert-password' node --experimental-strip-types \
|
|
139
|
+
scripts/pack-secrets.mjs \
|
|
140
|
+
--pfx ./client.pfx \
|
|
141
|
+
--urls https://your-ravendb.example.com \
|
|
142
|
+
--database your-database
|
|
143
|
+
|
|
144
|
+
# …or pipe the password instead of putting it in the environment
|
|
145
|
+
printf '%s' "$PFX_PW" | node --experimental-strip-types \
|
|
146
|
+
scripts/pack-secrets.mjs --pfx ./client.pfx --urls … --database … --password-stdin
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The password is read only from `STRIFE_PFX_PASSWORD` or `--password-stdin` — never a CLI flag, since process arguments are world-readable. The helper prints `STRIFE_SECRET=<blob>`; pipe it straight into your host's secret store rather than echoing it (it otherwise lands in shell history). `--experimental-strip-types` is unnecessary on Node ≥ 23.6 / 22.18. (The helper script ships with the repository, not the published package; a `strife secrets pack` CLI command is planned.)
|
|
150
|
+
|
|
151
|
+
### Platform size limits
|
|
152
|
+
|
|
153
|
+
The certificate dominates the value's size, and base64 of an encrypted PFX is incompressible — so a large certificate may not fit a platform's per-variable env limit. This is a property of the certificate, not of `STRIFE_SECRET` (the standalone `STRIFE_CERTIFICATE` has the same ceiling).
|
|
154
|
+
|
|
155
|
+
| Platform | Per-variable limit | A ~2 KB ECDSA cert (~1.8 KB blob) | A ~4 KB RSA-4096 cert (~5.5 KB blob) |
|
|
156
|
+
| --- | --- | --- | --- |
|
|
157
|
+
| Kubernetes secret | ~1 MiB | ✅ | ✅ |
|
|
158
|
+
| Vercel (serverless) | 64 KB total | ✅ | ✅ |
|
|
159
|
+
| Vercel (edge) / Cloudflare Workers | ~5 KB | ✅ | ❌ |
|
|
160
|
+
| Netlify build-time | 5,000 chars | ✅ | ❌ |
|
|
161
|
+
| AWS Lambda / Netlify Functions (SSR) | 256 chars / 4 KB total | ❌ | ❌ |
|
|
162
|
+
|
|
163
|
+
If you hit a limit, the fix is a **smaller certificate** — RavenDB authenticates clients by thumbprint, not key algorithm, so you can register a compact **ECDSA P-256** client certificate (≈1.2 KB PFX) and use it instead of an RSA-4096 one. No encoding change helps a large cert; a smaller key does.
|
|
64
164
|
|
|
65
|
-
|
|
66
|
-
2. **Deploys a search index** called `Content_ByUrl` for content search
|
|
67
|
-
3. **Indexes documents** from specified collections (default: Posts)
|
|
68
|
-
4. **Creates a virtual module** `strife:store` that exports the RavenDB DocumentStore
|
|
69
|
-
5. **Bulk inserts templates** into the Templates collection
|
|
165
|
+
## How it works
|
|
70
166
|
|
|
71
|
-
|
|
167
|
+
On `astro:config:setup` the integration registers the `STRIFE_*` env schema and a Vite plugin. When the `strife:store` module is first evaluated (at build for prerendered pages, at request time for SSR), the plugin:
|
|
72
168
|
|
|
73
|
-
|
|
169
|
+
1. Resolves configuration at runtime via `getSecret` (never baked into the bundle).
|
|
170
|
+
2. Connects to RavenDB using the resolved URLs, database, and client certificate.
|
|
171
|
+
3. Deploys a `Content_ByUrl` multi-map index (`deploymentMode: 'Rolling'`) for URL-based content lookup.
|
|
172
|
+
4. Bulk-inserts the configured collections into the `Templates` collection.
|
|
173
|
+
5. Exposes the initialized RavenDB `DocumentStore` through the `strife:store` virtual module.
|
|
74
174
|
|
|
75
|
-
|
|
76
|
-
2. Identifying variable names and function patterns
|
|
77
|
-
3. Extracting the embedded index mapping source code
|
|
78
|
-
4. Reconstructing TypeScript types from `.d.ts` files
|
|
79
|
-
5. Reverse engineering the build configuration
|
|
175
|
+
> The `Content_ByUrl` index is deployed with a bundled helper source (`localized-content-index.js`) that runs inside RavenDB's Jint engine. It is intentionally plain ES5 — do not transpile it.
|
|
80
176
|
|
|
81
|
-
##
|
|
177
|
+
## License
|
|
82
178
|
|
|
83
|
-
|
|
84
|
-
- [ ] Verify the build output matches the original
|
|
85
|
-
- [ ] Add tests
|
|
86
|
-
- [ ] Update version number if making changes
|
|
179
|
+
ISC © [Strife](https://strife.app)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Loads the Strife live-preview client (`@strifeapp/strife`) — but only when the
|
|
4
|
+
* request is an authenticated editor preview, i.e. `Astro.locals.editMode` is
|
|
5
|
+
* `true` (set by the edit-mode middleware). Place it once in your layout, the
|
|
6
|
+
* same way you'd add Astro's <ClientRouter />:
|
|
7
|
+
*
|
|
8
|
+
* ---
|
|
9
|
+
* import LivePreview from '@strifeapp/astro/LivePreview.astro';
|
|
10
|
+
* ---
|
|
11
|
+
* <head>…<LivePreview /></head>
|
|
12
|
+
*
|
|
13
|
+
* Normal visitors get nothing; the SDK chunk is fetched only in edit mode.
|
|
14
|
+
*/
|
|
15
|
+
const editMode = Astro.locals.editMode ?? false;
|
|
16
|
+
---
|
|
17
|
+
{editMode && <script>import '@strifeapp/strife';</script>}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MiddlewareHandler } from 'astro';
|
|
2
|
+
/**
|
|
3
|
+
* Sets `Astro.locals.editMode` on every request so pages can branch their SSR
|
|
4
|
+
* output (draft vs published). Registered automatically by the integration via
|
|
5
|
+
* `addMiddleware` (see src/index.ts); also exported for manual wiring if a
|
|
6
|
+
* consumer prefers to compose middleware explicitly.
|
|
7
|
+
*/
|
|
8
|
+
export declare const onRequest: MiddlewareHandler;
|
|
9
|
+
//# sourceMappingURL=edit-mode-middleware.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-mode-middleware.d.ts","sourceRoot":"","sources":["../src/edit-mode-middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAG/C;;;;;GAKG;AACH,eAAO,MAAM,SAAS,EAAE,iBAGvB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify a Strife preview (edit-mode) token.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `Strife.Security.Tokenizer.Verify` on the backend: an HS256 JWT
|
|
5
|
+
* signed with the team's secret, carrying a `workspace` claim equal to the
|
|
6
|
+
* team id. A valid signature AND a matching workspace claim means the request
|
|
7
|
+
* is an authenticated editor previewing THIS team's content.
|
|
8
|
+
*
|
|
9
|
+
* Pure (no Astro / `astro:env` imports) so it is unit-testable in isolation.
|
|
10
|
+
*
|
|
11
|
+
* Note: the backend signs with ASCII bytes; for ASCII secrets `TextEncoder`
|
|
12
|
+
* (UTF-8) produces identical bytes, so verification matches.
|
|
13
|
+
*/
|
|
14
|
+
export declare function verifyEditModeToken(token: string, secret: string, teamId: string): Promise<boolean>;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the (secret, teamId) pair used to verify a preview token, from either
|
|
17
|
+
* source the integration supports — blob first, then the legacy env vars:
|
|
18
|
+
*
|
|
19
|
+
* 1. the consolidated `STRIFE_SECRET` blob, when it packs `teamId` + `previewSecret`;
|
|
20
|
+
* 2. the legacy individual `SECRET` + `TEAM_ID` env vars (the older format).
|
|
21
|
+
*
|
|
22
|
+
* Falls through to (2) when the blob is absent, malformed, or does not carry the
|
|
23
|
+
* preview fields — mirroring the store's blob-first / individual-vars resolution.
|
|
24
|
+
* Pure (only `decodeSecrets`) so it is unit-testable in isolation.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveEditModeCreds(sources: {
|
|
27
|
+
blob?: string | null;
|
|
28
|
+
envSecret?: string | null;
|
|
29
|
+
envTeamId?: string | null;
|
|
30
|
+
}): {
|
|
31
|
+
secret: string;
|
|
32
|
+
teamId: string;
|
|
33
|
+
} | null;
|
|
34
|
+
//# sourceMappingURL=edit-mode-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-mode-token.d.ts","sourceRoot":"","sources":["../src/edit-mode-token.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiB5C"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve edit mode for the current request, server-side.
|
|
3
|
+
*
|
|
4
|
+
* Reads the `?token=` preview token from the URL and verifies it against the
|
|
5
|
+
* team's secret + id, resolved from EITHER the consolidated `STRIFE_SECRET`
|
|
6
|
+
* blob (when it packs `teamId` + `previewSecret`) OR the legacy individual
|
|
7
|
+
* `SECRET` + `TEAM_ID` env vars. Returns `false` for normal visitors (no token,
|
|
8
|
+
* bad token) and `true` for an authenticated Strife editor previewing this team:
|
|
9
|
+
*
|
|
10
|
+
* const edit = await editMode(Astro);
|
|
11
|
+
* { edit ? <DraftView /> : <PublishedView /> }
|
|
12
|
+
*/
|
|
13
|
+
export declare function editMode(astro: {
|
|
14
|
+
url: URL;
|
|
15
|
+
}): Promise<boolean>;
|
|
16
|
+
//# sourceMappingURL=edit-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit-mode.d.ts","sourceRoot":"","sources":["../src/edit-mode.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,wBAAsB,QAAQ,CAAC,KAAK,EAAE;IAAE,GAAG,EAAE,GAAG,CAAA;CAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAYpE"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { getSecret as c } from "astro:env/server";
|
|
2
|
+
import { jwtVerify as l } from "jose";
|
|
3
|
+
const m = "v1", f = /^[A-Za-z0-9_-]+$/;
|
|
4
|
+
class s extends Error {
|
|
5
|
+
constructor(e) {
|
|
6
|
+
super(`STRIFE_SECRET: ${e}`), this.name = "SecretsDecodeError";
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
function u(t) {
|
|
10
|
+
const e = t.split(".");
|
|
11
|
+
if (e.length !== 3)
|
|
12
|
+
throw new s(
|
|
13
|
+
`expected 3 dot-separated sections, got ${e.length}`
|
|
14
|
+
);
|
|
15
|
+
const [n, i, d] = e;
|
|
16
|
+
if (n !== m) {
|
|
17
|
+
if (/^v\d+$/.test(n)) return null;
|
|
18
|
+
throw new s("unrecognised format (missing version prefix)");
|
|
19
|
+
}
|
|
20
|
+
if (!f.test(i))
|
|
21
|
+
throw new s("meta section is not valid base64url");
|
|
22
|
+
if (!f.test(d))
|
|
23
|
+
throw new s("cert section is not valid base64url");
|
|
24
|
+
let o;
|
|
25
|
+
try {
|
|
26
|
+
o = JSON.parse(Buffer.from(i, "base64url").toString("utf8"));
|
|
27
|
+
} catch {
|
|
28
|
+
throw new s("meta section is not valid JSON");
|
|
29
|
+
}
|
|
30
|
+
if (typeof o != "object" || o === null || !Array.isArray(o.urls) || typeof o.database != "string")
|
|
31
|
+
throw new s("meta section missing required fields (urls, database)");
|
|
32
|
+
const r = o, a = {
|
|
33
|
+
urls: r.urls,
|
|
34
|
+
database: r.database,
|
|
35
|
+
certificate: Buffer.from(d, "base64url")
|
|
36
|
+
};
|
|
37
|
+
return r.password !== void 0 && (a.password = r.password), r.type !== void 0 && (a.type = r.type), r.teamId !== void 0 && (a.teamId = r.teamId), r.previewSecret !== void 0 && (a.previewSecret = r.previewSecret), a;
|
|
38
|
+
}
|
|
39
|
+
async function p(t, e, n) {
|
|
40
|
+
try {
|
|
41
|
+
const { payload: i } = await l(t, new TextEncoder().encode(e), {
|
|
42
|
+
algorithms: ["HS256"]
|
|
43
|
+
});
|
|
44
|
+
return i.workspace === n;
|
|
45
|
+
} catch {
|
|
46
|
+
return !1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function v(t) {
|
|
50
|
+
if (t.blob)
|
|
51
|
+
try {
|
|
52
|
+
const e = u(t.blob);
|
|
53
|
+
if (e?.previewSecret && e.teamId)
|
|
54
|
+
return { secret: e.previewSecret, teamId: e.teamId };
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
return t.envSecret && t.envTeamId ? { secret: t.envSecret, teamId: t.envTeamId } : null;
|
|
58
|
+
}
|
|
59
|
+
async function E(t) {
|
|
60
|
+
const e = t.url.searchParams.get("token");
|
|
61
|
+
if (!e) return !1;
|
|
62
|
+
const n = v({
|
|
63
|
+
blob: c("STRIFE_SECRET"),
|
|
64
|
+
envSecret: c("SECRET"),
|
|
65
|
+
envTeamId: c("TEAM_ID")
|
|
66
|
+
});
|
|
67
|
+
return n ? p(e, n.secret, n.teamId) : !1;
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
E as editMode
|
|
71
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,18 @@ export interface Collection {
|
|
|
11
11
|
name: string;
|
|
12
12
|
[key: string]: any;
|
|
13
13
|
}
|
|
14
|
+
declare global {
|
|
15
|
+
namespace App {
|
|
16
|
+
interface Locals {
|
|
17
|
+
/**
|
|
18
|
+
* `true` when the current request is an authenticated Strife editor
|
|
19
|
+
* previewing this team's content (a valid `?token=` was verified). Set on
|
|
20
|
+
* every request by the edit-mode middleware. Use it to branch SSR output,
|
|
21
|
+
* e.g. render draft vs published content.
|
|
22
|
+
*/
|
|
23
|
+
editMode?: boolean;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
14
27
|
export default function strifeIntegration(options?: IntegrationOptions): AstroIntegration;
|
|
15
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAI5C,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,GAAG,CAAC;QACZ,UAAU,MAAM;YACd;;;;;eAKG;YACH,QAAQ,CAAC,EAAE,OAAO,CAAC;SACpB;KACF;CACF;AAMD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,gBAAgB,CAsDxF"}
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,47 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { envField as e } from "astro/config";
|
|
2
|
+
import { v as c } from "./vite-plugin-strife-store-Tvau120y.js";
|
|
3
|
+
const i = {
|
|
3
4
|
type: "pfx"
|
|
4
5
|
};
|
|
5
|
-
function
|
|
6
|
+
function p(t) {
|
|
6
7
|
return {
|
|
7
8
|
name: "@strife/astro",
|
|
8
9
|
hooks: {
|
|
9
|
-
"astro:config:setup": ({ updateConfig:
|
|
10
|
-
const
|
|
11
|
-
...
|
|
10
|
+
"astro:config:setup": ({ updateConfig: r, addMiddleware: s }) => {
|
|
11
|
+
const n = {
|
|
12
|
+
...i,
|
|
12
13
|
...t ? Object.fromEntries(
|
|
13
|
-
Object.entries(t).filter(([,
|
|
14
|
+
Object.entries(t).filter(([, o]) => o != null)
|
|
14
15
|
) : {}
|
|
15
16
|
};
|
|
16
|
-
|
|
17
|
+
r({
|
|
18
|
+
env: {
|
|
19
|
+
schema: {
|
|
20
|
+
// Consolidated single-var secret (packs urls/database/certificate/password,
|
|
21
|
+
// plus teamId/previewSecret for edit-mode token verification).
|
|
22
|
+
// Resolved first, ahead of the individual vars below; see vite-plugin-strife-store.
|
|
23
|
+
STRIFE_SECRET: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
24
|
+
STRIFE_DATABASE_URLS: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
25
|
+
STRIFE_DATABASE: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
26
|
+
STRIFE_CERTIFICATE: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
27
|
+
STRIFE_CERTIFICATE_PASSWORD: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
28
|
+
// Legacy individual edit-mode token vars (the older format). editMode falls
|
|
29
|
+
// back to these when STRIFE_SECRET does not pack teamId/previewSecret.
|
|
30
|
+
SECRET: e.string({ context: "server", access: "secret", optional: !0 }),
|
|
31
|
+
TEAM_ID: e.string({ context: "server", access: "secret", optional: !0 })
|
|
32
|
+
}
|
|
33
|
+
},
|
|
17
34
|
vite: {
|
|
18
|
-
plugins: [n
|
|
35
|
+
plugins: [c(n)]
|
|
19
36
|
}
|
|
37
|
+
}), s({
|
|
38
|
+
entrypoint: "@strifeapp/astro/edit-mode-middleware",
|
|
39
|
+
order: "pre"
|
|
20
40
|
});
|
|
21
41
|
}
|
|
22
42
|
}
|
|
23
43
|
};
|
|
24
44
|
}
|
|
25
45
|
export {
|
|
26
|
-
|
|
46
|
+
p as default
|
|
27
47
|
};
|