fontdue-js 3.4.1 → 3.5.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 +5 -0
- package/dist/__generated__/PrecartAddToCartMutation.graphql.d.ts +9 -1
- package/dist/__generated__/PrecartAddToCartMutation.graphql.js +1 -1
- package/dist/__generated__/StoreModalProductSummaryAddToCartMutation.graphql.d.ts +9 -1
- package/dist/__generated__/StoreModalProductSummaryAddToCartMutation.graphql.js +1 -1
- package/dist/__tests__/createFontdueFetch.test.js +16 -0
- package/dist/__tests__/networkFetch.test.js +38 -0
- package/dist/components/Cart/orderTracking.d.ts +22 -5
- package/dist/components/Cart/orderTracking.js +32 -13
- package/dist/components/Precart/index.js +3 -1
- package/dist/components/StoreModalProductSummary/index.js +3 -1
- package/dist/relay/environment.d.ts +2 -2
- package/dist/relay/environment.js +5 -6
- package/dist/server/index.js +6 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.js +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 3.5.0
|
|
2
|
+
|
|
3
|
+
- Adding to the cart now sends the buyer's analytics context (cookie consent, anonymous ID, Meta's `_fbp`/`_fbc`) with the request, the same way opening the cart already did. Fontdue records a "Product Added" event for each add and a "Checkout Started" event the first time the buyer submits their contact details in checkout.
|
|
4
|
+
- `createFontdueFetch` from `fontdue-js/server` now sends the `fontdue-client-version` header, so server-rendered requests report the package version to Fontdue the way browser requests already did.
|
|
5
|
+
|
|
1
6
|
## 3.4.1
|
|
2
7
|
|
|
3
8
|
- Fixed the standalone type tester dropping an axis slider when its `variable-settings` starting value is negative. `variable-settings="slnt -11"` was rejected as unparseable, so no slant slider appeared and nothing in the markup explained why. Any axis with a negative range was affected. Extra spaces between an axis and its value are tolerated now too.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
2
|
+
* @generated SignedSource<<74cae87a2fa5e1e7b1ee3b6482faabae>>
|
|
3
3
|
* @lightSyntaxTransform
|
|
4
4
|
* @nogrep
|
|
5
5
|
*/
|
|
@@ -10,6 +10,7 @@ export type CreateOrderItemsInput = {
|
|
|
10
10
|
licenseeIsBillingIdentity?: boolean | null;
|
|
11
11
|
orderVariableSelections?: ReadonlyArray<OrderVariableSelectionInput> | null;
|
|
12
12
|
skuIds: ReadonlyArray<string | null>;
|
|
13
|
+
tracking?: OrderTrackingInput | null;
|
|
13
14
|
};
|
|
14
15
|
export type LicenseSelectionInput = {
|
|
15
16
|
id?: string | null;
|
|
@@ -23,6 +24,13 @@ export type OrderVariableSelectionInput = {
|
|
|
23
24
|
orderVariableId: string;
|
|
24
25
|
orderVariableOptionId?: string | null;
|
|
25
26
|
};
|
|
27
|
+
export type OrderTrackingInput = {
|
|
28
|
+
analyticsConsent?: boolean | null;
|
|
29
|
+
anonymousId?: string | null;
|
|
30
|
+
fbc?: string | null;
|
|
31
|
+
fbp?: string | null;
|
|
32
|
+
url?: string | null;
|
|
33
|
+
};
|
|
26
34
|
export type PrecartAddToCartMutation$variables = {
|
|
27
35
|
input: CreateOrderItemsInput;
|
|
28
36
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @generated SignedSource<<
|
|
2
|
+
* @generated SignedSource<<fef9b63617978230edc13ef9b3412c2e>>
|
|
3
3
|
* @lightSyntaxTransform
|
|
4
4
|
* @nogrep
|
|
5
5
|
*/
|
|
@@ -10,6 +10,7 @@ export type CreateOrderItemsInput = {
|
|
|
10
10
|
licenseeIsBillingIdentity?: boolean | null;
|
|
11
11
|
orderVariableSelections?: ReadonlyArray<OrderVariableSelectionInput> | null;
|
|
12
12
|
skuIds: ReadonlyArray<string | null>;
|
|
13
|
+
tracking?: OrderTrackingInput | null;
|
|
13
14
|
};
|
|
14
15
|
export type LicenseSelectionInput = {
|
|
15
16
|
id?: string | null;
|
|
@@ -23,6 +24,13 @@ export type OrderVariableSelectionInput = {
|
|
|
23
24
|
orderVariableId: string;
|
|
24
25
|
orderVariableOptionId?: string | null;
|
|
25
26
|
};
|
|
27
|
+
export type OrderTrackingInput = {
|
|
28
|
+
analyticsConsent?: boolean | null;
|
|
29
|
+
anonymousId?: string | null;
|
|
30
|
+
fbc?: string | null;
|
|
31
|
+
fbp?: string | null;
|
|
32
|
+
url?: string | null;
|
|
33
|
+
};
|
|
26
34
|
export type StoreModalProductSummaryAddToCartMutation$variables = {
|
|
27
35
|
input: CreateOrderItemsInput;
|
|
28
36
|
};
|
|
@@ -245,6 +245,22 @@ describe('createFontdueFetch', () => {
|
|
|
245
245
|
expect(init.next).toBeUndefined();
|
|
246
246
|
});
|
|
247
247
|
});
|
|
248
|
+
describe('fontdue-client-version header', () => {
|
|
249
|
+
it('sends the package version, like the Relay layer does', async () => {
|
|
250
|
+
const fetchMock = mockFetch(() => ({
|
|
251
|
+
status: 200,
|
|
252
|
+
json: async () => ({
|
|
253
|
+
data: {}
|
|
254
|
+
})
|
|
255
|
+
}));
|
|
256
|
+
const fetchGraphql = createFontdueFetch({
|
|
257
|
+
url: 'https://acme.fontdue.com'
|
|
258
|
+
});
|
|
259
|
+
await fetchGraphql('Q', 'query Q { __typename }');
|
|
260
|
+
const init = fetchMock.mock.calls[0][1];
|
|
261
|
+
expect(init.headers['fontdue-client-version']).toBe('0.0.0-test');
|
|
262
|
+
});
|
|
263
|
+
});
|
|
248
264
|
describe('fontdue-preview header', () => {
|
|
249
265
|
it('sends "false" by default so a public/session-only request never reveals hidden fonts', async () => {
|
|
250
266
|
const fetchMock = mockFetch(() => ({
|
|
@@ -111,6 +111,44 @@ describe('createNetworkFetch (server)', () => {
|
|
|
111
111
|
function headersOf(fetchMock) {
|
|
112
112
|
return fetchMock.mock.calls[0][1].headers;
|
|
113
113
|
}
|
|
114
|
+
describe('createNetworkFetch (fontdue-client-version header)', () => {
|
|
115
|
+
// The server records this per tenant (Fontage.ClientVersions) to find sites
|
|
116
|
+
// that must upgrade before a client-dependent feature works for them.
|
|
117
|
+
it('sends the package version on every request', async () => {
|
|
118
|
+
vi.stubEnv('FONTDUE_URL', 'https://acme.fontdue.com');
|
|
119
|
+
const fetchMock = vi.fn(async () => ({
|
|
120
|
+
json: async () => ({
|
|
121
|
+
data: {}
|
|
122
|
+
})
|
|
123
|
+
}));
|
|
124
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
125
|
+
const {
|
|
126
|
+
createNetworkFetch,
|
|
127
|
+
version
|
|
128
|
+
} = await import("../relay/environment.js");
|
|
129
|
+
await createNetworkFetch()(request, {});
|
|
130
|
+
expect(version).toBe('0.0.0-test');
|
|
131
|
+
expect(headersOf(fetchMock)['fontdue-client-version']).toBe('0.0.0-test');
|
|
132
|
+
});
|
|
133
|
+
it('cannot be overridden by per-call headers', async () => {
|
|
134
|
+
vi.stubEnv('FONTDUE_URL', 'https://acme.fontdue.com');
|
|
135
|
+
const fetchMock = vi.fn(async () => ({
|
|
136
|
+
json: async () => ({
|
|
137
|
+
data: {}
|
|
138
|
+
})
|
|
139
|
+
}));
|
|
140
|
+
vi.stubGlobal('fetch', fetchMock);
|
|
141
|
+
const {
|
|
142
|
+
createNetworkFetch
|
|
143
|
+
} = await import("../relay/environment.js");
|
|
144
|
+
await createNetworkFetch({
|
|
145
|
+
headers: {
|
|
146
|
+
'fontdue-client-version': '9.9.9'
|
|
147
|
+
}
|
|
148
|
+
})(request, {});
|
|
149
|
+
expect(headersOf(fetchMock)['fontdue-client-version']).toBe('0.0.0-test');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
114
152
|
describe('createNetworkFetch (fontdue-preview header)', () => {
|
|
115
153
|
it('sends fontdue-preview: false on a public server fetch (no token)', async () => {
|
|
116
154
|
vi.stubEnv('FONTDUE_URL', 'https://acme.fontdue.com');
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
import { Environment } from 'relay-runtime';
|
|
2
|
+
export type OrderTrackingInput = {
|
|
3
|
+
analyticsConsent: boolean;
|
|
4
|
+
anonymousId?: string;
|
|
5
|
+
fbp?: string;
|
|
6
|
+
fbc?: string;
|
|
7
|
+
url: string;
|
|
8
|
+
};
|
|
2
9
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
10
|
+
* The buyer's analytics context as the order mutations take it: cookie
|
|
11
|
+
* consent, the anonymous ID, Meta's browser IDs (`_fbp`/`_fbc`) and the page.
|
|
12
|
+
* Sent with add-to-cart (`createOrderItems`) and cart/checkout open
|
|
13
|
+
* (`updateOrderTracking`) alike, so the server captures the same identifiers
|
|
14
|
+
* on every event it emits for the order — "Product Added", "Checkout Started"
|
|
15
|
+
* (which the server emits when the buyer submits their contact details, not
|
|
16
|
+
* from these calls) and the purchase, which fires from a Stripe webhook with
|
|
17
|
+
* no browser at all.
|
|
7
18
|
*
|
|
8
|
-
*
|
|
19
|
+
* Returns undefined outside a browser or if anything throws: tracking must
|
|
20
|
+
* never break the cart.
|
|
21
|
+
*/
|
|
22
|
+
export declare function orderTrackingInput(): OrderTrackingInput | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Stores the buyer's analytics context on the current order as the cart or
|
|
25
|
+
* checkout opens. Fire-and-forget: tracking must never break checkout.
|
|
9
26
|
*/
|
|
10
27
|
export declare function sendOrderTracking(environment: Environment): void;
|
|
@@ -5,27 +5,46 @@ function readCookie(name) {
|
|
|
5
5
|
const match = document.cookie.match(new RegExp('(?:^|;\\s*)' + name + '=([^;]*)'));
|
|
6
6
|
return match ? decodeURIComponent(match[1]) : undefined;
|
|
7
7
|
}
|
|
8
|
-
|
|
9
8
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* The buyer's analytics context as the order mutations take it: cookie
|
|
10
|
+
* consent, the anonymous ID, Meta's browser IDs (`_fbp`/`_fbc`) and the page.
|
|
11
|
+
* Sent with add-to-cart (`createOrderItems`) and cart/checkout open
|
|
12
|
+
* (`updateOrderTracking`) alike, so the server captures the same identifiers
|
|
13
|
+
* on every event it emits for the order — "Product Added", "Checkout Started"
|
|
14
|
+
* (which the server emits when the buyer submits their contact details, not
|
|
15
|
+
* from these calls) and the purchase, which fires from a Stripe webhook with
|
|
16
|
+
* no browser at all.
|
|
14
17
|
*
|
|
15
|
-
*
|
|
18
|
+
* Returns undefined outside a browser or if anything throws: tracking must
|
|
19
|
+
* never break the cart.
|
|
20
|
+
*/
|
|
21
|
+
export function orderTrackingInput() {
|
|
22
|
+
try {
|
|
23
|
+
if (typeof window === 'undefined') return undefined;
|
|
24
|
+
return {
|
|
25
|
+
analyticsConsent: hasConsent('analytics'),
|
|
26
|
+
anonymousId: getClientAnonymousId(),
|
|
27
|
+
fbp: readCookie('_fbp'),
|
|
28
|
+
fbc: readCookie('_fbc'),
|
|
29
|
+
url: window.location.href
|
|
30
|
+
};
|
|
31
|
+
} catch {
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Stores the buyer's analytics context on the current order as the cart or
|
|
38
|
+
* checkout opens. Fire-and-forget: tracking must never break checkout.
|
|
16
39
|
*/
|
|
17
40
|
export function sendOrderTracking(environment) {
|
|
41
|
+
const input = orderTrackingInput();
|
|
42
|
+
if (!input) return;
|
|
18
43
|
try {
|
|
19
44
|
commitMutation(environment, {
|
|
20
45
|
mutation: (_orderTrackingUpdateOrderTrackingMutation.hash && _orderTrackingUpdateOrderTrackingMutation.hash !== "d59a127a7f140424f507ae549731bac7" && console.error("The definition of 'orderTrackingUpdateOrderTrackingMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _orderTrackingUpdateOrderTrackingMutation),
|
|
21
46
|
variables: {
|
|
22
|
-
input
|
|
23
|
-
analyticsConsent: hasConsent('analytics'),
|
|
24
|
-
anonymousId: getClientAnonymousId(),
|
|
25
|
-
fbp: readCookie('_fbp'),
|
|
26
|
-
fbc: readCookie('_fbc'),
|
|
27
|
-
url: window.location.href
|
|
28
|
-
}
|
|
47
|
+
input
|
|
29
48
|
},
|
|
30
49
|
onCompleted: () => undefined,
|
|
31
50
|
onError: () => undefined
|
|
@@ -12,6 +12,7 @@ import License from './License.js';
|
|
|
12
12
|
import { Price } from '../Price/index.js';
|
|
13
13
|
import { pluralize } from '../../utils.js';
|
|
14
14
|
import ComponentsContext from '../ComponentsContext.js';
|
|
15
|
+
import { orderTrackingInput } from '../Cart/orderTracking.js';
|
|
15
16
|
function skuName(sku) {
|
|
16
17
|
if (sku.product && 'name' in sku.product) return sku.product.name;
|
|
17
18
|
return null;
|
|
@@ -153,7 +154,8 @@ function Precart(_ref3) {
|
|
|
153
154
|
const variables = {
|
|
154
155
|
input: {
|
|
155
156
|
skuIds: selectedItemsArray(),
|
|
156
|
-
licenseSelections: licenseSelectionsArray()
|
|
157
|
+
licenseSelections: licenseSelectionsArray(),
|
|
158
|
+
tracking: orderTrackingInput()
|
|
157
159
|
}
|
|
158
160
|
};
|
|
159
161
|
const mutation = (_PrecartAddToCartMutation.hash && _PrecartAddToCartMutation.hash !== "c5ead46ecc07099bee68d4f4f1ecb5bf" && console.error("The definition of 'PrecartAddToCartMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _PrecartAddToCartMutation);
|
|
@@ -11,6 +11,7 @@ import { pluralize } from '../../utils.js';
|
|
|
11
11
|
import { useLicenseAndOrderVariables } from '../../hooks/useLicenseAndOrderVariables.js';
|
|
12
12
|
import { useRefetchOnLicenseChanges } from '../../hooks/useRefetchOnLicenseChanges.js';
|
|
13
13
|
import ConfigContext from '../ConfigContext.js';
|
|
14
|
+
import { orderTrackingInput } from '../Cart/orderTracking.js';
|
|
14
15
|
const addToCartMutation = (_StoreModalProductSummaryAddToCartMutation.hash && _StoreModalProductSummaryAddToCartMutation.hash !== "91ea762e3842af2919da3a4c710a48cc" && console.error("The definition of 'StoreModalProductSummaryAddToCartMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalProductSummaryAddToCartMutation);
|
|
15
16
|
const clearCartMutation = (_StoreModalProductSummaryClearCartMutation.hash && _StoreModalProductSummaryClearCartMutation.hash !== "b5c37f74432030a297c1bcf2be63b6f7" && console.error("The definition of 'StoreModalProductSummaryClearCartMutation' appears to have changed. Run `relay-compiler` to update the generated files to receive the expected data."), _StoreModalProductSummaryClearCartMutation);
|
|
16
17
|
const countStyles = viewer => {
|
|
@@ -105,7 +106,8 @@ const StoreModalProductSummary = _ref => {
|
|
|
105
106
|
});
|
|
106
107
|
}, []),
|
|
107
108
|
orderVariableSelections,
|
|
108
|
-
licenseeIsBillingIdentity
|
|
109
|
+
licenseeIsBillingIdentity,
|
|
110
|
+
tracking: orderTrackingInput()
|
|
109
111
|
}
|
|
110
112
|
};
|
|
111
113
|
commitAddToCart({
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Environment, RequestParameters, QueryResponseCache, Variables, GraphQLResponse } from 'relay-runtime';
|
|
2
|
-
|
|
2
|
+
import { version } from '../version.js';
|
|
3
|
+
export { version };
|
|
3
4
|
export declare function fontdueBaseUrl(): string | undefined;
|
|
4
5
|
export declare function createNetworkFetch(options?: CreateRelayEnvironmentOptions): (request: RequestParameters, variables: Variables) => Promise<GraphQLResponse>;
|
|
5
6
|
export declare const networkFetch: (request: RequestParameters, variables: Variables) => Promise<GraphQLResponse>;
|
|
@@ -16,4 +17,3 @@ interface CreateRelayEnvironmentOptions {
|
|
|
16
17
|
}
|
|
17
18
|
export declare function createEnvironment(options: CreateRelayEnvironmentOptions): Environment;
|
|
18
19
|
export declare function useCurrentEnvironment(options: CreateRelayEnvironmentOptions): Environment;
|
|
19
|
-
export {};
|
|
@@ -3,12 +3,11 @@ import { handlePossibleCorsError } from '../corsError.js';
|
|
|
3
3
|
import { resolveFontdueServerConfig } from './serverConfig.js';
|
|
4
4
|
import { PREVIEW_HEADER, hasPreviewMarkerCookie } from '../preview/constants.js';
|
|
5
5
|
import { NODE_ACCESS_HEADER } from '../nodeAccess.js';
|
|
6
|
+
import { CLIENT_VERSION_HEADER, version } from '../version.js';
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
// build-time global in a 'use client' module.
|
|
11
|
-
export const version = "3.4.1";
|
|
8
|
+
// Re-exported so UI (the admin toolbar) can surface the package version
|
|
9
|
+
// without re-reading the build-time global in a 'use client' module.
|
|
10
|
+
export { version };
|
|
12
11
|
const IS_SERVER = typeof window === typeof undefined;
|
|
13
12
|
|
|
14
13
|
// Opt server fetches into Next's data cache only in production; dev stays
|
|
@@ -78,7 +77,7 @@ export function createNetworkFetch(options) {
|
|
|
78
77
|
Accept: 'application/json',
|
|
79
78
|
'Content-Type': 'application/json',
|
|
80
79
|
'fontdue-stripe-integration': (options === null || options === void 0 ? void 0 : options.stripeIntegration) ?? STRIPE_INTEGRATION ?? 'dynamic',
|
|
81
|
-
|
|
80
|
+
[CLIENT_VERSION_HEADER]: version
|
|
82
81
|
};
|
|
83
82
|
|
|
84
83
|
// Whether this request is an admin *preview*. On the server that's a
|
package/dist/server/index.js
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
import { resolveFontdueServerConfig, setFontdueServerConfig, resolveNodeAccessRecovery } from '../relay/serverConfig.js';
|
|
49
49
|
import { PREVIEW_HEADER } from '../preview/constants.js';
|
|
50
|
+
import { CLIENT_VERSION_HEADER, version } from '../version.js';
|
|
50
51
|
function readEnv(name) {
|
|
51
52
|
if (typeof process !== 'undefined' && process.env) {
|
|
52
53
|
const v = process.env[name];
|
|
@@ -146,7 +147,11 @@ export function createFontdueFetch() {
|
|
|
146
147
|
const headers = {
|
|
147
148
|
'content-type': 'application/json',
|
|
148
149
|
...(config === null || config === void 0 ? void 0 : config.headers),
|
|
149
|
-
...options.headers
|
|
150
|
+
...options.headers,
|
|
151
|
+
// Which fontdue-js this site runs – the server records it per tenant so
|
|
152
|
+
// sites that need to upgrade for a feature can be found and warned.
|
|
153
|
+
// Set last so a caller's headers can't misreport it.
|
|
154
|
+
[CLIENT_VERSION_HEADER]: version
|
|
150
155
|
};
|
|
151
156
|
|
|
152
157
|
// Declare preview intent explicitly: a forwarded admin token means this is a
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// `__FONTDUE_JS_VERSION__` is replaced by an inline babel plugin
|
|
2
|
+
// (defineVersionPlugin in .babelrc.cjs) with the literal package.json#version;
|
|
3
|
+
// the CDN bundle gets the same literal from vite.config.ts `define`.
|
|
4
|
+
//
|
|
5
|
+
// Every GraphQL request sends it as the `fontdue-client-version` header
|
|
6
|
+
// (relay/environment.ts, server/index.ts, and the script-tag bootstrap in
|
|
7
|
+
// assets/fontdue/index.tsx). The server records the version per tenant
|
|
8
|
+
// (Fontage.ClientVersions) to spot sites that need to upgrade before a
|
|
9
|
+
// feature that depends on a newer client can work for them.
|
|
10
|
+
export const CLIENT_VERSION_HEADER = 'fontdue-client-version';
|
|
11
|
+
export const version = "3.5.0";
|