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.
Files changed (61) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.d.ts +23 -0
  3. package/dist/__generated__/FeatureTesterCard_fontStyle.graphql.js +62 -0
  4. package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.d.ts +25 -0
  5. package/dist/__generated__/FeatureTesterStandaloneQuery.graphql.js +240 -0
  6. package/dist/__generated__/FeatureTestersIdQuery.graphql.d.ts +21 -0
  7. package/dist/__generated__/FeatureTestersIdQuery.graphql.js +344 -0
  8. package/dist/__generated__/FeatureTestersSlugQuery.graphql.d.ts +25 -0
  9. package/dist/__generated__/FeatureTestersSlugQuery.graphql.js +364 -0
  10. package/dist/__generated__/FeatureTesters_collection.graphql.d.ts +39 -0
  11. package/dist/__generated__/FeatureTesters_collection.graphql.js +145 -0
  12. package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.d.ts +2 -1
  13. package/dist/__generated__/NodePasswordFormAccessNodeMutation.graphql.js +10 -4
  14. package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.d.ts +21 -0
  15. package/dist/__generated__/NodePasswordFormElementIDQuery.graphql.js +86 -0
  16. package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.d.ts +25 -0
  17. package/dist/__generated__/NodePasswordFormElementSlugQuery.graphql.js +108 -0
  18. package/dist/__tests__/createFontdueFetch.test.js +128 -4
  19. package/dist/__tests__/highlight.test.js +141 -0
  20. package/dist/__tests__/middleware.test.js +132 -0
  21. package/dist/components/FeatureTester/FeatureTesterCard.d.ts +30 -0
  22. package/dist/components/FeatureTester/FeatureTesterCard.js +167 -0
  23. package/dist/components/FeatureTester/FeatureTesterElement.d.ts +19 -0
  24. package/dist/components/FeatureTester/FeatureTesterElement.js +42 -0
  25. package/dist/components/FeatureTester/FeatureTesters.d.ts +43 -0
  26. package/dist/components/FeatureTester/FeatureTesters.js +156 -0
  27. package/dist/components/FeatureTester/FeatureTesters.server.d.ts +9 -0
  28. package/dist/components/FeatureTester/FeatureTesters.server.js +40 -0
  29. package/dist/components/FeatureTester/FeatureTestersElement.d.ts +10 -0
  30. package/dist/components/FeatureTester/FeatureTestersElement.js +27 -0
  31. package/dist/components/FeatureTester/highlight.d.ts +19 -0
  32. package/dist/components/FeatureTester/highlight.js +71 -0
  33. package/dist/components/FeatureTester/index.d.ts +26 -0
  34. package/dist/components/FeatureTester/index.js +66 -0
  35. package/dist/components/FeatureTester/index.server.d.ts +7 -0
  36. package/dist/components/FeatureTester/index.server.js +30 -0
  37. package/dist/components/NodePasswordForm/NodePasswordFormElement.d.ts +3 -0
  38. package/dist/components/NodePasswordForm/NodePasswordFormElement.js +65 -0
  39. package/dist/components/NodePasswordForm/index.d.ts +16 -1
  40. package/dist/components/NodePasswordForm/index.js +30 -59
  41. package/dist/components/Root/index.js +2 -1
  42. package/dist/fontdue.css +145 -0
  43. package/dist/hooks/useFeatureTesterAutofit.d.ts +17 -0
  44. package/dist/hooks/useFeatureTesterAutofit.js +106 -0
  45. package/dist/next/index.d.ts +2 -0
  46. package/dist/next/index.js +16 -1
  47. package/dist/next/registerSingleTenantResolver.js +13 -1
  48. package/dist/next/tenant.d.ts +1 -0
  49. package/dist/next/tenant.js +27 -2
  50. package/dist/nodeAccess.d.ts +18 -0
  51. package/dist/nodeAccess.js +84 -0
  52. package/dist/preview/server.d.ts +1 -20
  53. package/dist/preview/server.js +16 -85
  54. package/dist/relay/environment.js +8 -2
  55. package/dist/relay/serverConfig.d.ts +3 -0
  56. package/dist/relay/serverConfig.js +22 -1
  57. package/dist/server/index.d.ts +8 -0
  58. package/dist/server/index.js +90 -7
  59. package/dist/server/middleware.d.ts +37 -0
  60. package/dist/server/middleware.js +144 -0
  61. 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.6",
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
+ }