fontdue-js 3.0.6 → 3.1.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/CHANGELOG.md +10 -0
- package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.d.ts +23 -0
- package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.js +62 -0
- package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.d.ts +25 -0
- package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.js +240 -0
- package/dist/__generated__/FeatureTestersIdQuery.graphql.d.ts +21 -0
- package/dist/__generated__/FeatureTestersIdQuery.graphql.js +344 -0
- package/dist/__generated__/FeatureTestersSlugQuery.graphql.d.ts +25 -0
- package/dist/__generated__/FeatureTestersSlugQuery.graphql.js +364 -0
- package/dist/__generated__/FeatureTesters_collection.graphql.d.ts +39 -0
- package/dist/__generated__/FeatureTesters_collection.graphql.js +145 -0
- package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.d.ts +2 -1
- package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.js +10 -4
- package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.d.ts +21 -0
- package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.js +86 -0
- package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.d.ts +25 -0
- package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.js +108 -0
- package/dist/__tests__/createFontdueFetch.test.js +128 -4
- package/dist/__tests__/highlight.test.js +141 -0
- package/dist/__tests__/middleware.test.js +132 -0
- package/dist/components/FeatureTester/FeatureTesterCard.d.ts +30 -0
- package/dist/components/FeatureTester/FeatureTesterCard.js +167 -0
- package/dist/components/FeatureTester/FeatureTesterElement.d.ts +19 -0
- package/dist/components/FeatureTester/FeatureTesterElement.js +42 -0
- package/dist/components/FeatureTester/FeatureTesters.d.ts +43 -0
- package/dist/components/FeatureTester/FeatureTesters.js +156 -0
- package/dist/components/FeatureTester/FeatureTesters.server.d.ts +9 -0
- package/dist/components/FeatureTester/FeatureTesters.server.js +40 -0
- package/dist/components/FeatureTester/FeatureTestersElement.d.ts +10 -0
- package/dist/components/FeatureTester/FeatureTestersElement.js +27 -0
- package/dist/components/FeatureTester/highlight.d.ts +19 -0
- package/dist/components/FeatureTester/highlight.js +71 -0
- package/dist/components/FeatureTester/index.d.ts +26 -0
- package/dist/components/FeatureTester/index.js +66 -0
- package/dist/components/FeatureTester/index.server.d.ts +7 -0
- package/dist/components/FeatureTester/index.server.js +30 -0
- package/dist/components/NodePasswordForm/NodePasswordFormElement.d.ts +3 -0
- package/dist/components/NodePasswordForm/NodePasswordFormElement.js +65 -0
- package/dist/components/NodePasswordForm/index.d.ts +16 -1
- package/dist/components/NodePasswordForm/index.js +30 -59
- package/dist/components/Root/index.js +2 -1
- package/dist/fontdue.css +145 -0
- package/dist/hooks/useFeatureTesterAutofit.d.ts +17 -0
- package/dist/hooks/useFeatureTesterAutofit.js +106 -0
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +16 -1
- package/dist/next/registerSingleTenantResolver.js +13 -1
- package/dist/next/tenant.d.ts +1 -0
- package/dist/next/tenant.js +27 -2
- package/dist/nodeAccess.d.ts +18 -0
- package/dist/nodeAccess.js +84 -0
- package/dist/preview/server.d.ts +1 -20
- package/dist/preview/server.js +16 -85
- package/dist/relay/environment.js +8 -2
- package/dist/relay/serverConfig.d.ts +3 -0
- package/dist/relay/serverConfig.js +22 -1
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.js +90 -7
- package/dist/server/middleware.d.ts +37 -0
- package/dist/server/middleware.js +144 -0
- package/package.json +8 -2
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Request-scoped Fontdue context for non-RSC server frameworks (Astro, React
|
|
2
|
+
// Router 7, TanStack Start). RSC apps (Next) don't use this — they drive the
|
|
3
|
+
// per-render config through React.cache (see ../relay/serverConfig.ts).
|
|
4
|
+
//
|
|
5
|
+
// fontdue-js carries two kinds of request-scoped state to every server fetch:
|
|
6
|
+
//
|
|
7
|
+
// - the admin *preview* token (reveals unpublished fonts), and
|
|
8
|
+
// - the visitor's per-collection *node-access* token (a collection they
|
|
9
|
+
// unlocked with a password).
|
|
10
|
+
//
|
|
11
|
+
// Both need the same plumbing: read a cookie, hold a header in ambient scope for
|
|
12
|
+
// the whole render so every fontdue-js fetch/preload forwards it with no per-call
|
|
13
|
+
// threading, and force the response out of any shared/CDN cache because it's now
|
|
14
|
+
// per-visitor. This module provides that machinery once and exposes three
|
|
15
|
+
// single-responsibility middlewares over it:
|
|
16
|
+
//
|
|
17
|
+
// - runWithPreview — forwards only the admin preview token.
|
|
18
|
+
// - runWithNodeAccess — forwards only the visitor's node-access token.
|
|
19
|
+
// - runWithFontdue — both, composed (runWithPreview ∘ runWithNodeAccess).
|
|
20
|
+
//
|
|
21
|
+
// Mount one of these in your framework's request middleware. A storefront that
|
|
22
|
+
// wants both features mounts the precomposed runWithFontdue:
|
|
23
|
+
//
|
|
24
|
+
// // Astro: src/middleware.ts
|
|
25
|
+
// export const onRequest = (ctx, next) => runWithFontdue(ctx.request, next);
|
|
26
|
+
//
|
|
27
|
+
// // React Router 7 (root route, with future.v8_middleware):
|
|
28
|
+
// export const middleware = [({ request }, next) => runWithFontdue(request, next)];
|
|
29
|
+
//
|
|
30
|
+
// They compose because they share one ambient store and each merges its slice
|
|
31
|
+
// onto whatever an outer middleware established — so nesting accumulates headers
|
|
32
|
+
// rather than clobbering. Mount only the ones you need; the unused cookie is
|
|
33
|
+
// simply never present.
|
|
34
|
+
//
|
|
35
|
+
// Requirement: AsyncLocalStorage must propagate from the install point into the
|
|
36
|
+
// render. That holds for in-process middleware — Node (Netlify Functions, the
|
|
37
|
+
// default SSR target), Deno (Netlify Edge), Bun. It does NOT hold when
|
|
38
|
+
// middleware runs in a separate runtime from the render (e.g. Astro with
|
|
39
|
+
// `edgeMiddleware: true`, where locals cross the boundary as a serialized
|
|
40
|
+
// header); mount the middleware in-process on those setups.
|
|
41
|
+
|
|
42
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
43
|
+
import { readPreviewToken, previewAuthHeaders } from '../preview/index.js';
|
|
44
|
+
import { nodeAccessHeadersFromCookie } from '../nodeAccess.js';
|
|
45
|
+
import { registerAmbientConfigResolver } from '../relay/serverConfig.js';
|
|
46
|
+
const ambientStore = new AsyncLocalStorage();
|
|
47
|
+
|
|
48
|
+
// Feed the ambient headers into fontdue-js's server config resolution. Returns
|
|
49
|
+
// undefined outside the context, so plain public requests are untouched.
|
|
50
|
+
registerAmbientConfigResolver(() => {
|
|
51
|
+
const store = ambientStore.getStore();
|
|
52
|
+
return store ? {
|
|
53
|
+
headers: store.headers
|
|
54
|
+
} : undefined;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/** Whether the current async context is an admin preview. */
|
|
58
|
+
export function isPreviewing() {
|
|
59
|
+
var _ambientStore$getStor;
|
|
60
|
+
return ((_ambientStore$getStor = ambientStore.getStore()) === null || _ambientStore$getStor === void 0 ? void 0 : _ambientStore$getStor.previewing) === true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Request-scoped Fontdue headers for the current async context (admin preview
|
|
65
|
+
* and/or the visitor's node-access token), or {} when there are none. Spread
|
|
66
|
+
* into a hand-rolled fetch you make inside a runWith* middleware; the fontdue-js
|
|
67
|
+
* fetch/preload helpers pick these up automatically and don't need it.
|
|
68
|
+
*/
|
|
69
|
+
export function ambientHeaders() {
|
|
70
|
+
var _ambientStore$getStor2;
|
|
71
|
+
return ((_ambientStore$getStor2 = ambientStore.getStore()) === null || _ambientStore$getStor2 === void 0 ? void 0 : _ambientStore$getStor2.headers) ?? {};
|
|
72
|
+
}
|
|
73
|
+
const NO_STORE = 'private, no-store';
|
|
74
|
+
|
|
75
|
+
// A per-visitor response (preview or an unlocked collection) must never be
|
|
76
|
+
// stored in or served from a shared/CDN cache.
|
|
77
|
+
function forceNoStore(response) {
|
|
78
|
+
response.headers.set('Cache-Control', NO_STORE);
|
|
79
|
+
response.headers.delete('Netlify-CDN-Cache-Control');
|
|
80
|
+
response.headers.delete('CDN-Cache-Control');
|
|
81
|
+
return response;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Run `next` with `patch` merged onto any ambient context an outer middleware
|
|
85
|
+
// already set, so runWithPreview ∘ runWithNodeAccess accumulate (headers union,
|
|
86
|
+
// previewing OR'd) instead of the inner call clobbering the outer.
|
|
87
|
+
function withAmbient(patch, next) {
|
|
88
|
+
const existing = ambientStore.getStore();
|
|
89
|
+
return Promise.resolve(ambientStore.run({
|
|
90
|
+
headers: {
|
|
91
|
+
...(existing === null || existing === void 0 ? void 0 : existing.headers),
|
|
92
|
+
...patch.headers
|
|
93
|
+
},
|
|
94
|
+
previewing: (existing === null || existing === void 0 ? void 0 : existing.previewing) === true || patch.previewing === true
|
|
95
|
+
}, next));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Run `next` (your framework's render/loader chain) with the request's admin
|
|
100
|
+
* preview token in ambient scope, then return its Response. While active, every
|
|
101
|
+
* fontdue-js server fetch forwards the token (reveals unpublished fonts) with no
|
|
102
|
+
* per-call plumbing; when previewing, the response is forced out of any
|
|
103
|
+
* shared/CDN cache. Public requests (no preview cookie) pass through untouched
|
|
104
|
+
* and stay fully cacheable. For the visitor password-unlock token use
|
|
105
|
+
* runWithNodeAccess; for both, runWithFontdue.
|
|
106
|
+
*/
|
|
107
|
+
export async function runWithPreview(request, next) {
|
|
108
|
+
const token = readPreviewToken(request.headers.get('cookie'));
|
|
109
|
+
if (!token) return next();
|
|
110
|
+
const response = await withAmbient({
|
|
111
|
+
headers: previewAuthHeaders(token),
|
|
112
|
+
previewing: true
|
|
113
|
+
}, next);
|
|
114
|
+
return forceNoStore(response);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Run `next` with the visitor's per-collection node-access token in ambient
|
|
119
|
+
* scope, then return its Response. The token is read from the first-party cookie
|
|
120
|
+
* the password form set; while active, every fontdue-js server fetch forwards it
|
|
121
|
+
* so a collection the visitor unlocked resolves for them. A request carrying an
|
|
122
|
+
* unlock is per-visitor, so its response is forced out of any shared/CDN cache —
|
|
123
|
+
* an unlocked render is never served to someone who hasn't unlocked. Requests
|
|
124
|
+
* with no node-access cookie pass through untouched and stay cacheable.
|
|
125
|
+
*/
|
|
126
|
+
export async function runWithNodeAccess(request, next) {
|
|
127
|
+
const headers = nodeAccessHeadersFromCookie(request.headers.get('cookie'));
|
|
128
|
+
if (Object.keys(headers).length === 0) return next();
|
|
129
|
+
const response = await withAmbient({
|
|
130
|
+
headers
|
|
131
|
+
}, next);
|
|
132
|
+
return forceNoStore(response);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The precomposed middleware most storefronts want: forwards the admin preview
|
|
137
|
+
* token AND the visitor's node-access token, each handled by its own
|
|
138
|
+
* single-responsibility middleware. Equivalent to nesting
|
|
139
|
+
* `runWithPreview(request, () => runWithNodeAccess(request, next))` — mount this
|
|
140
|
+
* in place of runWithPreview to get the password-unlock forwarding too.
|
|
141
|
+
*/
|
|
142
|
+
export async function runWithFontdue(request, next) {
|
|
143
|
+
return runWithPreview(request, () => runWithNodeAccess(request, next));
|
|
144
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fontdue-js",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "npm run relay && run-p build-js build-css build-ts",
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
"./preview": "./dist/preview/index.js",
|
|
87
87
|
"./preview/server": "./dist/preview/server.js",
|
|
88
88
|
"./server": "./dist/server/index.js",
|
|
89
|
+
"./server/middleware": "./dist/server/middleware.js",
|
|
89
90
|
"./next": "./dist/next/index.js",
|
|
90
91
|
"./next/config": "./dist/next/config.js",
|
|
91
92
|
"./next/revalidate": "./dist/next/revalidate.js",
|
|
@@ -101,6 +102,10 @@
|
|
|
101
102
|
"default": "./dist/components/CharacterViewer/index.js"
|
|
102
103
|
},
|
|
103
104
|
"./CustomerLoginForm": "./dist/components/CustomerLoginForm/index.js",
|
|
105
|
+
"./FeatureTesters": {
|
|
106
|
+
"react-server": "./dist/components/FeatureTester/FeatureTesters.server.js",
|
|
107
|
+
"default": "./dist/components/FeatureTester/FeatureTesters.js"
|
|
108
|
+
},
|
|
104
109
|
"./FontdueProvider": {
|
|
105
110
|
"react-server": "./dist/components/FontdueProvider/index.server.js",
|
|
106
111
|
"default": "./dist/components/FontdueProvider/index.js"
|
|
@@ -109,6 +114,7 @@
|
|
|
109
114
|
"react-server": "./dist/components/NewsletterSignup/index.server.js",
|
|
110
115
|
"default": "./dist/components/NewsletterSignup/index.js"
|
|
111
116
|
},
|
|
117
|
+
"./NodePasswordForm": "./dist/components/NodePasswordForm/index.js",
|
|
112
118
|
"./StoreModal": "./dist/components/StoreModal/index.js",
|
|
113
119
|
"./TestFontsForm": {
|
|
114
120
|
"react-server": "./dist/components/TestFontsForm/index.server.js",
|
|
@@ -128,4 +134,4 @@
|
|
|
128
134
|
"./useFont": "./dist/components/useFont.js",
|
|
129
135
|
"./useFontStyle": "./dist/components/useFont.js"
|
|
130
136
|
}
|
|
131
|
-
}
|
|
137
|
+
}
|