@tokenoftrust/storefront-runner 2.0.32 → 2.0.33
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/apps/storefront/astro.config.mjs +8 -0
- package/package.json +1 -1
- package/packages/public-runtime/src/integration/contact-sales-action-source.ts +4 -2
- package/packages/public-runtime/src/integration/lifecycle-boot.ts +2 -1
- package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +18 -0
|
@@ -133,6 +133,14 @@ export default defineConfig({
|
|
|
133
133
|
"@astrojs/cloudflare/entrypoints/preview.js",
|
|
134
134
|
],
|
|
135
135
|
},
|
|
136
|
+
// The Cloudflare dev worker keeps its SSR module graph across Vite optimizer
|
|
137
|
+
// turns. Prebundle Preact's renderer before that graph is loaded so it never
|
|
138
|
+
// retains a URL for a superseded .vite/deps_ssr chunk.
|
|
139
|
+
ssr: {
|
|
140
|
+
optimizeDeps: {
|
|
141
|
+
include: ["@astrojs/preact/server.js"],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
136
144
|
// Dev-only: let the dev server accept tenant Host headers so host-based
|
|
137
145
|
// tenant routing can be tested locally (e.g. curl -H 'Host: sample-store.example').
|
|
138
146
|
// Prod runs on Cloudflare Workers, which has no such allowlist.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.33",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* selectors supplied by a caller, event detail, or arbitrary DOM data.
|
|
7
7
|
*/
|
|
8
8
|
import type { PlatformManagedActionActivation, PlatformManagedActionSource } from "./managed-analytics-bridge.js";
|
|
9
|
+
import { managedAnalyticsOpaqueRevision } from "./managed-analytics-value-safety.js";
|
|
9
10
|
|
|
10
11
|
/** The only reviewed CTA identities that may raise this marketing action. */
|
|
11
12
|
export const CONTACT_SALES_ACTION_SOURCES = [
|
|
@@ -42,6 +43,7 @@ export function createContactSalesActionSource(
|
|
|
42
43
|
): PlatformManagedActionSource {
|
|
43
44
|
const document = options.document;
|
|
44
45
|
const now = options.now ?? Date.now;
|
|
46
|
+
const revisionId = managedAnalyticsOpaqueRevision(options.planRevision);
|
|
45
47
|
let sequence = 0;
|
|
46
48
|
|
|
47
49
|
return {
|
|
@@ -55,10 +57,10 @@ export function createContactSalesActionSource(
|
|
|
55
57
|
sequence += 1;
|
|
56
58
|
const at = now();
|
|
57
59
|
const activation: PlatformManagedActionActivation = {
|
|
58
|
-
logicalId: `${source.logicalId}-${
|
|
60
|
+
logicalId: `${source.logicalId}-${revisionId}-${sequence}`,
|
|
59
61
|
name: CONTACT_SALES_ACTION_NAME,
|
|
60
62
|
correlation: {
|
|
61
|
-
id: `contact-sales-${
|
|
63
|
+
id: `contact-sales-${revisionId}`,
|
|
62
64
|
expiresAt: new Date(at + CORRELATION_TTL_MS).toISOString(),
|
|
63
65
|
},
|
|
64
66
|
sequence,
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
} from "./native-ga4-sandbox.js";
|
|
50
50
|
import { ManagedAnalyticsEventBrokerBridge } from "./managed-analytics-bridge.js";
|
|
51
51
|
import { minimizePageAttribution, type ManagedPageViewInput } from "./managed-analytics.js";
|
|
52
|
+
import { managedAnalyticsOpaqueRevision } from "./managed-analytics-value-safety.js";
|
|
52
53
|
import {
|
|
53
54
|
createContactSalesActionSource,
|
|
54
55
|
type ContactSalesActionDocument,
|
|
@@ -238,7 +239,7 @@ function documentPageView(
|
|
|
238
239
|
referrerUrl: win.document?.referrer ?? null,
|
|
239
240
|
routeUrl: win.location.href,
|
|
240
241
|
});
|
|
241
|
-
const id = `pageview-${descriptor.planRevision}`;
|
|
242
|
+
const id = `pageview-${managedAnalyticsOpaqueRevision(descriptor.planRevision)}`;
|
|
242
243
|
return {
|
|
243
244
|
logicalId: id,
|
|
244
245
|
path: win.location.pathname,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/** Shared PII-value canary for managed browser events and their diagnostics. */
|
|
2
2
|
import { MANAGED_ANALYTICS_PII_VALUE_PATTERN } from "./managed-analytics-api-v1-safety.mjs";
|
|
3
|
+
import { fnv1a128Hex } from "./digest.js";
|
|
3
4
|
|
|
4
5
|
const MANAGED_ANALYTICS_PII_VALUE = new RegExp(MANAGED_ANALYTICS_PII_VALUE_PATTERN);
|
|
5
6
|
const MANAGED_ANALYTICS_PROTECTED_VALUE =
|
|
6
7
|
/(?:@|\d{7,}|(?:^|[./_~-])(?:bearer|password|secret|token|authorization|preview)(?:$|[./_~-]))/i;
|
|
8
|
+
const OPAQUE_HEX_ALPHABET = "abcdefghijklmnop";
|
|
7
9
|
|
|
8
10
|
/** True when a public string resembles an email, SSN, payment card, or phone number. */
|
|
9
11
|
export function resemblesManagedAnalyticsPii(value: unknown): boolean {
|
|
@@ -17,6 +19,22 @@ export function resemblesManagedAnalyticsProtectedValue(value: unknown): boolean
|
|
|
17
19
|
);
|
|
18
20
|
}
|
|
19
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Derive a stable letters-only token for managed-event ids from a public revision.
|
|
24
|
+
*
|
|
25
|
+
* Revisions are hexadecimal content identities and can therefore contain a run of
|
|
26
|
+
* seven digits by chance. Copying one directly into an event id trips the deliberate
|
|
27
|
+
* phone/card canary and silently rejects an otherwise safe event. Hashing once more
|
|
28
|
+
* and encoding each nibble as `a`-`p` retains deterministic revision scoping while
|
|
29
|
+
* making a numeric/credential-looking result impossible by construction.
|
|
30
|
+
*/
|
|
31
|
+
export function managedAnalyticsOpaqueRevision(value: string): string {
|
|
32
|
+
return Array.from(
|
|
33
|
+
fnv1a128Hex(value),
|
|
34
|
+
(nibble) => OPAQUE_HEX_ALPHABET[Number.parseInt(nibble, 16)]!,
|
|
35
|
+
).join("");
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
/** Defense-in-depth for identifiers copied into structured broker observations. */
|
|
21
39
|
export function safeManagedAnalyticsDiagnosticId(value: string): string {
|
|
22
40
|
return resemblesManagedAnalyticsPii(value) ? "[redacted]" : value;
|