@valbuild/shared 0.148.0 → 0.148.3
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 +64 -0
- package/client/dist/valbuild-shared-client.cjs.dev.js +1 -1
- package/client/dist/valbuild-shared-client.cjs.prod.js +1 -1
- package/client/dist/valbuild-shared-client.esm.js +1 -1
- package/dist/declarations/src/internal/ApiRoutes.d.ts +39 -0
- package/dist/declarations/src/internal/demo.d.ts +76 -0
- package/dist/{getSitemapTree-109be3b8.cjs.prod.js → getSitemapTree-40d76bf8.cjs.prod.js} +1 -1
- package/dist/{getSitemapTree-f6254b32.cjs.dev.js → getSitemapTree-a7f2cc6d.cjs.dev.js} +1 -1
- package/dist/{getSitemapTree-c70ea145.esm.js → getSitemapTree-cd006a36.esm.js} +1 -1
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +113 -11
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +113 -11
- package/internal/dist/valbuild-shared-internal.esm.js +114 -13
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,69 @@
|
|
|
1
1
|
# @valbuild/shared
|
|
2
2
|
|
|
3
|
+
## 0.148.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#881](https://github.com/valbuild/val/pull/881) [`0139436`](https://github.com/valbuild/val/commit/0139436426142d91cbb29ec6c696dfb86f34ab9d) Thanks [@freekh](https://github.com/freekh)! - The content analytics script. With analytics on (it is off by default, and turned on in a hosted project's settings), a TanStack site counts which content each visitor's page **rendered** and which they actually **viewed** (at least half on screen for a second), and sends it to `/api/val/analytics`.
|
|
8
|
+
|
|
9
|
+
- No cookies, no storage, no visitor IDs. Each page view also says where it came from (the referring site's host and any `utm_source` / `utm_medium` / `utm_campaign`) and whether it was a phone, tablet or desktop.
|
|
10
|
+
- A page is sent as its route's pattern (`/posts/$postId`), never its address, so a path that holds something about one visitor (an order number, a token) is never stored. `startValAnalytics` takes this as `routeFor`; `ValProvider` passes TanStack's matched route.
|
|
11
|
+
- Editors are never counted: nothing is sent in draft mode, in the Studio, with Val enabled, or at a proposal's address, and nothing from automated browsers. A page the browser prerenders counts nothing until it is shown.
|
|
12
|
+
- The script is the new `@valbuild/react/analytics` entry, loaded only for visitors of a site with analytics on, after the page has hydrated. It imports nothing else from Val.
|
|
13
|
+
- Storing the counts and showing them is part of Val's hosting, which takes these beacons before they reach the site. Anywhere else, `/api/val/analytics` checks each beacon and stores nothing; in local development, with `VAL_DEBUG=1`, it logs a line per beacon, so you can see it working.
|
|
14
|
+
- `ValProvider`'s Studio check now matches `/val` and what is below it only, not every route starting with those letters (`/values`). The same fix is in `@valbuild/next`.
|
|
15
|
+
|
|
16
|
+
- [#896](https://github.com/valbuild/val/pull/896) [`5eff8a0`](https://github.com/valbuild/val/commit/5eff8a055a4ef50d476797c28f9c3e50deb73c89) Thanks [@freekh](https://github.com/freekh)! - A demo's tour can now be written by the site: `<ValApp demo={{ tour }}>`, with each step as data (`ValDemoTourStep`), so what it says changes with the site rather than with a Val release.
|
|
17
|
+
|
|
18
|
+
It is drawn as a ring around what a step is about, with nothing dimmed and the Studio usable underneath, and a step can move on by itself once the visitor has done what it asks:
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
const tour: ValDemoTourStep[] = [
|
|
22
|
+
{
|
|
23
|
+
id: "click",
|
|
24
|
+
title: "This is Val",
|
|
25
|
+
body: "Click the heading on the page.",
|
|
26
|
+
target: "canvas",
|
|
27
|
+
page: HEADING, // outlined on the page
|
|
28
|
+
moveOn: { open: HEADING },
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: "type",
|
|
32
|
+
title: "Change a word",
|
|
33
|
+
body: "The page changes as you type.",
|
|
34
|
+
field: HEADING, // ringed wherever the field is shown
|
|
35
|
+
moveOn: {
|
|
36
|
+
edit: true,
|
|
37
|
+
path: HEADING,
|
|
38
|
+
value: "Coffee, roasted this weekend",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
A step that moves on has **Do it for me**, which does it the way the Studio would, and **Skip**. On a phone the card is a sheet along the bottom. The Studio's own tour is unchanged.
|
|
45
|
+
|
|
46
|
+
## 0.148.2
|
|
47
|
+
|
|
48
|
+
### Patch Changes
|
|
49
|
+
|
|
50
|
+
- [#889](https://github.com/valbuild/val/pull/889) [`dc7c8cc`](https://github.com/valbuild/val/commit/dc7c8ccd82f643e662d00225fabec411b5d39e3a) Thanks [@freekh](https://github.com/freekh)! - Val is quieter in your app's console. Errors and warnings you can act on still
|
|
51
|
+
print, now prefixed with `[val]` so you can filter them. Val's own debug
|
|
52
|
+
output, which used to reach your terminal and browser console, is now off by
|
|
53
|
+
default. That includes the `Invalid JWT` line that printed on every request
|
|
54
|
+
with an expired session cookie, the "verifying draft mode" and polling notices,
|
|
55
|
+
and the Studio's sync and WebSocket chatter.
|
|
56
|
+
|
|
57
|
+
To turn the debug output back on, for example when reporting a bug:
|
|
58
|
+
|
|
59
|
+
- on the server, set `VAL_DEBUG=1`
|
|
60
|
+
- in the browser, run `localStorage.setItem("val:debug", "1")` in the console.
|
|
61
|
+
It takes effect immediately, with no reload. Remove the key to turn it off
|
|
62
|
+
again.
|
|
63
|
+
|
|
64
|
+
- Updated dependencies [[`dc7c8cc`](https://github.com/valbuild/val/commit/dc7c8ccd82f643e662d00225fabec411b5d39e3a)]:
|
|
65
|
+
- @valbuild/core@0.148.2
|
|
66
|
+
|
|
3
67
|
## 0.148.0
|
|
4
68
|
|
|
5
69
|
### Patch Changes
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { D as DEFAULT_CANVAS_SELECTION, e as DEFAULT_CANVAS_SELECTION_SOFT, b as VAL_AI_SESSION_STORAGE_KEY, d as VAL_CANVAS_MESSAGE, c as VAL_CANVAS_PARAM, V as VAL_CONFIG_SESSION_STORAGE_KEY, a as VAL_THEME_SESSION_STORAGE_KEY, h as formatRoutePattern, j as getNextAppRouterSourceFolder, n as getPageRouterSitemapTree, l as getPageRouterSourceFolder, o as getPatternFromModuleFilePath, k as getTanStackRouterSourceFolder, m as isTanStackRoutesFolder, g as isValCanvasFrame, i as isValCanvasPageMessage, f as isValCanvasStudioMessage, p as parseRoutePattern, w as withValCanvasParam } from '../../dist/getSitemapTree-
|
|
1
|
+
export { D as DEFAULT_CANVAS_SELECTION, e as DEFAULT_CANVAS_SELECTION_SOFT, b as VAL_AI_SESSION_STORAGE_KEY, d as VAL_CANVAS_MESSAGE, c as VAL_CANVAS_PARAM, V as VAL_CONFIG_SESSION_STORAGE_KEY, a as VAL_THEME_SESSION_STORAGE_KEY, h as formatRoutePattern, j as getNextAppRouterSourceFolder, n as getPageRouterSitemapTree, l as getPageRouterSourceFolder, o as getPatternFromModuleFilePath, k as getTanStackRouterSourceFolder, m as isTanStackRoutesFolder, g as isValCanvasFrame, i as isValCanvasPageMessage, f as isValCanvasStudioMessage, p as parseRoutePattern, w as withValCanvasParam } from '../../dist/getSitemapTree-cd006a36.esm.js';
|
|
2
2
|
import '@valbuild/core';
|
|
@@ -45,6 +45,27 @@ type CookieValue = EnableCookieValue | {
|
|
|
45
45
|
* this. Shared so client and server agree on the limit.
|
|
46
46
|
*/
|
|
47
47
|
export declare const JSON_ENTRIES_BATCH_MAX = 100;
|
|
48
|
+
export declare const AnalyticsBeacon: z.ZodObject<{
|
|
49
|
+
v: z.ZodLiteral<1>;
|
|
50
|
+
route: z.ZodString;
|
|
51
|
+
cv: z.ZodOptional<z.ZodString>;
|
|
52
|
+
view: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
54
|
+
utm: z.ZodOptional<z.ZodObject<{
|
|
55
|
+
source: z.ZodOptional<z.ZodString>;
|
|
56
|
+
medium: z.ZodOptional<z.ZodString>;
|
|
57
|
+
campaign: z.ZodOptional<z.ZodString>;
|
|
58
|
+
}, z.core.$strip>>;
|
|
59
|
+
device: z.ZodEnum<{
|
|
60
|
+
phone: "phone";
|
|
61
|
+
tablet: "tablet";
|
|
62
|
+
desktop: "desktop";
|
|
63
|
+
}>;
|
|
64
|
+
}, z.core.$strip>>;
|
|
65
|
+
rendered: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>;
|
|
66
|
+
viewed: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>;
|
|
67
|
+
}, z.core.$strip>;
|
|
68
|
+
export type AnalyticsBeacon = z.infer<typeof AnalyticsBeacon>;
|
|
48
69
|
export declare const Api: {
|
|
49
70
|
"/draft/enable": {
|
|
50
71
|
GET: {
|
|
@@ -98,6 +119,24 @@ export declare const Api: {
|
|
|
98
119
|
}, z.core.$strip>]>;
|
|
99
120
|
};
|
|
100
121
|
};
|
|
122
|
+
"/analytics": {
|
|
123
|
+
POST: {
|
|
124
|
+
req: {
|
|
125
|
+
body: z.ZodUnknown;
|
|
126
|
+
};
|
|
127
|
+
res: z.ZodUnion<readonly [z.ZodObject<{
|
|
128
|
+
status: z.ZodLiteral<200>;
|
|
129
|
+
json: z.ZodObject<{
|
|
130
|
+
counted: z.ZodBoolean;
|
|
131
|
+
}, z.core.$strip>;
|
|
132
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
133
|
+
status: z.ZodLiteral<400>;
|
|
134
|
+
json: z.ZodObject<{
|
|
135
|
+
message: z.ZodString;
|
|
136
|
+
}, z.core.$strip>;
|
|
137
|
+
}, z.core.$strip>]>;
|
|
138
|
+
};
|
|
139
|
+
};
|
|
101
140
|
"/draft/stat": {
|
|
102
141
|
GET: {
|
|
103
142
|
req: {
|
|
@@ -23,6 +23,82 @@ export type ValDemoRuntime = {
|
|
|
23
23
|
* refuses uploads before sending anything, and says why.
|
|
24
24
|
*/
|
|
25
25
|
uploads: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The tour the site wrote, in place of the Studio's own demo tour. See
|
|
28
|
+
* `ValDemoTourStep`. Absent: the Studio's.
|
|
29
|
+
*/
|
|
30
|
+
tour?: ValDemoTourStep[];
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* What the site starts the demo with: `<ValApp demo={{ tour }}>`.
|
|
34
|
+
*
|
|
35
|
+
* `demo` alone (`true`) is the same with nothing given.
|
|
36
|
+
*/
|
|
37
|
+
export type ValDemoOptions = {
|
|
38
|
+
tour?: ValDemoTourStep[];
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* A control of the Studio's a step can point at.
|
|
42
|
+
*
|
|
43
|
+
* The `data-val-tour` markers the Studio puts on them. One that is not on
|
|
44
|
+
* screen (the rail on a phone) leaves the card on its own, so a step's words
|
|
45
|
+
* must work without the arrow: never "this button here".
|
|
46
|
+
*/
|
|
47
|
+
export type ValDemoTourTarget = "canvas" | "pages" | "media" | "data" | "review" | "preview" | "publish" | "ai" | "locale" | "demo" | "utility";
|
|
48
|
+
/** A panel a step opens, so what it is about is on screen behind the card. */
|
|
49
|
+
export type ValDemoTourPanel = "pages" | "media" | "data" | "settings" | "ai";
|
|
50
|
+
/**
|
|
51
|
+
* What moves a step on by itself. A step without one has Next.
|
|
52
|
+
*
|
|
53
|
+
* Each is something the visitor does, because doing it is the lesson, and
|
|
54
|
+
* each has a "Do it for me" that does it the way the Studio would:
|
|
55
|
+
*
|
|
56
|
+
* - `open`: a field at or below this source path is opened -- by clicking it
|
|
57
|
+
* on the page, or anywhere else. Do it for me opens it.
|
|
58
|
+
* - `edit`: a change is made. Do it for me writes `value` at `path`; without
|
|
59
|
+
* them, it is offered nowhere and the step waits for the visitor.
|
|
60
|
+
* - `panel`: that panel is opened. Do it for me opens it.
|
|
61
|
+
* - `locale`: the language shown is changed. Do it for me picks the next one.
|
|
62
|
+
*/
|
|
63
|
+
export type ValDemoTourMoveOn = {
|
|
64
|
+
open: string;
|
|
65
|
+
} | {
|
|
66
|
+
edit: true;
|
|
67
|
+
path?: string;
|
|
68
|
+
value?: string;
|
|
69
|
+
} | {
|
|
70
|
+
panel: ValDemoTourPanel;
|
|
71
|
+
} | {
|
|
72
|
+
locale: true;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* One stop of the demo's tour, as the site writes it.
|
|
76
|
+
*
|
|
77
|
+
* Data rather than components, so the tour can be rewritten -- and tried on
|
|
78
|
+
* people -- without a Val release: the Studio draws it, the site says what it
|
|
79
|
+
* says. Written for someone who has never seen Val.
|
|
80
|
+
*/
|
|
81
|
+
export type ValDemoTourStep = {
|
|
82
|
+
/** Stable, so a test can name a step without matching its words. */
|
|
83
|
+
id: string;
|
|
84
|
+
title: string;
|
|
85
|
+
body: string;
|
|
86
|
+
/** The control this step is about. */
|
|
87
|
+
target?: ValDemoTourTarget;
|
|
88
|
+
/**
|
|
89
|
+
* A field this step is about, as a source path: ringed wherever the Studio
|
|
90
|
+
* shows it -- the page's fields, or the module open in the editor. Takes
|
|
91
|
+
* precedence over `target`, which is what is ringed when the field is not
|
|
92
|
+
* on screen.
|
|
93
|
+
*/
|
|
94
|
+
field?: string;
|
|
95
|
+
/**
|
|
96
|
+
* A place on the page this step is about, as a source path: the page
|
|
97
|
+
* outlines it and brings it into view.
|
|
98
|
+
*/
|
|
99
|
+
page?: string;
|
|
100
|
+
panel?: ValDemoTourPanel;
|
|
101
|
+
moveOn?: ValDemoTourMoveOn;
|
|
26
102
|
};
|
|
27
103
|
declare global {
|
|
28
104
|
var __VAL_DEMO__: ValDemoRuntime | undefined;
|
|
@@ -388,7 +388,7 @@ function getPageRouterSitemapTree(srcFolder, paths) {
|
|
|
388
388
|
moduleFilePathS = path.moduleFilePath;
|
|
389
389
|
var moduleFilePath = moduleFilePathS;
|
|
390
390
|
if (!urlPath.startsWith("/")) {
|
|
391
|
-
|
|
391
|
+
core.Internal.log.error("urlPath must start with /: ".concat(urlPath));
|
|
392
392
|
return 0; // continue
|
|
393
393
|
}
|
|
394
394
|
var pattern = getPatternFromModuleFilePath(moduleFilePath, srcFolder);
|
|
@@ -388,7 +388,7 @@ function getPageRouterSitemapTree(srcFolder, paths) {
|
|
|
388
388
|
moduleFilePathS = path.moduleFilePath;
|
|
389
389
|
var moduleFilePath = moduleFilePathS;
|
|
390
390
|
if (!urlPath.startsWith("/")) {
|
|
391
|
-
|
|
391
|
+
core.Internal.log.error("urlPath must start with /: ".concat(urlPath));
|
|
392
392
|
return 0; // continue
|
|
393
393
|
}
|
|
394
394
|
var pattern = getPatternFromModuleFilePath(moduleFilePath, srcFolder);
|
|
@@ -386,7 +386,7 @@ function getPageRouterSitemapTree(srcFolder, paths) {
|
|
|
386
386
|
moduleFilePathS = path.moduleFilePath;
|
|
387
387
|
var moduleFilePath = moduleFilePathS;
|
|
388
388
|
if (!urlPath.startsWith("/")) {
|
|
389
|
-
|
|
389
|
+
Internal.log.error("urlPath must start with /: ".concat(urlPath));
|
|
390
390
|
return 0; // continue
|
|
391
391
|
}
|
|
392
392
|
var pattern = getPatternFromModuleFilePath(moduleFilePath, srcFolder);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var getSitemapTree = require('../../dist/getSitemapTree-
|
|
5
|
+
var getSitemapTree = require('../../dist/getSitemapTree-a7f2cc6d.cjs.dev.js');
|
|
6
6
|
var core = require('@valbuild/core');
|
|
7
7
|
var zod = require('zod');
|
|
8
8
|
var zodValidationError = require('zod-validation-error');
|
|
@@ -266,17 +266,17 @@ function convertImageNode(path, node, files, configDirectory, remoteOptions) {
|
|
|
266
266
|
if (remoteRef) {
|
|
267
267
|
noParamsUrl = decodeURIComponent(remoteRef);
|
|
268
268
|
} else {
|
|
269
|
-
|
|
269
|
+
core.Internal.log.error("Remote image URL does not contain ref: " + url);
|
|
270
270
|
}
|
|
271
271
|
} else if (noParamsUrl.startsWith("/api/val/files/public")) {
|
|
272
272
|
noParamsUrl = noParamsUrl.slice("/api/val/files".length);
|
|
273
273
|
} else {
|
|
274
|
-
|
|
274
|
+
core.Internal.log.error("Patched image URL does not start with /api/val/files: " + url);
|
|
275
275
|
}
|
|
276
276
|
} else if (core.Internal.remote.splitRemoteRef(noParamsUrl).status === "success") ; else if (!noParamsUrl.startsWith("/public")) {
|
|
277
277
|
noParamsUrl = "/public".concat(noParamsUrl);
|
|
278
278
|
} else {
|
|
279
|
-
|
|
279
|
+
core.Internal.log.error("Unpatched image URL starts with /public: " + url);
|
|
280
280
|
}
|
|
281
281
|
var tag = {
|
|
282
282
|
tag: "img",
|
|
@@ -1782,6 +1782,48 @@ var onlyOneIntQueryParam = onlyOneStringQueryParam.refine(function (arg) {
|
|
|
1782
1782
|
* this. Shared so client and server agree on the limit.
|
|
1783
1783
|
*/
|
|
1784
1784
|
var JSON_ENTRIES_BATCH_MAX = 100;
|
|
1785
|
+
|
|
1786
|
+
/**
|
|
1787
|
+
* Content analytics, wire format version 1: the beacon the browser script
|
|
1788
|
+
* (`@valbuild/react/analytics`) sends to `POST /api/val/analytics`. Its
|
|
1789
|
+
* `AnalyticsBeacon` type is written by hand there, because that code is on
|
|
1790
|
+
* every visitor's page and must not load zod; `analytics/beacon.test.ts` in
|
|
1791
|
+
* `@valbuild/react` checks that what it builds parses here.
|
|
1792
|
+
*/
|
|
1793
|
+
/*
|
|
1794
|
+
* The limits the browser script keeps to (`MAX_*` in
|
|
1795
|
+
* `@valbuild/react/analytics`'s `beacon.ts`, which cannot import this). The
|
|
1796
|
+
* endpoint takes anyone's POST, so it checks what it is sent rather than
|
|
1797
|
+
* trusting the sender; `beacon.test.ts` builds beacons at the limits and
|
|
1798
|
+
* parses them here.
|
|
1799
|
+
*/
|
|
1800
|
+
var MAX_ANALYTICS_PATHS_PER_BEACON = 200;
|
|
1801
|
+
var AnalyticsPaths = zod.z.record(zod.z.string().max(512), zod.z.array(zod.z.string().max(1024)).max(MAX_ANALYTICS_PATHS_PER_BEACON));
|
|
1802
|
+
var countAnalyticsPaths = function countAnalyticsPaths(paths) {
|
|
1803
|
+
return Object.values(paths).reduce(function (n, list) {
|
|
1804
|
+
return n + list.length;
|
|
1805
|
+
}, 0);
|
|
1806
|
+
};
|
|
1807
|
+
var AnalyticsBeacon = zod.z.object({
|
|
1808
|
+
v: zod.z.literal(1),
|
|
1809
|
+
route: zod.z.string().max(512),
|
|
1810
|
+
cv: zod.z.string().max(128).optional(),
|
|
1811
|
+
view: zod.z.object({
|
|
1812
|
+
ref: zod.z.string().max(253).optional(),
|
|
1813
|
+
utm: zod.z.object({
|
|
1814
|
+
source: zod.z.string().max(100).optional(),
|
|
1815
|
+
medium: zod.z.string().max(100).optional(),
|
|
1816
|
+
campaign: zod.z.string().max(100).optional()
|
|
1817
|
+
}).optional(),
|
|
1818
|
+
device: zod.z["enum"](["phone", "tablet", "desktop"])
|
|
1819
|
+
}).optional(),
|
|
1820
|
+
rendered: AnalyticsPaths,
|
|
1821
|
+
viewed: AnalyticsPaths
|
|
1822
|
+
}).refine(function (beacon) {
|
|
1823
|
+
return countAnalyticsPaths(beacon.rendered) + countAnalyticsPaths(beacon.viewed) <= MAX_ANALYTICS_PATHS_PER_BEACON;
|
|
1824
|
+
}, {
|
|
1825
|
+
message: "At most ".concat(MAX_ANALYTICS_PATHS_PER_BEACON, " paths a beacon")
|
|
1826
|
+
});
|
|
1785
1827
|
var Api = {
|
|
1786
1828
|
"/draft/enable": {
|
|
1787
1829
|
GET: {
|
|
@@ -1827,6 +1869,27 @@ var Api = {
|
|
|
1827
1869
|
})])
|
|
1828
1870
|
}
|
|
1829
1871
|
},
|
|
1872
|
+
"/analytics": {
|
|
1873
|
+
POST: {
|
|
1874
|
+
// Parsed by the handler rather than here, so a beacon of a version this
|
|
1875
|
+
// server does not know is ignored instead of refused.
|
|
1876
|
+
req: {
|
|
1877
|
+
body: zod.z.unknown()
|
|
1878
|
+
},
|
|
1879
|
+
res: zod.z.union([
|
|
1880
|
+
// `counted` is false wherever nothing stores the counts -- every
|
|
1881
|
+
// server but the hosted platform's, for now.
|
|
1882
|
+
zod.z.object({
|
|
1883
|
+
status: zod.z.literal(200),
|
|
1884
|
+
json: zod.z.object({
|
|
1885
|
+
counted: zod.z["boolean"]()
|
|
1886
|
+
})
|
|
1887
|
+
}), zod.z.object({
|
|
1888
|
+
status: zod.z.literal(400),
|
|
1889
|
+
json: GenericError
|
|
1890
|
+
})])
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1830
1893
|
"/draft/stat": {
|
|
1831
1894
|
GET: {
|
|
1832
1895
|
req: {
|
|
@@ -3928,7 +3991,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
3928
3991
|
_context2.n = 2;
|
|
3929
3992
|
break;
|
|
3930
3993
|
}
|
|
3931
|
-
|
|
3994
|
+
core.Internal.log.error("Got an invalid request body while validating client-side. This is most likely a Val bug.", {
|
|
3932
3995
|
path: path,
|
|
3933
3996
|
method: method,
|
|
3934
3997
|
body: anyReq.body,
|
|
@@ -4006,7 +4069,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
4006
4069
|
_context.n = 4;
|
|
4007
4070
|
break;
|
|
4008
4071
|
}
|
|
4009
|
-
|
|
4072
|
+
core.Internal.log.error("Server responded with an error", json);
|
|
4010
4073
|
message = getErrorMessageFromUnknownJson(json, "Unknown error");
|
|
4011
4074
|
return _context.a(2, {
|
|
4012
4075
|
status: 500,
|
|
@@ -4093,6 +4156,44 @@ function isRetryable(error) {
|
|
|
4093
4156
|
* modules. See `docs/plans/demo-mode.md`.
|
|
4094
4157
|
*/
|
|
4095
4158
|
|
|
4159
|
+
/**
|
|
4160
|
+
* What the site starts the demo with: `<ValApp demo={{ tour }}>`.
|
|
4161
|
+
*
|
|
4162
|
+
* `demo` alone (`true`) is the same with nothing given.
|
|
4163
|
+
*/
|
|
4164
|
+
|
|
4165
|
+
/**
|
|
4166
|
+
* A control of the Studio's a step can point at.
|
|
4167
|
+
*
|
|
4168
|
+
* The `data-val-tour` markers the Studio puts on them. One that is not on
|
|
4169
|
+
* screen (the rail on a phone) leaves the card on its own, so a step's words
|
|
4170
|
+
* must work without the arrow: never "this button here".
|
|
4171
|
+
*/
|
|
4172
|
+
|
|
4173
|
+
/** A panel a step opens, so what it is about is on screen behind the card. */
|
|
4174
|
+
|
|
4175
|
+
/**
|
|
4176
|
+
* What moves a step on by itself. A step without one has Next.
|
|
4177
|
+
*
|
|
4178
|
+
* Each is something the visitor does, because doing it is the lesson, and
|
|
4179
|
+
* each has a "Do it for me" that does it the way the Studio would:
|
|
4180
|
+
*
|
|
4181
|
+
* - `open`: a field at or below this source path is opened -- by clicking it
|
|
4182
|
+
* on the page, or anywhere else. Do it for me opens it.
|
|
4183
|
+
* - `edit`: a change is made. Do it for me writes `value` at `path`; without
|
|
4184
|
+
* them, it is offered nowhere and the step waits for the visitor.
|
|
4185
|
+
* - `panel`: that panel is opened. Do it for me opens it.
|
|
4186
|
+
* - `locale`: the language shown is changed. Do it for me picks the next one.
|
|
4187
|
+
*/
|
|
4188
|
+
|
|
4189
|
+
/**
|
|
4190
|
+
* One stop of the demo's tour, as the site writes it.
|
|
4191
|
+
*
|
|
4192
|
+
* Data rather than components, so the tour can be rewritten -- and tried on
|
|
4193
|
+
* people -- without a Val release: the Studio draws it, the site says what it
|
|
4194
|
+
* says. Written for someone who has never seen Val.
|
|
4195
|
+
*/
|
|
4196
|
+
|
|
4096
4197
|
/*
|
|
4097
4198
|
* A global `var` rather than a `Window` member: this package is compiled
|
|
4098
4199
|
* without the DOM's types, and a `var` in global scope is also a property of
|
|
@@ -4631,14 +4732,14 @@ function filterRoutesByPatterns(routes, includePattern, excludePattern) {
|
|
|
4631
4732
|
try {
|
|
4632
4733
|
includeRegex = new RegExp(includePattern.source, includePattern.flags);
|
|
4633
4734
|
} catch (e) {
|
|
4634
|
-
|
|
4735
|
+
core.Internal.log.warn("[Val] Invalid include pattern: /".concat(includePattern.source, "/").concat(includePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed include pattern.");
|
|
4635
4736
|
}
|
|
4636
4737
|
}
|
|
4637
4738
|
if (excludePattern) {
|
|
4638
4739
|
try {
|
|
4639
4740
|
excludeRegex = new RegExp(excludePattern.source, excludePattern.flags);
|
|
4640
4741
|
} catch (e) {
|
|
4641
|
-
|
|
4742
|
+
core.Internal.log.warn("[Val] Invalid exclude pattern: /".concat(excludePattern.source, "/").concat(excludePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed exclude pattern.");
|
|
4642
4743
|
}
|
|
4643
4744
|
}
|
|
4644
4745
|
return routes.filter(function (route) {
|
|
@@ -8360,7 +8461,7 @@ function schemaTypesOfPath(schema, patchPath) {
|
|
|
8360
8461
|
} else {
|
|
8361
8462
|
var _unreachable = current;
|
|
8362
8463
|
var unknownType = _unreachable.type;
|
|
8363
|
-
|
|
8464
|
+
core.Internal.log.error("Unexecpted resolved schema type: ".concat(unknownType, " in ").concat(patchPath.join("/"), " at ").concat(pathPart));
|
|
8364
8465
|
return new Set([unknownType]);
|
|
8365
8466
|
}
|
|
8366
8467
|
}
|
|
@@ -8699,9 +8800,9 @@ var PatchSets = /*#__PURE__*/function () {
|
|
|
8699
8800
|
} catch (e) {
|
|
8700
8801
|
// We might be in this situation if the schema changes, etc etc:
|
|
8701
8802
|
if (e instanceof Error) {
|
|
8702
|
-
|
|
8803
|
+
core.Internal.log.error("Could not resolve path while creating patch set", e.message);
|
|
8703
8804
|
} else {
|
|
8704
|
-
|
|
8805
|
+
core.Internal.log.error("Could not resolve path while creating patch set", e);
|
|
8705
8806
|
}
|
|
8706
8807
|
// "terminate" the entire module file path (i.e. all patches are their own patch set)
|
|
8707
8808
|
this.insertPath(moduleFilePath, [], patchId, createdAt, author, op.op, [schema.type], op.path);
|
|
@@ -8943,6 +9044,7 @@ exports.parseRoutePattern = getSitemapTree.parseRoutePattern;
|
|
|
8943
9044
|
exports.withValCanvasParam = getSitemapTree.withValCanvasParam;
|
|
8944
9045
|
exports.AA_LARGE = AA_LARGE;
|
|
8945
9046
|
exports.AA_TEXT = AA_TEXT;
|
|
9047
|
+
exports.AnalyticsBeacon = AnalyticsBeacon;
|
|
8946
9048
|
exports.Api = Api;
|
|
8947
9049
|
exports.BRAND_CONTRAST_PAIRS = BRAND_CONTRAST_PAIRS;
|
|
8948
9050
|
exports.BinaryFileRef = BinaryFileRef;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var getSitemapTree = require('../../dist/getSitemapTree-
|
|
5
|
+
var getSitemapTree = require('../../dist/getSitemapTree-40d76bf8.cjs.prod.js');
|
|
6
6
|
var core = require('@valbuild/core');
|
|
7
7
|
var zod = require('zod');
|
|
8
8
|
var zodValidationError = require('zod-validation-error');
|
|
@@ -266,17 +266,17 @@ function convertImageNode(path, node, files, configDirectory, remoteOptions) {
|
|
|
266
266
|
if (remoteRef) {
|
|
267
267
|
noParamsUrl = decodeURIComponent(remoteRef);
|
|
268
268
|
} else {
|
|
269
|
-
|
|
269
|
+
core.Internal.log.error("Remote image URL does not contain ref: " + url);
|
|
270
270
|
}
|
|
271
271
|
} else if (noParamsUrl.startsWith("/api/val/files/public")) {
|
|
272
272
|
noParamsUrl = noParamsUrl.slice("/api/val/files".length);
|
|
273
273
|
} else {
|
|
274
|
-
|
|
274
|
+
core.Internal.log.error("Patched image URL does not start with /api/val/files: " + url);
|
|
275
275
|
}
|
|
276
276
|
} else if (core.Internal.remote.splitRemoteRef(noParamsUrl).status === "success") ; else if (!noParamsUrl.startsWith("/public")) {
|
|
277
277
|
noParamsUrl = "/public".concat(noParamsUrl);
|
|
278
278
|
} else {
|
|
279
|
-
|
|
279
|
+
core.Internal.log.error("Unpatched image URL starts with /public: " + url);
|
|
280
280
|
}
|
|
281
281
|
var tag = {
|
|
282
282
|
tag: "img",
|
|
@@ -1782,6 +1782,48 @@ var onlyOneIntQueryParam = onlyOneStringQueryParam.refine(function (arg) {
|
|
|
1782
1782
|
* this. Shared so client and server agree on the limit.
|
|
1783
1783
|
*/
|
|
1784
1784
|
var JSON_ENTRIES_BATCH_MAX = 100;
|
|
1785
|
+
|
|
1786
|
+
/**
|
|
1787
|
+
* Content analytics, wire format version 1: the beacon the browser script
|
|
1788
|
+
* (`@valbuild/react/analytics`) sends to `POST /api/val/analytics`. Its
|
|
1789
|
+
* `AnalyticsBeacon` type is written by hand there, because that code is on
|
|
1790
|
+
* every visitor's page and must not load zod; `analytics/beacon.test.ts` in
|
|
1791
|
+
* `@valbuild/react` checks that what it builds parses here.
|
|
1792
|
+
*/
|
|
1793
|
+
/*
|
|
1794
|
+
* The limits the browser script keeps to (`MAX_*` in
|
|
1795
|
+
* `@valbuild/react/analytics`'s `beacon.ts`, which cannot import this). The
|
|
1796
|
+
* endpoint takes anyone's POST, so it checks what it is sent rather than
|
|
1797
|
+
* trusting the sender; `beacon.test.ts` builds beacons at the limits and
|
|
1798
|
+
* parses them here.
|
|
1799
|
+
*/
|
|
1800
|
+
var MAX_ANALYTICS_PATHS_PER_BEACON = 200;
|
|
1801
|
+
var AnalyticsPaths = zod.z.record(zod.z.string().max(512), zod.z.array(zod.z.string().max(1024)).max(MAX_ANALYTICS_PATHS_PER_BEACON));
|
|
1802
|
+
var countAnalyticsPaths = function countAnalyticsPaths(paths) {
|
|
1803
|
+
return Object.values(paths).reduce(function (n, list) {
|
|
1804
|
+
return n + list.length;
|
|
1805
|
+
}, 0);
|
|
1806
|
+
};
|
|
1807
|
+
var AnalyticsBeacon = zod.z.object({
|
|
1808
|
+
v: zod.z.literal(1),
|
|
1809
|
+
route: zod.z.string().max(512),
|
|
1810
|
+
cv: zod.z.string().max(128).optional(),
|
|
1811
|
+
view: zod.z.object({
|
|
1812
|
+
ref: zod.z.string().max(253).optional(),
|
|
1813
|
+
utm: zod.z.object({
|
|
1814
|
+
source: zod.z.string().max(100).optional(),
|
|
1815
|
+
medium: zod.z.string().max(100).optional(),
|
|
1816
|
+
campaign: zod.z.string().max(100).optional()
|
|
1817
|
+
}).optional(),
|
|
1818
|
+
device: zod.z["enum"](["phone", "tablet", "desktop"])
|
|
1819
|
+
}).optional(),
|
|
1820
|
+
rendered: AnalyticsPaths,
|
|
1821
|
+
viewed: AnalyticsPaths
|
|
1822
|
+
}).refine(function (beacon) {
|
|
1823
|
+
return countAnalyticsPaths(beacon.rendered) + countAnalyticsPaths(beacon.viewed) <= MAX_ANALYTICS_PATHS_PER_BEACON;
|
|
1824
|
+
}, {
|
|
1825
|
+
message: "At most ".concat(MAX_ANALYTICS_PATHS_PER_BEACON, " paths a beacon")
|
|
1826
|
+
});
|
|
1785
1827
|
var Api = {
|
|
1786
1828
|
"/draft/enable": {
|
|
1787
1829
|
GET: {
|
|
@@ -1827,6 +1869,27 @@ var Api = {
|
|
|
1827
1869
|
})])
|
|
1828
1870
|
}
|
|
1829
1871
|
},
|
|
1872
|
+
"/analytics": {
|
|
1873
|
+
POST: {
|
|
1874
|
+
// Parsed by the handler rather than here, so a beacon of a version this
|
|
1875
|
+
// server does not know is ignored instead of refused.
|
|
1876
|
+
req: {
|
|
1877
|
+
body: zod.z.unknown()
|
|
1878
|
+
},
|
|
1879
|
+
res: zod.z.union([
|
|
1880
|
+
// `counted` is false wherever nothing stores the counts -- every
|
|
1881
|
+
// server but the hosted platform's, for now.
|
|
1882
|
+
zod.z.object({
|
|
1883
|
+
status: zod.z.literal(200),
|
|
1884
|
+
json: zod.z.object({
|
|
1885
|
+
counted: zod.z["boolean"]()
|
|
1886
|
+
})
|
|
1887
|
+
}), zod.z.object({
|
|
1888
|
+
status: zod.z.literal(400),
|
|
1889
|
+
json: GenericError
|
|
1890
|
+
})])
|
|
1891
|
+
}
|
|
1892
|
+
},
|
|
1830
1893
|
"/draft/stat": {
|
|
1831
1894
|
GET: {
|
|
1832
1895
|
req: {
|
|
@@ -3928,7 +3991,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
3928
3991
|
_context2.n = 2;
|
|
3929
3992
|
break;
|
|
3930
3993
|
}
|
|
3931
|
-
|
|
3994
|
+
core.Internal.log.error("Got an invalid request body while validating client-side. This is most likely a Val bug.", {
|
|
3932
3995
|
path: path,
|
|
3933
3996
|
method: method,
|
|
3934
3997
|
body: anyReq.body,
|
|
@@ -4006,7 +4069,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
4006
4069
|
_context.n = 4;
|
|
4007
4070
|
break;
|
|
4008
4071
|
}
|
|
4009
|
-
|
|
4072
|
+
core.Internal.log.error("Server responded with an error", json);
|
|
4010
4073
|
message = getErrorMessageFromUnknownJson(json, "Unknown error");
|
|
4011
4074
|
return _context.a(2, {
|
|
4012
4075
|
status: 500,
|
|
@@ -4093,6 +4156,44 @@ function isRetryable(error) {
|
|
|
4093
4156
|
* modules. See `docs/plans/demo-mode.md`.
|
|
4094
4157
|
*/
|
|
4095
4158
|
|
|
4159
|
+
/**
|
|
4160
|
+
* What the site starts the demo with: `<ValApp demo={{ tour }}>`.
|
|
4161
|
+
*
|
|
4162
|
+
* `demo` alone (`true`) is the same with nothing given.
|
|
4163
|
+
*/
|
|
4164
|
+
|
|
4165
|
+
/**
|
|
4166
|
+
* A control of the Studio's a step can point at.
|
|
4167
|
+
*
|
|
4168
|
+
* The `data-val-tour` markers the Studio puts on them. One that is not on
|
|
4169
|
+
* screen (the rail on a phone) leaves the card on its own, so a step's words
|
|
4170
|
+
* must work without the arrow: never "this button here".
|
|
4171
|
+
*/
|
|
4172
|
+
|
|
4173
|
+
/** A panel a step opens, so what it is about is on screen behind the card. */
|
|
4174
|
+
|
|
4175
|
+
/**
|
|
4176
|
+
* What moves a step on by itself. A step without one has Next.
|
|
4177
|
+
*
|
|
4178
|
+
* Each is something the visitor does, because doing it is the lesson, and
|
|
4179
|
+
* each has a "Do it for me" that does it the way the Studio would:
|
|
4180
|
+
*
|
|
4181
|
+
* - `open`: a field at or below this source path is opened -- by clicking it
|
|
4182
|
+
* on the page, or anywhere else. Do it for me opens it.
|
|
4183
|
+
* - `edit`: a change is made. Do it for me writes `value` at `path`; without
|
|
4184
|
+
* them, it is offered nowhere and the step waits for the visitor.
|
|
4185
|
+
* - `panel`: that panel is opened. Do it for me opens it.
|
|
4186
|
+
* - `locale`: the language shown is changed. Do it for me picks the next one.
|
|
4187
|
+
*/
|
|
4188
|
+
|
|
4189
|
+
/**
|
|
4190
|
+
* One stop of the demo's tour, as the site writes it.
|
|
4191
|
+
*
|
|
4192
|
+
* Data rather than components, so the tour can be rewritten -- and tried on
|
|
4193
|
+
* people -- without a Val release: the Studio draws it, the site says what it
|
|
4194
|
+
* says. Written for someone who has never seen Val.
|
|
4195
|
+
*/
|
|
4196
|
+
|
|
4096
4197
|
/*
|
|
4097
4198
|
* A global `var` rather than a `Window` member: this package is compiled
|
|
4098
4199
|
* without the DOM's types, and a `var` in global scope is also a property of
|
|
@@ -4631,14 +4732,14 @@ function filterRoutesByPatterns(routes, includePattern, excludePattern) {
|
|
|
4631
4732
|
try {
|
|
4632
4733
|
includeRegex = new RegExp(includePattern.source, includePattern.flags);
|
|
4633
4734
|
} catch (e) {
|
|
4634
|
-
|
|
4735
|
+
core.Internal.log.warn("[Val] Invalid include pattern: /".concat(includePattern.source, "/").concat(includePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed include pattern.");
|
|
4635
4736
|
}
|
|
4636
4737
|
}
|
|
4637
4738
|
if (excludePattern) {
|
|
4638
4739
|
try {
|
|
4639
4740
|
excludeRegex = new RegExp(excludePattern.source, excludePattern.flags);
|
|
4640
4741
|
} catch (e) {
|
|
4641
|
-
|
|
4742
|
+
core.Internal.log.warn("[Val] Invalid exclude pattern: /".concat(excludePattern.source, "/").concat(excludePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed exclude pattern.");
|
|
4642
4743
|
}
|
|
4643
4744
|
}
|
|
4644
4745
|
return routes.filter(function (route) {
|
|
@@ -8360,7 +8461,7 @@ function schemaTypesOfPath(schema, patchPath) {
|
|
|
8360
8461
|
} else {
|
|
8361
8462
|
var _unreachable = current;
|
|
8362
8463
|
var unknownType = _unreachable.type;
|
|
8363
|
-
|
|
8464
|
+
core.Internal.log.error("Unexecpted resolved schema type: ".concat(unknownType, " in ").concat(patchPath.join("/"), " at ").concat(pathPart));
|
|
8364
8465
|
return new Set([unknownType]);
|
|
8365
8466
|
}
|
|
8366
8467
|
}
|
|
@@ -8699,9 +8800,9 @@ var PatchSets = /*#__PURE__*/function () {
|
|
|
8699
8800
|
} catch (e) {
|
|
8700
8801
|
// We might be in this situation if the schema changes, etc etc:
|
|
8701
8802
|
if (e instanceof Error) {
|
|
8702
|
-
|
|
8803
|
+
core.Internal.log.error("Could not resolve path while creating patch set", e.message);
|
|
8703
8804
|
} else {
|
|
8704
|
-
|
|
8805
|
+
core.Internal.log.error("Could not resolve path while creating patch set", e);
|
|
8705
8806
|
}
|
|
8706
8807
|
// "terminate" the entire module file path (i.e. all patches are their own patch set)
|
|
8707
8808
|
this.insertPath(moduleFilePath, [], patchId, createdAt, author, op.op, [schema.type], op.path);
|
|
@@ -8943,6 +9044,7 @@ exports.parseRoutePattern = getSitemapTree.parseRoutePattern;
|
|
|
8943
9044
|
exports.withValCanvasParam = getSitemapTree.withValCanvasParam;
|
|
8944
9045
|
exports.AA_LARGE = AA_LARGE;
|
|
8945
9046
|
exports.AA_TEXT = AA_TEXT;
|
|
9047
|
+
exports.AnalyticsBeacon = AnalyticsBeacon;
|
|
8946
9048
|
exports.Api = Api;
|
|
8947
9049
|
exports.BRAND_CONTRAST_PAIRS = BRAND_CONTRAST_PAIRS;
|
|
8948
9050
|
exports.BinaryFileRef = BinaryFileRef;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { _ as _createForOfIteratorHelper, q as _objectSpread2, r as _arrayLikeToArray, s as _unsupportedIterableToArray, t as _typeof, u as _defineProperty, v as _toPropertyKey } from '../../dist/getSitemapTree-
|
|
2
|
-
export { D as DEFAULT_CANVAS_SELECTION, e as DEFAULT_CANVAS_SELECTION_SOFT, b as VAL_AI_SESSION_STORAGE_KEY, d as VAL_CANVAS_MESSAGE, c as VAL_CANVAS_PARAM, V as VAL_CONFIG_SESSION_STORAGE_KEY, a as VAL_THEME_SESSION_STORAGE_KEY, h as formatRoutePattern, j as getNextAppRouterSourceFolder, n as getPageRouterSitemapTree, l as getPageRouterSourceFolder, o as getPatternFromModuleFilePath, k as getTanStackRouterSourceFolder, m as isTanStackRoutesFolder, g as isValCanvasFrame, i as isValCanvasPageMessage, f as isValCanvasStudioMessage, p as parseRoutePattern, w as withValCanvasParam } from '../../dist/getSitemapTree-
|
|
1
|
+
import { _ as _createForOfIteratorHelper, q as _objectSpread2, r as _arrayLikeToArray, s as _unsupportedIterableToArray, t as _typeof, u as _defineProperty, v as _toPropertyKey } from '../../dist/getSitemapTree-cd006a36.esm.js';
|
|
2
|
+
export { D as DEFAULT_CANVAS_SELECTION, e as DEFAULT_CANVAS_SELECTION_SOFT, b as VAL_AI_SESSION_STORAGE_KEY, d as VAL_CANVAS_MESSAGE, c as VAL_CANVAS_PARAM, V as VAL_CONFIG_SESSION_STORAGE_KEY, a as VAL_THEME_SESSION_STORAGE_KEY, h as formatRoutePattern, j as getNextAppRouterSourceFolder, n as getPageRouterSitemapTree, l as getPageRouterSourceFolder, o as getPatternFromModuleFilePath, k as getTanStackRouterSourceFolder, m as isTanStackRoutesFolder, g as isValCanvasFrame, i as isValCanvasPageMessage, f as isValCanvasStudioMessage, p as parseRoutePattern, w as withValCanvasParam } from '../../dist/getSitemapTree-cd006a36.esm.js';
|
|
3
3
|
import { Internal, CODE_LANGUAGES, resolveSettingsModule, missingDeclaredKeys, localeOfValue, discriminatedUnionBranchOf, routePatternOf, matchRoutePattern, DEFAULT_COLOR_FORMAT, declaredKeySetOf } from '@valbuild/core';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { fromError } from 'zod-validation-error';
|
|
@@ -259,17 +259,17 @@ function convertImageNode(path, node, files, configDirectory, remoteOptions) {
|
|
|
259
259
|
if (remoteRef) {
|
|
260
260
|
noParamsUrl = decodeURIComponent(remoteRef);
|
|
261
261
|
} else {
|
|
262
|
-
|
|
262
|
+
Internal.log.error("Remote image URL does not contain ref: " + url);
|
|
263
263
|
}
|
|
264
264
|
} else if (noParamsUrl.startsWith("/api/val/files/public")) {
|
|
265
265
|
noParamsUrl = noParamsUrl.slice("/api/val/files".length);
|
|
266
266
|
} else {
|
|
267
|
-
|
|
267
|
+
Internal.log.error("Patched image URL does not start with /api/val/files: " + url);
|
|
268
268
|
}
|
|
269
269
|
} else if (Internal.remote.splitRemoteRef(noParamsUrl).status === "success") ; else if (!noParamsUrl.startsWith("/public")) {
|
|
270
270
|
noParamsUrl = "/public".concat(noParamsUrl);
|
|
271
271
|
} else {
|
|
272
|
-
|
|
272
|
+
Internal.log.error("Unpatched image URL starts with /public: " + url);
|
|
273
273
|
}
|
|
274
274
|
var tag = {
|
|
275
275
|
tag: "img",
|
|
@@ -1775,6 +1775,48 @@ var onlyOneIntQueryParam = onlyOneStringQueryParam.refine(function (arg) {
|
|
|
1775
1775
|
* this. Shared so client and server agree on the limit.
|
|
1776
1776
|
*/
|
|
1777
1777
|
var JSON_ENTRIES_BATCH_MAX = 100;
|
|
1778
|
+
|
|
1779
|
+
/**
|
|
1780
|
+
* Content analytics, wire format version 1: the beacon the browser script
|
|
1781
|
+
* (`@valbuild/react/analytics`) sends to `POST /api/val/analytics`. Its
|
|
1782
|
+
* `AnalyticsBeacon` type is written by hand there, because that code is on
|
|
1783
|
+
* every visitor's page and must not load zod; `analytics/beacon.test.ts` in
|
|
1784
|
+
* `@valbuild/react` checks that what it builds parses here.
|
|
1785
|
+
*/
|
|
1786
|
+
/*
|
|
1787
|
+
* The limits the browser script keeps to (`MAX_*` in
|
|
1788
|
+
* `@valbuild/react/analytics`'s `beacon.ts`, which cannot import this). The
|
|
1789
|
+
* endpoint takes anyone's POST, so it checks what it is sent rather than
|
|
1790
|
+
* trusting the sender; `beacon.test.ts` builds beacons at the limits and
|
|
1791
|
+
* parses them here.
|
|
1792
|
+
*/
|
|
1793
|
+
var MAX_ANALYTICS_PATHS_PER_BEACON = 200;
|
|
1794
|
+
var AnalyticsPaths = z.record(z.string().max(512), z.array(z.string().max(1024)).max(MAX_ANALYTICS_PATHS_PER_BEACON));
|
|
1795
|
+
var countAnalyticsPaths = function countAnalyticsPaths(paths) {
|
|
1796
|
+
return Object.values(paths).reduce(function (n, list) {
|
|
1797
|
+
return n + list.length;
|
|
1798
|
+
}, 0);
|
|
1799
|
+
};
|
|
1800
|
+
var AnalyticsBeacon = z.object({
|
|
1801
|
+
v: z.literal(1),
|
|
1802
|
+
route: z.string().max(512),
|
|
1803
|
+
cv: z.string().max(128).optional(),
|
|
1804
|
+
view: z.object({
|
|
1805
|
+
ref: z.string().max(253).optional(),
|
|
1806
|
+
utm: z.object({
|
|
1807
|
+
source: z.string().max(100).optional(),
|
|
1808
|
+
medium: z.string().max(100).optional(),
|
|
1809
|
+
campaign: z.string().max(100).optional()
|
|
1810
|
+
}).optional(),
|
|
1811
|
+
device: z["enum"](["phone", "tablet", "desktop"])
|
|
1812
|
+
}).optional(),
|
|
1813
|
+
rendered: AnalyticsPaths,
|
|
1814
|
+
viewed: AnalyticsPaths
|
|
1815
|
+
}).refine(function (beacon) {
|
|
1816
|
+
return countAnalyticsPaths(beacon.rendered) + countAnalyticsPaths(beacon.viewed) <= MAX_ANALYTICS_PATHS_PER_BEACON;
|
|
1817
|
+
}, {
|
|
1818
|
+
message: "At most ".concat(MAX_ANALYTICS_PATHS_PER_BEACON, " paths a beacon")
|
|
1819
|
+
});
|
|
1778
1820
|
var Api = {
|
|
1779
1821
|
"/draft/enable": {
|
|
1780
1822
|
GET: {
|
|
@@ -1820,6 +1862,27 @@ var Api = {
|
|
|
1820
1862
|
})])
|
|
1821
1863
|
}
|
|
1822
1864
|
},
|
|
1865
|
+
"/analytics": {
|
|
1866
|
+
POST: {
|
|
1867
|
+
// Parsed by the handler rather than here, so a beacon of a version this
|
|
1868
|
+
// server does not know is ignored instead of refused.
|
|
1869
|
+
req: {
|
|
1870
|
+
body: z.unknown()
|
|
1871
|
+
},
|
|
1872
|
+
res: z.union([
|
|
1873
|
+
// `counted` is false wherever nothing stores the counts -- every
|
|
1874
|
+
// server but the hosted platform's, for now.
|
|
1875
|
+
z.object({
|
|
1876
|
+
status: z.literal(200),
|
|
1877
|
+
json: z.object({
|
|
1878
|
+
counted: z["boolean"]()
|
|
1879
|
+
})
|
|
1880
|
+
}), z.object({
|
|
1881
|
+
status: z.literal(400),
|
|
1882
|
+
json: GenericError
|
|
1883
|
+
})])
|
|
1884
|
+
}
|
|
1885
|
+
},
|
|
1823
1886
|
"/draft/stat": {
|
|
1824
1887
|
GET: {
|
|
1825
1888
|
req: {
|
|
@@ -3921,7 +3984,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
3921
3984
|
_context2.n = 2;
|
|
3922
3985
|
break;
|
|
3923
3986
|
}
|
|
3924
|
-
|
|
3987
|
+
Internal.log.error("Got an invalid request body while validating client-side. This is most likely a Val bug.", {
|
|
3925
3988
|
path: path,
|
|
3926
3989
|
method: method,
|
|
3927
3990
|
body: anyReq.body,
|
|
@@ -3999,7 +4062,7 @@ var createValClient = function createValClient(host, config, options) {
|
|
|
3999
4062
|
_context.n = 4;
|
|
4000
4063
|
break;
|
|
4001
4064
|
}
|
|
4002
|
-
|
|
4065
|
+
Internal.log.error("Server responded with an error", json);
|
|
4003
4066
|
message = getErrorMessageFromUnknownJson(json, "Unknown error");
|
|
4004
4067
|
return _context.a(2, {
|
|
4005
4068
|
status: 500,
|
|
@@ -4086,6 +4149,44 @@ function isRetryable(error) {
|
|
|
4086
4149
|
* modules. See `docs/plans/demo-mode.md`.
|
|
4087
4150
|
*/
|
|
4088
4151
|
|
|
4152
|
+
/**
|
|
4153
|
+
* What the site starts the demo with: `<ValApp demo={{ tour }}>`.
|
|
4154
|
+
*
|
|
4155
|
+
* `demo` alone (`true`) is the same with nothing given.
|
|
4156
|
+
*/
|
|
4157
|
+
|
|
4158
|
+
/**
|
|
4159
|
+
* A control of the Studio's a step can point at.
|
|
4160
|
+
*
|
|
4161
|
+
* The `data-val-tour` markers the Studio puts on them. One that is not on
|
|
4162
|
+
* screen (the rail on a phone) leaves the card on its own, so a step's words
|
|
4163
|
+
* must work without the arrow: never "this button here".
|
|
4164
|
+
*/
|
|
4165
|
+
|
|
4166
|
+
/** A panel a step opens, so what it is about is on screen behind the card. */
|
|
4167
|
+
|
|
4168
|
+
/**
|
|
4169
|
+
* What moves a step on by itself. A step without one has Next.
|
|
4170
|
+
*
|
|
4171
|
+
* Each is something the visitor does, because doing it is the lesson, and
|
|
4172
|
+
* each has a "Do it for me" that does it the way the Studio would:
|
|
4173
|
+
*
|
|
4174
|
+
* - `open`: a field at or below this source path is opened -- by clicking it
|
|
4175
|
+
* on the page, or anywhere else. Do it for me opens it.
|
|
4176
|
+
* - `edit`: a change is made. Do it for me writes `value` at `path`; without
|
|
4177
|
+
* them, it is offered nowhere and the step waits for the visitor.
|
|
4178
|
+
* - `panel`: that panel is opened. Do it for me opens it.
|
|
4179
|
+
* - `locale`: the language shown is changed. Do it for me picks the next one.
|
|
4180
|
+
*/
|
|
4181
|
+
|
|
4182
|
+
/**
|
|
4183
|
+
* One stop of the demo's tour, as the site writes it.
|
|
4184
|
+
*
|
|
4185
|
+
* Data rather than components, so the tour can be rewritten -- and tried on
|
|
4186
|
+
* people -- without a Val release: the Studio draws it, the site says what it
|
|
4187
|
+
* says. Written for someone who has never seen Val.
|
|
4188
|
+
*/
|
|
4189
|
+
|
|
4089
4190
|
/*
|
|
4090
4191
|
* A global `var` rather than a `Window` member: this package is compiled
|
|
4091
4192
|
* without the DOM's types, and a `var` in global scope is also a property of
|
|
@@ -4624,14 +4725,14 @@ function filterRoutesByPatterns(routes, includePattern, excludePattern) {
|
|
|
4624
4725
|
try {
|
|
4625
4726
|
includeRegex = new RegExp(includePattern.source, includePattern.flags);
|
|
4626
4727
|
} catch (e) {
|
|
4627
|
-
|
|
4728
|
+
Internal.log.warn("[Val] Invalid include pattern: /".concat(includePattern.source, "/").concat(includePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed include pattern.");
|
|
4628
4729
|
}
|
|
4629
4730
|
}
|
|
4630
4731
|
if (excludePattern) {
|
|
4631
4732
|
try {
|
|
4632
4733
|
excludeRegex = new RegExp(excludePattern.source, excludePattern.flags);
|
|
4633
4734
|
} catch (e) {
|
|
4634
|
-
|
|
4735
|
+
Internal.log.warn("[Val] Invalid exclude pattern: /".concat(excludePattern.source, "/").concat(excludePattern.flags), "\nError: ".concat(e instanceof Error ? e.message : String(e)), "\nAll routes will be filtered out due to malformed exclude pattern.");
|
|
4635
4736
|
}
|
|
4636
4737
|
}
|
|
4637
4738
|
return routes.filter(function (route) {
|
|
@@ -8353,7 +8454,7 @@ function schemaTypesOfPath(schema, patchPath) {
|
|
|
8353
8454
|
} else {
|
|
8354
8455
|
var _unreachable = current;
|
|
8355
8456
|
var unknownType = _unreachable.type;
|
|
8356
|
-
|
|
8457
|
+
Internal.log.error("Unexecpted resolved schema type: ".concat(unknownType, " in ").concat(patchPath.join("/"), " at ").concat(pathPart));
|
|
8357
8458
|
return new Set([unknownType]);
|
|
8358
8459
|
}
|
|
8359
8460
|
}
|
|
@@ -8692,9 +8793,9 @@ var PatchSets = /*#__PURE__*/function () {
|
|
|
8692
8793
|
} catch (e) {
|
|
8693
8794
|
// We might be in this situation if the schema changes, etc etc:
|
|
8694
8795
|
if (e instanceof Error) {
|
|
8695
|
-
|
|
8796
|
+
Internal.log.error("Could not resolve path while creating patch set", e.message);
|
|
8696
8797
|
} else {
|
|
8697
|
-
|
|
8798
|
+
Internal.log.error("Could not resolve path while creating patch set", e);
|
|
8698
8799
|
}
|
|
8699
8800
|
// "terminate" the entire module file path (i.e. all patches are their own patch set)
|
|
8700
8801
|
this.insertPath(moduleFilePath, [], patchId, createdAt, author, op.op, [schema.type], op.path);
|
|
@@ -8915,4 +9016,4 @@ function schemaErrorsOf(schema, moduleFilePath, source) {
|
|
|
8915
9016
|
return errors;
|
|
8916
9017
|
}
|
|
8917
9018
|
|
|
8918
|
-
export { AA_LARGE, AA_TEXT, Api, BRAND_CONTRAST_PAIRS, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchId, PatchJSON, PatchSets, PlanRefusalError, PublishProtocolError, RAMP_STEPS, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SCHEMA_SOURCE_FIXES, STUDIO_FIXES, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedLocaleSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema, SerializedValViewSchema, SerializedVideoSchema, SharedValConfig, VAL_ENABLE_COOKIE_NAME, VAL_GREEN_RAMP, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, VAL_STUDIO_HEADER, ValCommit, ValDeployment, VideoOptions, VideoStreamOption, WASM_ENCODED_MIME_TYPES, accentRamp, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, buildSearchIndex, chainHeadOf, checkCompatibility, chooseEncoded, concatModulePath, contrastRatio, createRegExpFromPattern, createSearchIndex, createValClient, declaredLocales, describeContainerAtPath, emptyOf, enumLocaleTag, explainIncompatible, fallbackMimeType, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, fitWithin, flattenRichText, forEachRichTextImage, getErrorMessageFromUnknownJson, getFilenameFromRef, getInlineImgInfo, getKeyOfRecordAt, getRefParts, getRoutesOf, getRoutesWithModulePaths, getSourceAt, getValDemo, indexModule, isInsidePatchSetPath, isLocaleSchema, isMimeTypeAccepted, isRemoteSchema, isRepairedOnSave, isSchemaSourceFixError, isSkippedSource, isStudioFix, joinSharedChanges, keyOfRecordPath, levenshtein, localeAt, localeMeantBy, memoizePerRequest, newestCommitSha, parseArtifacts, parseBuildTarget, parseCancel, parseDeclare, parseDiscard, parseJob, parseNewestCiRun, parsePress, parseProblems, parseProjectSource, parsePromote, parsePublishToken, parseRenew, parseRequestStatus, parseStatus, parseUpdateTarget, parseVerify, partitionValidationErrors, performSearch, relativeLuminance, remirrorToRichTextSource, removeModule, resolveEncodeSettings, resolvePairGround, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextImageSchema, richTextToRemirror, safeParsePatch, schemaErrorsOf, schemaTypesOfPath, selectionClosure, shouldEncodeWithWasm, sideFiles, sideSource, sourcePathOfChild, themeCustomProperties, toolNames, traverseSchemaSource, urlOf, validateRoutePatterns, withExtension };
|
|
9019
|
+
export { AA_LARGE, AA_TEXT, AnalyticsBeacon, Api, BRAND_CONTRAST_PAIRS, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchId, PatchJSON, PatchSets, PlanRefusalError, PublishProtocolError, RAMP_STEPS, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SCHEMA_SOURCE_FIXES, STUDIO_FIXES, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedLocaleSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema, SerializedValViewSchema, SerializedVideoSchema, SharedValConfig, VAL_ENABLE_COOKIE_NAME, VAL_GREEN_RAMP, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, VAL_STUDIO_HEADER, ValCommit, ValDeployment, VideoOptions, VideoStreamOption, WASM_ENCODED_MIME_TYPES, accentRamp, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, buildSearchIndex, chainHeadOf, checkCompatibility, chooseEncoded, concatModulePath, contrastRatio, createRegExpFromPattern, createSearchIndex, createValClient, declaredLocales, describeContainerAtPath, emptyOf, enumLocaleTag, explainIncompatible, fallbackMimeType, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, fitWithin, flattenRichText, forEachRichTextImage, getErrorMessageFromUnknownJson, getFilenameFromRef, getInlineImgInfo, getKeyOfRecordAt, getRefParts, getRoutesOf, getRoutesWithModulePaths, getSourceAt, getValDemo, indexModule, isInsidePatchSetPath, isLocaleSchema, isMimeTypeAccepted, isRemoteSchema, isRepairedOnSave, isSchemaSourceFixError, isSkippedSource, isStudioFix, joinSharedChanges, keyOfRecordPath, levenshtein, localeAt, localeMeantBy, memoizePerRequest, newestCommitSha, parseArtifacts, parseBuildTarget, parseCancel, parseDeclare, parseDiscard, parseJob, parseNewestCiRun, parsePress, parseProblems, parseProjectSource, parsePromote, parsePublishToken, parseRenew, parseRequestStatus, parseStatus, parseUpdateTarget, parseVerify, partitionValidationErrors, performSearch, relativeLuminance, remirrorToRichTextSource, removeModule, resolveEncodeSettings, resolvePairGround, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextImageSchema, richTextToRemirror, safeParsePatch, schemaErrorsOf, schemaTypesOfPath, selectionClosure, shouldEncodeWithWasm, sideFiles, sideSource, sourcePathOfChild, themeCustomProperties, toolNames, traverseSchemaSource, urlOf, validateRoutePatterns, withExtension };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valbuild/shared",
|
|
3
|
-
"version": "0.148.
|
|
3
|
+
"version": "0.148.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Val shared types and utilities",
|
|
6
6
|
"repository": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"flexsearch": "^0.8.212",
|
|
38
38
|
"zod": "^4.4.3",
|
|
39
39
|
"zod-validation-error": "^5.0.0",
|
|
40
|
-
"@valbuild/core": "0.148.
|
|
40
|
+
"@valbuild/core": "0.148.2"
|
|
41
41
|
},
|
|
42
42
|
"files": [
|
|
43
43
|
"CHANGELOG.md",
|