@valbuild/server 0.144.0 → 0.144.2

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 CHANGED
@@ -1,5 +1,29 @@
1
1
  # @valbuild/server
2
2
 
3
+ ## 0.144.2
4
+
5
+ ### Patch Changes
6
+
7
+ - [#832](https://github.com/valbuild/val/pull/832) [`ab0ea20`](https://github.com/valbuild/val/commit/ab0ea2046e3872c4955f34b363881f76d48d1b1e) Thanks [@freekh](https://github.com/freekh)! - A site served by Val's platform can now be given its content separately from its build. When the platform hands a TanStack app a content version (`VAL_CONTENT`) that differs from what the build bundles, Val renders that content, in the Studio and in draft mode too. It reads it the way it already reads a proposal's saved content.
8
+
9
+ Nothing changes for an app that is not given one, and nothing hands one over yet. This is the reading side of publishing content without rebuilding the site.
10
+
11
+ A version too large for one environment variable can name others under `refs` (`"env://VAL_CONTENT_1"`), each holding one module's Source or one file's text. Only `refs` is resolved, never a string inside your content, and only variables named `VAL_CONTENT_<n>` are read.
12
+
13
+ At a proposal's address, a proposal's saved content is shown over the content version the site serves, so modules the proposal did not change show what the site shows rather than what the build bundles.
14
+
15
+ When Val's platform puts a publish live without building the site, because it changed only content, the Studio shows it being checked and going live instead of "Building".
16
+
17
+ - Updated dependencies [[`ab0ea20`](https://github.com/valbuild/val/commit/ab0ea2046e3872c4955f34b363881f76d48d1b1e), [`44a5636`](https://github.com/valbuild/val/commit/44a5636955e005a40f2e6c8544e5cf4378fd0fdf)]:
18
+ - @valbuild/shared@0.144.2
19
+ - @valbuild/ui@0.144.2
20
+
21
+ ## 0.144.1
22
+
23
+ ### Patch Changes
24
+
25
+ - [#824](https://github.com/valbuild/val/pull/824) [`a641bb0`](https://github.com/valbuild/val/commit/a641bb0286756339252c53e9230d766c23fcccc6) Thanks [@freekh](https://github.com/freekh)! - `.jsonValues()` entries saved in a proposal now show at the proposal's address. Before, the page kept showing the entry as it was when the site was last built, and the Studio there showed every entry of a saved `.jsonValues()` module as empty.
26
+
3
27
  ## 0.144.0
4
28
 
5
29
  ### Patch Changes
@@ -51,6 +51,21 @@ export type ValOpsOptions = {
51
51
  * the next save's prepare -- starts from it, and the SHAs describe it.
52
52
  */
53
53
  snapshotSources?: Sources;
54
+ /**
55
+ * Source the SITE serves over what the modules evaluate to, beneath
56
+ * {@link snapshotSources}: a content version (`ValContentVersion` in
57
+ * `./proposal`), the content published since the build. Applied the same
58
+ * way, and what a proposal's saves are compared against
59
+ * ({@link ValOps.siteSourcesUnderSnapshot}) -- the site, not the bundle.
60
+ */
61
+ siteSnapshotSources?: Sources;
62
+ /**
63
+ * The `.jsonValues()` entries the same snapshot saved, by module and key:
64
+ * their content is in their own files, not in {@link snapshotSources}, which
65
+ * holds markers. The baseline those entries are read from, as a save in
66
+ * this instance would leave them (`proposalJsonEntries` in `./proposal`).
67
+ */
68
+ snapshotJsonEntries?: Map<ModuleFilePath, Map<string, JSONValue>>;
54
69
  };
55
70
  export declare abstract class ValOps {
56
71
  private readonly valModules;
@@ -90,6 +105,13 @@ export declare abstract class ValOps {
90
105
  * {@link siteSourcesUnderSnapshot}, and only where there is a snapshot.
91
106
  */
92
107
  private siteSourcesBeforeSnapshot;
108
+ /**
109
+ * The same modules as the bundle evaluated them, imports and all: where a
110
+ * `.jsonValues()` entry the snapshot did not save is read from. Not
111
+ * {@link siteSourcesBeforeSnapshot}, whose markers may have come as JSON
112
+ * from a content version, with no import behind them.
113
+ */
114
+ private bundleSourcesBeforeSnapshot;
93
115
  /**
94
116
  * What a save has told us each `.jsonValues()` entry now holds.
95
117
  *
@@ -101,7 +123,9 @@ export declare abstract class ValOps {
101
123
  * unlike a module source there is nothing to re-extract, because the memo was
102
124
  * never holding the content in the first place.
103
125
  *
104
- * `null` for an entry the commit deleted.
126
+ * `deleted` for an entry the commit deleted: tagged, not `null`, because an
127
+ * entry's content may itself be JSON `null` (a nullable item), and a saved
128
+ * `null` read back as "deleted" would report the entry missing.
105
129
  *
106
130
  * Never cleared: it describes what is on disk. A host rebuild makes a new
107
131
  * instance, which is the right reset. Bounded by the project's entry count,
@@ -1,4 +1,4 @@
1
- import { type ValProposal } from "./proposal.js";
1
+ import { type ValContentVersion, type ValProposal } from "./proposal.js";
2
2
  import { type PatchId, type ModuleFilePath, ValModules } from "@valbuild/core";
3
3
  import type { Patch as PatchT, ParentRef as ParentRefT } from "@valbuild/core/patch";
4
4
  import { type AuthorId, type BaseSha, BinaryFileType, type CommitSha, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, type PatchGroupMembership, SchemaSha, OrderedPatchesMetadata, OrderedPatches, SourcesSha, type PublishRefusal } from "./ValOps.js";
@@ -81,6 +81,8 @@ export declare class ValOpsHttp extends ValOps {
81
81
  private readonly publishBuild;
82
82
  /** See `proposal` on {@link ValApiOptions}; `null` on the site. */
83
83
  private readonly proposal;
84
+ /** See `contentVersion` on {@link ValApiOptions}; `null` at a proposal's address. */
85
+ private readonly contentVersion;
84
86
  /** Did the host hand over the running build's source? See `projectSource`. */
85
87
  embedsSource(): boolean;
86
88
  /**
@@ -153,6 +155,8 @@ export declare class ValOpsHttp extends ValOps {
153
155
  publishBuild?: string;
154
156
  /** See `proposal` on {@link ValApiOptions}. */
155
157
  proposal?: ValProposal;
158
+ /** See `contentVersion` on {@link ValApiOptions}. */
159
+ contentVersion?: ValContentVersion;
156
160
  });
157
161
  /**
158
162
  * A deployment that cannot mirror a project which expects to be mirrored.
@@ -8,7 +8,7 @@ type Versions = {
8
8
  };
9
9
  };
10
10
  import type { ValPatchStore } from "./ValOpsMemory.js";
11
- import type { ValProposal } from "./proposal.js";
11
+ import type { ValContentVersion, ValProposal } from "./proposal.js";
12
12
  import type { CommitContext, CommitResult } from "./ValServer.js";
13
13
  export type ValApiOptions = ValServerOverrides & ValConfig & Versions;
14
14
  type ValServerOverrides = Partial<{
@@ -163,6 +163,14 @@ type ValServerOverrides = Partial<{
163
163
  * and the snapshot that replaces the bundle's Source for what it saved.
164
164
  */
165
165
  proposal?: ValProposal;
166
+ /**
167
+ * The content version the site serves, when a platform says it differs from
168
+ * the one this build bundles (`VAL_CONTENT`; read it with `contentFromEnv`).
169
+ * See {@link ValContentVersion}: its Source replaces the bundle's for what
170
+ * it holds, and its publish is this server's position. Ignored at a
171
+ * proposal's address.
172
+ */
173
+ contentVersion?: ValContentVersion;
166
174
  /**
167
175
  * The base url of Val.
168
176
  *
@@ -1,4 +1,4 @@
1
- import type { ValProposal } from "./proposal.js";
1
+ import type { ValContentVersion, ValProposal } from "./proposal.js";
2
2
  import { ValModules, PatchId, ModuleFilePath, ValConfig } from "@valbuild/core";
3
3
  import { Api, ServerOf, type PatchGroupT } from "@valbuild/shared/internal";
4
4
  import { z } from "zod";
@@ -148,6 +148,8 @@ export type ValServerConfig = ValServerOptions & ({
148
148
  publishBuild?: string;
149
149
  /** See `proposal` on {@link ValApiOptions}. */
150
150
  proposal?: ValProposal;
151
+ /** See `contentVersion` on {@link ValApiOptions}. */
152
+ contentVersion?: ValContentVersion;
151
153
  config: ValConfig;
152
154
  }
153
155
  /**
@@ -2,8 +2,8 @@ export { createService, Service } from "./Service.js";
2
2
  export { defineExternal, ok, err, isExternalResult, EXTERNAL_RESULT, } from "./externalRecords.js";
3
3
  export type { AdapterFor, BoundExternalRecord, ExternalAuthor, ExternalBuilder, ExternalCtx, ExternalDefinition, ExternalFile, ExternalIssue, ExternalKeyPage, ExternalRecords, ExternalResult, ExternalSearchHit, ExternalSearchPage, ExternalSort, ItemOfModule, ReadonlyRecordHasNoWrites, Returns, } from "./externalRecords.js";
4
4
  export { createValApiRouter, createValServer, safeReadGit } from "./ValRouter.js";
5
- export { proposalFromEnv, proposalSnapshot } from "./proposal.js";
6
- export type { ValProposal } from "./proposal.js";
5
+ export { contentFromEnv, proposalFromEnv, layeredSnapshot, proposalSnapshot, proposalSnapshotForReaders, } from "./proposal.js";
6
+ export type { ValContentVersion, ValProposal } from "./proposal.js";
7
7
  export { initHandlerOptions, createValOps } from "./valServerConfig.js";
8
8
  export { resolveRemoteFileAuth } from "./valServerConfig.js";
9
9
  export { APP_MODE_REQUIRES_REMOTE_FILES } from "./valServerConfig.js";
@@ -1,4 +1,5 @@
1
1
  import type { Json, ModuleFilePath } from "@valbuild/core";
2
+ import type { JSONValue } from "@valbuild/core/patch";
2
3
  /**
3
4
  * A proposal this server runs at the address of: an editor-managed branch of
4
5
  * the project's content, served from its own copy of the content the
@@ -64,9 +65,89 @@ export declare function proposalFromEnv(env: {
64
65
  VAL_BRANCH?: string | undefined;
65
66
  VAL_OVERLAY?: string | undefined;
66
67
  }): ValProposal | undefined;
68
+ /**
69
+ * A content version: the site's content, served by a build that bundles an
70
+ * older one. valbuild/home `docs/hosted-publishing.md`, step 2.
71
+ *
72
+ * The platform hands over only what differs from the bundle -- the modules
73
+ * whose Source changed and the Val files whose text did -- the way it hands a
74
+ * proposal's address its saved content, and it is read the same way: the
75
+ * snapshot source provider, over the bundle. What differs is the position: a
76
+ * version names the publish that made it (`job`, or its `commit`), and that is
77
+ * where this server says it sits, never at the build it runs in.
78
+ */
79
+ export type ValContentVersion = {
80
+ /** The version's id: the hash of its manifest, as the platform stores it. */
81
+ id: string;
82
+ /** The publish job that made it, when a job did. */
83
+ job: string | null;
84
+ /** Its place in the chain: the commit that publish minted. */
85
+ commit: string | null;
86
+ /** Source, by module file path, for the modules that differ from the bundle. */
87
+ modules: Record<string, unknown>;
88
+ /** Val file text, by path, for the files that differ from the bundle. */
89
+ files: Record<string, string>;
90
+ };
91
+ /**
92
+ * The content version a platform hands over in its runtime env
93
+ * (`VAL_CONTENT`), or `undefined` when it hands over none.
94
+ *
95
+ * Throws on one it cannot read rather than serving the bundle as though it
96
+ * were the version: the site would show content older than what was
97
+ * published, and nothing would say so.
98
+ *
99
+ * A version too large for one variable names others under `refs`: a module's
100
+ * Source (JSON) or a file's text, each in a variable of its own --
101
+ * `{ "refs": { "modules": { "/a.val.ts": "env://VAL_CONTENT_1" } } }`. Flat:
102
+ * a referenced variable holds the value itself and is never read for further
103
+ * references. Only `refs` is resolved, never a string inside Source, and only
104
+ * `VAL_CONTENT_<n>` is ever read: Source is text editors write, and a
105
+ * reference resolved in there would read any variable the isolate holds,
106
+ * `VAL_SECRET` included, into a page. The scheme leaves room for another
107
+ * place to read from; one this does not know is refused, not skipped.
108
+ */
109
+ export declare function contentFromEnv(env: Record<string, string | undefined>): ValContentVersion | undefined;
110
+ /**
111
+ * What a server or reader renders over the bundle: a proposal's saves over the
112
+ * content version the site serves, either alone, or nothing.
113
+ *
114
+ * Layered rather than chosen. At a proposal's address the platform hands both
115
+ * when the base the proposal was opened from serves content its build does not
116
+ * bundle (a content-only publish), and the proposal saves only the modules it
117
+ * changed: choosing the proposal alone would show every other module as the
118
+ * build bundles it -- older than the site it was opened from.
119
+ */
120
+ export declare function layeredSnapshot(proposal: Pick<ValProposal, "modules" | "files"> | undefined, contentVersion: Pick<ValContentVersion, "modules" | "files"> | undefined): Pick<ValProposal, "modules" | "files"> | undefined;
67
121
  /**
68
122
  * The proposal's saved Source, as Source: every module whose value is JSON.
69
123
  * One place, so the server and the readers that render without it agree on
70
124
  * what the snapshot holds.
71
125
  */
72
126
  export declare function proposalSnapshot(proposal: Pick<ValProposal, "modules">): Record<ModuleFilePath, Json>;
127
+ /**
128
+ * The `.jsonValues()` entries the proposal saved, by module and key.
129
+ *
130
+ * An entry's content is not in its module's Source -- that holds a marker per
131
+ * entry -- but in the entry's own `*.val.json`, and a save writes that file:
132
+ * it reaches the proposal's address as saved TEXT ({@link ValProposal.files}),
133
+ * not as Source. So the snapshot alone shows the build's entries. This is the
134
+ * other half: each saved `*.val.json`, read as the entry its module names.
135
+ *
136
+ * Which entry a file is comes from the module's `.val.ts`, whose
137
+ * `c.json(() => import("..."))` thunks name the files -- the saved text if
138
+ * the save rewrote it, else the build's own (`projectSource`). An entry whose
139
+ * module cannot be read that way is left to the build, as before: this adds
140
+ * what it can find and never fails the address.
141
+ */
142
+ export declare function proposalJsonEntries(proposal: Pick<ValProposal, "modules" | "files">, projectSource?: Record<string, string>): Map<ModuleFilePath, Map<string, JSONValue>>;
143
+ /**
144
+ * The snapshot as a page reads it: {@link proposalSnapshot}, with each saved
145
+ * `.jsonValues()` entry's content in place of its marker -- the shape a draft
146
+ * already has, where the entries it edits hold content and the rest are
147
+ * markers the readers resolve from the build. See {@link proposalJsonEntries}.
148
+ *
149
+ * For the readers only. Val's own server keeps the markers
150
+ * ({@link proposalSnapshot}): its patching works on them, and it takes the
151
+ * saved entries separately.
152
+ */
153
+ export declare function proposalSnapshotForReaders(proposal: Pick<ValProposal, "modules" | "files">, projectSource?: Record<string, string>): Record<ModuleFilePath, Json>;