@strifeapp/astro 1.2.0 → 1.4.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/README.md +28 -4
- package/dist/Insights.astro +243 -0
- package/dist/edit-mode.js +21 -56
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{vite-plugin-strife-store-Tvau120y.js → vite-plugin-strife-store-B-B_HXbA.js} +13 -51
- package/dist/vite-plugin-strife-store-entry.js +1 -1
- package/dist/vite-plugin-strife-store.d.ts.map +1 -1
- package/package.json +6 -3
- package/dist/localized-content-index.js +0 -798
- package/dist/secrets-codec.d.ts +0 -54
- package/dist/secrets-codec.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Official [Strife](https://strife.app) integration for [Astro](https://astro.buil
|
|
|
10
10
|
- [Requirements](#requirements)
|
|
11
11
|
- [Usage](#usage)
|
|
12
12
|
- [Reading content](#reading-content)
|
|
13
|
+
- [Telemetry: `<Insights />`](#telemetry-insights)
|
|
13
14
|
- [TypeScript: typing `strife:store`](#typescript-typing-strifestore)
|
|
14
15
|
- [Direct Vite plugin](#direct-vite-plugin)
|
|
15
16
|
- [Configuration](#configuration)
|
|
@@ -68,14 +69,37 @@ Read from the store anywhere in your site through the `strife:store` virtual mod
|
|
|
68
69
|
import { store } from 'strife:store';
|
|
69
70
|
|
|
70
71
|
const session = store.openSession();
|
|
71
|
-
// The integration deploys a `
|
|
72
|
+
// The integration deploys a `Content/ByUrl` index for URL-based lookups.
|
|
72
73
|
const page = await session
|
|
73
|
-
.query({ indexName: '
|
|
74
|
+
.query({ indexName: 'Content/ByUrl' })
|
|
74
75
|
.whereEquals('url', Astro.url.pathname)
|
|
75
76
|
.firstOrNull();
|
|
76
77
|
---
|
|
77
78
|
```
|
|
78
79
|
|
|
80
|
+
### Telemetry: `<Insights />`
|
|
81
|
+
|
|
82
|
+
Drop-in Web Vitals + accessibility telemetry. Add it once to your layout `<head>`, the same way you'd add Astro's `<ClientRouter />`:
|
|
83
|
+
|
|
84
|
+
```astro
|
|
85
|
+
---
|
|
86
|
+
import Insights from '@strifeapp/astro/Insights.astro';
|
|
87
|
+
---
|
|
88
|
+
<head>
|
|
89
|
+
…
|
|
90
|
+
<Insights />
|
|
91
|
+
</head>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
On every page load it reports Core Web Vitals (LCP, INP, CLS, FCP, TTFB) and, when the browser is idle, an [axe-core](https://github.com/dequelabs/axe-core) accessibility audit (re-running on Astro View Transitions). Both are sent with `navigator.sendBeacon` to the hosted Strife insights API and stored as RavenDB time series on the page's content document. The beacon carries your **public team id** — resolved server-side from your Strife env, so no secret reaches the browser — letting the API attribute metrics to your workspace and validate the request against your registered domains.
|
|
95
|
+
|
|
96
|
+
| Prop | Type | Default | Description |
|
|
97
|
+
| --- | --- | --- | --- |
|
|
98
|
+
| `endpoint` | `string` | `https://api.strife.app/insights/collect` | Override the collection endpoint. |
|
|
99
|
+
| `accessibility` | `boolean` | `true` | Set `false` to skip the axe-core audit (Web Vitals still reported). |
|
|
100
|
+
|
|
101
|
+
> The API only stores a beacon when its `Origin` is one of the team's registered domains. For local development, run the API in `Development` and add `localhost` to your team's `Domains`.
|
|
102
|
+
|
|
79
103
|
### TypeScript: typing `strife:store`
|
|
80
104
|
|
|
81
105
|
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`):
|
|
@@ -168,11 +192,11 @@ On `astro:config:setup` the integration registers the `STRIFE_*` env schema and
|
|
|
168
192
|
|
|
169
193
|
1. Resolves configuration at runtime via `getSecret` (never baked into the bundle).
|
|
170
194
|
2. Connects to RavenDB using the resolved URLs, database, and client certificate.
|
|
171
|
-
3. Deploys a `
|
|
195
|
+
3. Deploys a `Content/ByUrl` multi-map index (`deploymentMode: 'Rolling'`) for URL-based content lookup.
|
|
172
196
|
4. Bulk-inserts the configured collections into the `Templates` collection.
|
|
173
197
|
5. Exposes the initialized RavenDB `DocumentStore` through the `strife:store` virtual module.
|
|
174
198
|
|
|
175
|
-
> The `
|
|
199
|
+
> 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.
|
|
176
200
|
|
|
177
201
|
## License
|
|
178
202
|
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Strife Insights — drop-in Web Vitals + accessibility telemetry.
|
|
4
|
+
*
|
|
5
|
+
* Add once to your layout <head>, the same way you'd add Astro's <ClientRouter />:
|
|
6
|
+
*
|
|
7
|
+
* ---
|
|
8
|
+
* import Insights from '@strifeapp/astro/Insights.astro';
|
|
9
|
+
* ---
|
|
10
|
+
* <head>…<Insights /></head>
|
|
11
|
+
*
|
|
12
|
+
* Real visitors report Core Web Vitals (LCP, INP, CLS, FCP, TTFB), batched into a
|
|
13
|
+
* single beacon when the page is backgrounded. The heavier axe-core accessibility
|
|
14
|
+
* audit runs ONLY inside the Strife live preview (edit mode), so axe-core is never
|
|
15
|
+
* downloaded or run by a real visitor. Both are beaconed to the central Strife
|
|
16
|
+
* insights endpoint and stored as time series, tagged by device class (mobile/desktop).
|
|
17
|
+
*
|
|
18
|
+
* The beacon carries a PUBLIC `site` id (this team's id, resolved server-side from
|
|
19
|
+
* the same Strife env the integration already reads) so the endpoint can attribute
|
|
20
|
+
* metrics to your workspace and validate the request Origin against your registered
|
|
21
|
+
* domains. No secret is ever exposed to the browser.
|
|
22
|
+
*/
|
|
23
|
+
// @ts-ignore — `astro:env/server` is a virtual module Astro provides in the
|
|
24
|
+
// consumer's runtime/build (see the integration's env schema).
|
|
25
|
+
import { getSecret } from 'astro:env/server';
|
|
26
|
+
import { decodeSecrets } from '@strifeapp/strife/secrets';
|
|
27
|
+
|
|
28
|
+
export interface Props {
|
|
29
|
+
/** Override the collection endpoint. Defaults to the hosted Strife API. */
|
|
30
|
+
endpoint?: string;
|
|
31
|
+
/** Set false to skip the axe-core accessibility audit (Web Vitals still reported). */
|
|
32
|
+
accessibility?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
endpoint = 'https://api.strife.app/insights/collect',
|
|
37
|
+
accessibility = true,
|
|
38
|
+
} = Astro.props;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolve this team's PUBLIC id from the same sources the integration reads: the
|
|
42
|
+
* consolidated STRIFE_SECRET blob (teamId), the legacy TEAM_ID env, or — last
|
|
43
|
+
* resort — the database name (`wieldy_{id}`). Returns null when no Strife env is
|
|
44
|
+
* configured, in which case the component renders nothing.
|
|
45
|
+
*/
|
|
46
|
+
function resolveSiteId(): string | null {
|
|
47
|
+
const blob = getSecret('STRIFE_SECRET');
|
|
48
|
+
if (blob) {
|
|
49
|
+
try {
|
|
50
|
+
const packed = decodeSecrets(blob);
|
|
51
|
+
if (packed?.teamId) return packed.teamId;
|
|
52
|
+
} catch {
|
|
53
|
+
// Malformed blob — fall through to the individual vars.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const teamId = getSecret('TEAM_ID');
|
|
57
|
+
if (teamId) return teamId;
|
|
58
|
+
const database = getSecret('STRIFE_DATABASE');
|
|
59
|
+
const match = database?.match(/^wieldy_(.+)$/);
|
|
60
|
+
return match ? match[1] : null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const site = resolveSiteId();
|
|
64
|
+
|
|
65
|
+
// `editMode` is true inside the Strife live preview (set by the edit-mode
|
|
66
|
+
// middleware). We split the work by audience: Web Vitals run only for REAL visitors
|
|
67
|
+
// (they need real-user device/network/interaction variance), while the heavy
|
|
68
|
+
// axe-core accessibility audit runs only in the editor's live preview — a11y is
|
|
69
|
+
// deterministic per content version, so the editor is the right place for it, and it
|
|
70
|
+
// keeps axe-core off every real visitor entirely. Without the middleware, editMode
|
|
71
|
+
// defaults to false, so plain sites get Web Vitals exactly as before.
|
|
72
|
+
const editMode = Astro.locals.editMode ?? false;
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
{site && (
|
|
76
|
+
<Fragment>
|
|
77
|
+
<script is:inline define:vars={{ site, endpoint, accessibility, editMode }}>
|
|
78
|
+
window.__strifeInsights = { site, endpoint, accessibility, editMode };
|
|
79
|
+
</script>
|
|
80
|
+
<script>
|
|
81
|
+
import { onLCP, onINP, onCLS, onFCP, onTTFB } from 'web-vitals';
|
|
82
|
+
|
|
83
|
+
const cfg = (window as any).__strifeInsights || {};
|
|
84
|
+
const ENDPOINT: string = cfg.endpoint;
|
|
85
|
+
const SITE: string = cfg.site;
|
|
86
|
+
const RUN_A11Y: boolean = cfg.accessibility !== false;
|
|
87
|
+
const EDIT_MODE: boolean = cfg.editMode === true;
|
|
88
|
+
|
|
89
|
+
/** Beacon a payload to the collection endpoint (fire-and-forget). */
|
|
90
|
+
function send(payload: Record<string, unknown>) {
|
|
91
|
+
const body = JSON.stringify({ site: SITE, ...payload });
|
|
92
|
+
try {
|
|
93
|
+
// Send as a plain string → text/plain, a CORS-safelisted content type.
|
|
94
|
+
// That keeps the cross-origin beacon a "simple request" (no preflight),
|
|
95
|
+
// so it is delivered from ANY registered custom domain — not just the
|
|
96
|
+
// origins in the API's global CORS list. The server parses the body
|
|
97
|
+
// itself; we never read the response, so CORS never blocks the write.
|
|
98
|
+
if (navigator.sendBeacon && navigator.sendBeacon(ENDPOINT, body)) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// Fall through to fetch.
|
|
103
|
+
}
|
|
104
|
+
// No JSON content-type header here either, so the fallback stays
|
|
105
|
+
// preflight-free (a string body defaults to text/plain).
|
|
106
|
+
fetch(ENDPOINT, {
|
|
107
|
+
method: 'POST',
|
|
108
|
+
body,
|
|
109
|
+
keepalive: true,
|
|
110
|
+
}).catch(() => {});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function sendAccessibilityMetrics(
|
|
114
|
+
metrics: Record<string, number>,
|
|
115
|
+
tag: string,
|
|
116
|
+
violations: unknown[],
|
|
117
|
+
) {
|
|
118
|
+
send({ page: window.location.pathname, metrics, tag, violations });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Collect the finalised Core Web Vitals and send them as ONE batched beacon when
|
|
122
|
+
// the page is backgrounded/unloaded — the standard web-vitals RUM pattern.
|
|
123
|
+
// (reportAllChanges defaults to false, so each metric reports once.) Far fewer
|
|
124
|
+
// beacons + time-series writes than reporting on every change.
|
|
125
|
+
function initWebVitals() {
|
|
126
|
+
const speed: string | undefined = (navigator as any).connection?.effectiveType;
|
|
127
|
+
// Tag each metric by device class so Experience scores can be sliced by device
|
|
128
|
+
// in the Studio — same convention the accessibility audit uses.
|
|
129
|
+
const tag = navigator.userAgent.includes('Mobile') ? 'mobile' : 'desktop';
|
|
130
|
+
const metrics: Record<string, number> = {};
|
|
131
|
+
const add = (m: { name: string; value: number }) => {
|
|
132
|
+
metrics[m.name] = m.value;
|
|
133
|
+
};
|
|
134
|
+
onLCP(add);
|
|
135
|
+
onINP(add);
|
|
136
|
+
onCLS(add);
|
|
137
|
+
onFCP(add);
|
|
138
|
+
onTTFB(add);
|
|
139
|
+
|
|
140
|
+
const flush = () => {
|
|
141
|
+
const names = Object.keys(metrics);
|
|
142
|
+
if (names.length === 0) return;
|
|
143
|
+
// Read the pathname at flush time, not at init time: on Astro View Transition
|
|
144
|
+
// sites the URL changes via soft nav without re-running initWebVitals, so this
|
|
145
|
+
// attributes the batch to the page actually being left rather than the first one.
|
|
146
|
+
const page = window.location.pathname;
|
|
147
|
+
const batch: Record<string, number> = {};
|
|
148
|
+
for (const name of names) {
|
|
149
|
+
batch[name] = metrics[name];
|
|
150
|
+
delete metrics[name]; // send each metric at most once across flushes
|
|
151
|
+
}
|
|
152
|
+
send({ page, metrics: batch, speed, tag });
|
|
153
|
+
};
|
|
154
|
+
addEventListener('visibilitychange', () => {
|
|
155
|
+
if (document.visibilityState === 'hidden') flush();
|
|
156
|
+
});
|
|
157
|
+
addEventListener('pagehide', flush);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function runAccessibilityAudit() {
|
|
161
|
+
try {
|
|
162
|
+
const axe = await import('axe-core');
|
|
163
|
+
const results = await axe.default.run(document, { resultTypes: ['violations'] });
|
|
164
|
+
|
|
165
|
+
const byImpact = { critical: 0, serious: 0, moderate: 0, minor: 0 };
|
|
166
|
+
for (const violation of results.violations) {
|
|
167
|
+
const impact = violation.impact as keyof typeof byImpact;
|
|
168
|
+
if (impact && impact in byImpact) byImpact[impact] += violation.nodes.length;
|
|
169
|
+
}
|
|
170
|
+
const total = byImpact.critical + byImpact.serious + byImpact.moderate + byImpact.minor;
|
|
171
|
+
const penalty =
|
|
172
|
+
byImpact.critical * 10 + byImpact.serious * 5 + byImpact.moderate * 2 + byImpact.minor * 1;
|
|
173
|
+
const score = Math.max(0, 100 - penalty);
|
|
174
|
+
|
|
175
|
+
// Compact, capped violation details for the "what's actually wrong" list.
|
|
176
|
+
// axe-core categories live in the `cat.*` tag (e.g. `cat.color` → `color`).
|
|
177
|
+
const details = results.violations
|
|
178
|
+
.map((v) => {
|
|
179
|
+
const cat = (v.tags || []).find((t: string) => t.indexOf('cat.') === 0);
|
|
180
|
+
const firstTarget = (v.nodes[0] as any)?.target;
|
|
181
|
+
return {
|
|
182
|
+
id: v.id,
|
|
183
|
+
impact: v.impact || 'minor',
|
|
184
|
+
category: cat ? cat.slice(4) : 'other',
|
|
185
|
+
help: v.help,
|
|
186
|
+
helpUrl: v.helpUrl,
|
|
187
|
+
count: v.nodes.length,
|
|
188
|
+
sample: Array.isArray(firstTarget) ? firstTarget.join(' ') : '',
|
|
189
|
+
};
|
|
190
|
+
})
|
|
191
|
+
.slice(0, 50);
|
|
192
|
+
|
|
193
|
+
sendAccessibilityMetrics(
|
|
194
|
+
{
|
|
195
|
+
A11Y_SCORE: score,
|
|
196
|
+
A11Y_VIOLATIONS: total,
|
|
197
|
+
A11Y_CRITICAL: byImpact.critical,
|
|
198
|
+
A11Y_SERIOUS: byImpact.serious,
|
|
199
|
+
A11Y_MODERATE: byImpact.moderate,
|
|
200
|
+
A11Y_MINOR: byImpact.minor,
|
|
201
|
+
},
|
|
202
|
+
navigator.userAgent.includes('Mobile') ? 'mobile' : 'desktop',
|
|
203
|
+
details,
|
|
204
|
+
);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
// Best-effort — accessibility metrics never break the page.
|
|
207
|
+
console.warn('[Insights] Accessibility audit failed:', error);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function scheduleAccessibilityAudit() {
|
|
212
|
+
if ('requestIdleCallback' in window) {
|
|
213
|
+
(window as any).requestIdleCallback(() => runAccessibilityAudit(), { timeout: 10000 });
|
|
214
|
+
} else {
|
|
215
|
+
setTimeout(runAccessibilityAudit, 3000);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Track audited pages to avoid duplicate audits on soft navigations.
|
|
220
|
+
const auditedPages = new Set<string>();
|
|
221
|
+
|
|
222
|
+
function auditOnce() {
|
|
223
|
+
if (!RUN_A11Y) return;
|
|
224
|
+
const path = window.location.pathname;
|
|
225
|
+
if (auditedPages.has(path)) return;
|
|
226
|
+
auditedPages.add(path);
|
|
227
|
+
scheduleAccessibilityAudit();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (EDIT_MODE) {
|
|
231
|
+
// In the Strife live preview: only the accessibility audit runs. The editor is
|
|
232
|
+
// the right place for the heavy axe-core scan (a11y is deterministic per content
|
|
233
|
+
// version), and it keeps axe-core off every real visitor.
|
|
234
|
+
auditOnce();
|
|
235
|
+
// Astro View Transitions: re-audit the newly loaded page.
|
|
236
|
+
document.addEventListener('astro:page-load', auditOnce);
|
|
237
|
+
} else {
|
|
238
|
+
// A real visitor: Web Vitals only, batched on pagehide. No axe-core download/run.
|
|
239
|
+
initWebVitals();
|
|
240
|
+
}
|
|
241
|
+
</script>
|
|
242
|
+
</Fragment>
|
|
243
|
+
)}
|
package/dist/edit-mode.js
CHANGED
|
@@ -1,71 +1,36 @@
|
|
|
1
|
-
import { getSecret as
|
|
2
|
-
import { jwtVerify as
|
|
3
|
-
|
|
4
|
-
|
|
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) {
|
|
1
|
+
import { getSecret as n } from "astro:env/server";
|
|
2
|
+
import { jwtVerify as c } from "jose";
|
|
3
|
+
import { decodeSecrets as o } from "@strifeapp/strife/secrets";
|
|
4
|
+
async function d(e, t, r) {
|
|
40
5
|
try {
|
|
41
|
-
const { payload:
|
|
6
|
+
const { payload: a } = await c(e, new TextEncoder().encode(t), {
|
|
42
7
|
algorithms: ["HS256"]
|
|
43
8
|
});
|
|
44
|
-
return
|
|
9
|
+
return a.workspace === r;
|
|
45
10
|
} catch {
|
|
46
11
|
return !1;
|
|
47
12
|
}
|
|
48
13
|
}
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
14
|
+
function i(e) {
|
|
15
|
+
if (e.blob)
|
|
51
16
|
try {
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
return { secret:
|
|
17
|
+
const t = o(e.blob);
|
|
18
|
+
if (t?.previewSecret && t.teamId)
|
|
19
|
+
return { secret: t.previewSecret, teamId: t.teamId };
|
|
55
20
|
} catch {
|
|
56
21
|
}
|
|
57
|
-
return
|
|
22
|
+
return e.envSecret && e.envTeamId ? { secret: e.envSecret, teamId: e.envTeamId } : null;
|
|
58
23
|
}
|
|
59
|
-
async function
|
|
60
|
-
const
|
|
61
|
-
if (!
|
|
62
|
-
const
|
|
63
|
-
blob:
|
|
64
|
-
envSecret:
|
|
65
|
-
envTeamId:
|
|
24
|
+
async function S(e) {
|
|
25
|
+
const t = e.url.searchParams.get("token");
|
|
26
|
+
if (!t) return !1;
|
|
27
|
+
const r = i({
|
|
28
|
+
blob: n("STRIFE_SECRET"),
|
|
29
|
+
envSecret: n("SECRET"),
|
|
30
|
+
envTeamId: n("TEAM_ID")
|
|
66
31
|
});
|
|
67
|
-
return
|
|
32
|
+
return r ? d(t, r.secret, r.teamId) : !1;
|
|
68
33
|
}
|
|
69
34
|
export {
|
|
70
|
-
|
|
35
|
+
S as editMode
|
|
71
36
|
};
|
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;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,
|
|
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,CAwDxF"}
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const s = "strife:store", o = "\0" + s;
|
|
6
|
-
function h(i) {
|
|
7
|
-
const n = d(import.meta.url), a = f(n), c = l(
|
|
8
|
-
u(a, "./localized-content-index.js"),
|
|
9
|
-
"utf-8"
|
|
10
|
-
), e = { ...i };
|
|
1
|
+
import a from "serialize-javascript";
|
|
2
|
+
const s = "strife:store", r = "\0" + s;
|
|
3
|
+
function n(o) {
|
|
4
|
+
const e = { ...o };
|
|
11
5
|
return delete e.certificate, delete e.password, {
|
|
12
6
|
name: "strife:store",
|
|
13
7
|
resolveId(t) {
|
|
14
8
|
if (t === s)
|
|
15
|
-
return
|
|
9
|
+
return r;
|
|
16
10
|
},
|
|
17
11
|
load(t) {
|
|
18
|
-
if (t ===
|
|
12
|
+
if (t === r)
|
|
19
13
|
return `
|
|
20
|
-
import { DocumentStore
|
|
14
|
+
import { DocumentStore } from "ravendb";
|
|
21
15
|
import { getSecret } from "astro:env/server";
|
|
22
16
|
|
|
23
|
-
const
|
|
24
|
-
const defaultConfig = ${r(e)};
|
|
17
|
+
const defaultConfig = ${a(e)};
|
|
25
18
|
|
|
26
|
-
// --- STRIFE_SECRET decode (keep in sync with
|
|
19
|
+
// --- STRIFE_SECRET decode (keep in sync with @strifeapp/strife/secrets; format v1.<meta>.<cert>) ---
|
|
27
20
|
function decodeStrifeSecrets(value) {
|
|
28
21
|
const sections = value.split('.');
|
|
29
22
|
if (sections.length !== 3) {
|
|
@@ -99,45 +92,14 @@ function h(i) {
|
|
|
99
92
|
authOptions || undefined,
|
|
100
93
|
).initialize();
|
|
101
94
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
this.additionalSources = {"Helper": indexMappingSource};
|
|
107
|
-
|
|
108
|
-
const collections = (defaultConfig.collections && defaultConfig.collections.length)
|
|
109
|
-
? defaultConfig.collections
|
|
110
|
-
: ['Posts'];
|
|
111
|
-
|
|
112
|
-
for (const collection of collections) {
|
|
113
|
-
const name = typeof collection === 'string' ? collection : collection.name;
|
|
114
|
-
this.map(name, function (doc) { return mapDocument(doc); });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
this.deploymentMode = 'Rolling';
|
|
118
|
-
this.searchEngineType = 'Lucene';
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
console.log('Deploying index...');
|
|
123
|
-
|
|
124
|
-
await store.executeIndex(new Content_ByUrl());
|
|
125
|
-
|
|
126
|
-
const bulkInsert = store.bulkInsert();
|
|
127
|
-
|
|
128
|
-
if (defaultConfig.collections && defaultConfig.collections.length) {
|
|
129
|
-
for (const collection of defaultConfig.collections) {
|
|
130
|
-
await bulkInsert.store(collection, 'templates/' + collection.name, { '@collection': 'Templates' });
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
await bulkInsert.finish();
|
|
135
|
-
|
|
95
|
+
// Content/ByUrl + templates are deployed by 'strife push' (the versioned,
|
|
96
|
+
// operator-controlled path). The store only connects and reads — Astro no
|
|
97
|
+
// longer deploys the index or seeds templates.
|
|
136
98
|
export { store };
|
|
137
99
|
`;
|
|
138
100
|
}
|
|
139
101
|
};
|
|
140
102
|
}
|
|
141
103
|
export {
|
|
142
|
-
|
|
104
|
+
n as v
|
|
143
105
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite-plugin-strife-store.d.ts","sourceRoot":"","sources":["../src/vite-plugin-strife-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"vite-plugin-strife-store.d.ts","sourceRoot":"","sources":["../src/vite-plugin-strife-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AAEzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAKlD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CA6G9E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strifeapp/astro",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Official Strife integration for Astro — connect your Astro site to a RavenDB-backed Strife content store via a strife:store virtual module.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astro-integration",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"import": "./dist/edit-mode-middleware.js"
|
|
41
41
|
},
|
|
42
42
|
"./LivePreview.astro": "./dist/LivePreview.astro",
|
|
43
|
+
"./Insights.astro": "./dist/Insights.astro",
|
|
43
44
|
"./vite-plugin-strife-store": "./dist/vite-plugin-strife-store-entry.js"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
@@ -59,11 +60,13 @@
|
|
|
59
60
|
"prepublishOnly": "npm run build"
|
|
60
61
|
},
|
|
61
62
|
"dependencies": {
|
|
62
|
-
"@strifeapp/strife": "^1.0
|
|
63
|
+
"@strifeapp/strife": "^1.1.0",
|
|
64
|
+
"axe-core": "^4.11.0",
|
|
63
65
|
"dotenv": "^17.2.3",
|
|
64
66
|
"jose": "^5.9.6",
|
|
65
67
|
"ravendb": "^7.1.4",
|
|
66
|
-
"serialize-javascript": "^
|
|
68
|
+
"serialize-javascript": "^7.0.5",
|
|
69
|
+
"web-vitals": "^5.1.0"
|
|
67
70
|
},
|
|
68
71
|
"devDependencies": {
|
|
69
72
|
"@types/serialize-javascript": "^5.0.4",
|