@volter/world-core 3.0.17 → 3.0.18
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/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/runtime.d.ts +1 -1
- package/dist/src/runtime.js +1 -1
- package/dist/src/twin-fetch.d.ts +9 -2
- package/dist/src/twin-fetch.js +23 -4
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/runtime.ts +1 -1
- package/src/twin-fetch.ts +19 -4
package/dist/src/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ export { VendorUnreachableError } from './vendor-call.js';
|
|
|
36
36
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from './request-scope.js';
|
|
37
37
|
export { serveHttp, serveStream, type HttpHandler, type HttpServer, type ServeHttpOptions } from './serve-http.js';
|
|
38
38
|
export type { TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.js';
|
|
39
|
-
export { twinSiteUrl } from './twin-fetch.js';
|
|
39
|
+
export { siteLabel, siteUrlOf, twinSiteUrl } from './twin-fetch.js';
|
|
40
40
|
export { statefulTwinManifest, twinManifest } from './scenario.js';
|
|
41
41
|
export { assetContentType, packAsset } from './pack-assets.js';
|
|
42
42
|
export { bytesResponse, contentTypeOf, fileResponse } from './file-response.js';
|
package/dist/src/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from "./request-scope.js"
|
|
|
29
29
|
// ── the serve factory ──────────────────────────────────────────────────────────────────────────
|
|
30
30
|
export { serveHttp, serveStream } from "./serve-http.js";
|
|
31
31
|
// where a page links a hostname its twin answers, inside the World that shows it
|
|
32
|
-
export { twinSiteUrl } from "./twin-fetch.js";
|
|
32
|
+
export { siteLabel, siteUrlOf, twinSiteUrl } from "./twin-fetch.js";
|
|
33
33
|
export { statefulTwinManifest, twinManifest } from "./scenario.js";
|
|
34
34
|
export { assetContentType, packAsset } from "./pack-assets.js";
|
|
35
35
|
export { bytesResponse, contentTypeOf, fileResponse } from "./file-response.js";
|
package/dist/src/runtime.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioErr
|
|
|
4
4
|
export { WORLD_CLOCK_ENV, worldNow } from './world-clock.js';
|
|
5
5
|
export { WORLD_ENV_NAMES_ENV, worldEnvValue } from './world-env.js';
|
|
6
6
|
export { ORIGINAL_PATH_HEADER } from './sigv4.js';
|
|
7
|
-
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, twinPublicBase, twinSiteUrl, withRequestScopes } from './twin-fetch.js';
|
|
7
|
+
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, withRequestScopes } from './twin-fetch.js';
|
|
8
8
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from './request-scope.js';
|
|
9
9
|
export { compileSurface, createDerivedFetch, matchOperation } from './derived.js';
|
|
10
10
|
export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.js';
|
package/dist/src/runtime.js
CHANGED
|
@@ -12,7 +12,7 @@ export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioErr
|
|
|
12
12
|
export { WORLD_CLOCK_ENV, worldNow } from "./world-clock.js";
|
|
13
13
|
export { WORLD_ENV_NAMES_ENV, worldEnvValue } from "./world-env.js";
|
|
14
14
|
export { ORIGINAL_PATH_HEADER } from "./sigv4.js";
|
|
15
|
-
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, twinPublicBase, twinSiteUrl, withRequestScopes } from "./twin-fetch.js";
|
|
15
|
+
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, withRequestScopes } from "./twin-fetch.js";
|
|
16
16
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from "./request-scope.js";
|
|
17
17
|
export { compileSurface, createDerivedFetch, matchOperation } from "./derived.js";
|
|
18
18
|
export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from "./trace-context.js";
|
package/dist/src/twin-fetch.d.ts
CHANGED
|
@@ -8,9 +8,16 @@ export declare const TWIN_PREFIX_HEADER = "x-forwarded-prefix";
|
|
|
8
8
|
* callback) from this, never from the bare origin, so the URL works behind a served World. */
|
|
9
9
|
export declare function twinPublicBase(request: Request): string;
|
|
10
10
|
/** Where a World shows a hostname its twins answer (a Workers Custom Domain, an R2 public domain): the address a person
|
|
11
|
-
* opens it at, `{host}`
|
|
12
|
-
*
|
|
11
|
+
* opens it at, from the World's sites template. `{host}` stands for the hostname as it is, where the host's names nest
|
|
12
|
+
* (`http://{host}.<world>--<org>.localhost:<port>`); `{site}` for the hostname as one DNS label, its dots as hyphens,
|
|
13
|
+
* where one wildcard certificate covers the host's names (`https://{site}--<world>--<org>.volterdev.com`). A World that
|
|
14
|
+
* routes its sites to a browser sends the template on every request it forwards to a twin. */
|
|
13
15
|
export declare const TWIN_SITES_HEADER = "x-volter-world-sites";
|
|
16
|
+
/** A hostname as one DNS label: its dots as hyphens (`www.volter.ai` is `www-volter-ai`). */
|
|
17
|
+
export declare const siteLabel: (hostname: string) => string;
|
|
18
|
+
/** The address a sites template gives `hostname`, or null where the template is not one or the name makes no address
|
|
19
|
+
* (a label over 63 characters). */
|
|
20
|
+
export declare function siteUrlOf(template: string, hostname: string): string | null;
|
|
14
21
|
/** Where a page links a hostname the twin answers: the World's address for it when the World shows sites, else the
|
|
15
22
|
* hostname itself (reached through the World's proxy, or the vendor). A pack's screen links a site from this, as it
|
|
16
23
|
* mints its own URLs from twinPublicBase. */
|
package/dist/src/twin-fetch.js
CHANGED
|
@@ -41,16 +41,35 @@ export function twinPublicBase(request) {
|
|
|
41
41
|
return `${origin}${prefix.replace(/\/+$/, '')}`;
|
|
42
42
|
}
|
|
43
43
|
/** Where a World shows a hostname its twins answer (a Workers Custom Domain, an R2 public domain): the address a person
|
|
44
|
-
* opens it at, `{host}`
|
|
45
|
-
*
|
|
44
|
+
* opens it at, from the World's sites template. `{host}` stands for the hostname as it is, where the host's names nest
|
|
45
|
+
* (`http://{host}.<world>--<org>.localhost:<port>`); `{site}` for the hostname as one DNS label, its dots as hyphens,
|
|
46
|
+
* where one wildcard certificate covers the host's names (`https://{site}--<world>--<org>.volterdev.com`). A World that
|
|
47
|
+
* routes its sites to a browser sends the template on every request it forwards to a twin. */
|
|
46
48
|
export const TWIN_SITES_HEADER = 'x-volter-world-sites';
|
|
49
|
+
/** A hostname as one DNS label: its dots as hyphens (`www.volter.ai` is `www-volter-ai`). */
|
|
50
|
+
export const siteLabel = (hostname) => hostname.toLowerCase().replace(/\./g, '-');
|
|
51
|
+
/** The address a sites template gives `hostname`, or null where the template is not one or the name makes no address
|
|
52
|
+
* (a label over 63 characters). */
|
|
53
|
+
export function siteUrlOf(template, hostname) {
|
|
54
|
+
const host = hostname.toLowerCase();
|
|
55
|
+
if (!/^[a-z0-9.-]+$/.test(host))
|
|
56
|
+
return null;
|
|
57
|
+
// a one-label site is never an IDN's (`xn--…` would be read as punycode, and is no address)
|
|
58
|
+
const filled = /^https?:\/\/\{host\}\.[A-Za-z0-9.-]+(:\d+)?$/.test(template) ? template.replace('{host}', host)
|
|
59
|
+
: /^https?:\/\/\{site\}--[A-Za-z0-9.-]+(:\d+)?$/.test(template) && !host.startsWith('xn--') ? template.replace('{site}', siteLabel(host)) : null;
|
|
60
|
+
try {
|
|
61
|
+
return filled && new URL(filled).hostname.split('.').every((l) => l.length > 0 && l.length <= 63) ? filled : null;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
47
67
|
/** Where a page links a hostname the twin answers: the World's address for it when the World shows sites, else the
|
|
48
68
|
* hostname itself (reached through the World's proxy, or the vendor). A pack's screen links a site from this, as it
|
|
49
69
|
* mints its own URLs from twinPublicBase. */
|
|
50
70
|
export function twinSiteUrl(request, hostname) {
|
|
51
71
|
const at = request.headers.get(TWIN_SITES_HEADER);
|
|
52
|
-
|
|
53
|
-
return at && /^https?:\/\/\{host\}\.[A-Za-z0-9.-]+(:\d+)?$/.test(at) && /^[a-z0-9.-]+$/.test(host) ? at.replace('{host}', host) : `https://${host}`;
|
|
72
|
+
return (at ? siteUrlOf(at, hostname) : null) ?? `https://${hostname.toLowerCase()}`;
|
|
54
73
|
}
|
|
55
74
|
/** The request scopes a pack wrapped in `withRequestScopes` enforces, advertised on its `GET /twin` as
|
|
56
75
|
* `requestScopes`: `read` — a request carrying `x-volter-read-only: 1` (request-scope.ts) has every
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/world-core",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.18",
|
|
4
4
|
"description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"twin",
|
package/src/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from './request-scope.ts'
|
|
|
52
52
|
export { serveHttp, serveStream, type HttpHandler, type HttpServer, type ServeHttpOptions } from './serve-http.ts';
|
|
53
53
|
export type { TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.ts';
|
|
54
54
|
// where a page links a hostname its twin answers, inside the World that shows it
|
|
55
|
-
export { twinSiteUrl } from './twin-fetch.ts';
|
|
55
|
+
export { siteLabel, siteUrlOf, twinSiteUrl } from './twin-fetch.ts';
|
|
56
56
|
export { statefulTwinManifest, twinManifest } from './scenario.ts';
|
|
57
57
|
export { assetContentType, packAsset } from './pack-assets.ts';
|
|
58
58
|
export { bytesResponse, contentTypeOf, fileResponse } from './file-response.ts';
|
package/src/runtime.ts
CHANGED
|
@@ -13,7 +13,7 @@ export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioErr
|
|
|
13
13
|
export { WORLD_CLOCK_ENV, worldNow } from './world-clock.ts';
|
|
14
14
|
export { WORLD_ENV_NAMES_ENV, worldEnvValue } from './world-env.ts';
|
|
15
15
|
export { ORIGINAL_PATH_HEADER } from './sigv4.ts';
|
|
16
|
-
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, twinPublicBase, twinSiteUrl, withRequestScopes } from './twin-fetch.ts';
|
|
16
|
+
export { createTwinFetchFromHandler, TWIN_PREFIX_HEADER, TWIN_REQUEST_SCOPES, TWIN_SITES_HEADER, siteLabel, siteUrlOf, twinPublicBase, twinSiteUrl, withRequestScopes } from './twin-fetch.ts';
|
|
17
17
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER, ReadOnlyRequestError, runAsReadOnlyRequest, runAsVendorMove, writesRefused } from './request-scope.ts';
|
|
18
18
|
export { compileSurface, createDerivedFetch, matchOperation } from './derived.ts';
|
|
19
19
|
export { currentTraceparent, deliveryTraceHeaders, newTraceparent, parseTraceparent, runWithRequestTrace, runWithTraceparent, TRACEPARENT_HEADER, traceparentForDelivery, validTraceparent } from './trace-context.ts';
|
package/src/twin-fetch.ts
CHANGED
|
@@ -44,17 +44,32 @@ export function twinPublicBase(request: Request): string {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** Where a World shows a hostname its twins answer (a Workers Custom Domain, an R2 public domain): the address a person
|
|
47
|
-
* opens it at, `{host}`
|
|
48
|
-
*
|
|
47
|
+
* opens it at, from the World's sites template. `{host}` stands for the hostname as it is, where the host's names nest
|
|
48
|
+
* (`http://{host}.<world>--<org>.localhost:<port>`); `{site}` for the hostname as one DNS label, its dots as hyphens,
|
|
49
|
+
* where one wildcard certificate covers the host's names (`https://{site}--<world>--<org>.volterdev.com`). A World that
|
|
50
|
+
* routes its sites to a browser sends the template on every request it forwards to a twin. */
|
|
49
51
|
export const TWIN_SITES_HEADER = 'x-volter-world-sites';
|
|
50
52
|
|
|
53
|
+
/** A hostname as one DNS label: its dots as hyphens (`www.volter.ai` is `www-volter-ai`). */
|
|
54
|
+
export const siteLabel = (hostname: string): string => hostname.toLowerCase().replace(/\./g, '-');
|
|
55
|
+
|
|
56
|
+
/** The address a sites template gives `hostname`, or null where the template is not one or the name makes no address
|
|
57
|
+
* (a label over 63 characters). */
|
|
58
|
+
export function siteUrlOf(template: string, hostname: string): string | null {
|
|
59
|
+
const host = hostname.toLowerCase();
|
|
60
|
+
if (!/^[a-z0-9.-]+$/.test(host)) return null;
|
|
61
|
+
// a one-label site is never an IDN's (`xn--…` would be read as punycode, and is no address)
|
|
62
|
+
const filled = /^https?:\/\/\{host\}\.[A-Za-z0-9.-]+(:\d+)?$/.test(template) ? template.replace('{host}', host)
|
|
63
|
+
: /^https?:\/\/\{site\}--[A-Za-z0-9.-]+(:\d+)?$/.test(template) && !host.startsWith('xn--') ? template.replace('{site}', siteLabel(host)) : null;
|
|
64
|
+
try { return filled && new URL(filled).hostname.split('.').every((l) => l.length > 0 && l.length <= 63) ? filled : null; } catch { return null; }
|
|
65
|
+
}
|
|
66
|
+
|
|
51
67
|
/** Where a page links a hostname the twin answers: the World's address for it when the World shows sites, else the
|
|
52
68
|
* hostname itself (reached through the World's proxy, or the vendor). A pack's screen links a site from this, as it
|
|
53
69
|
* mints its own URLs from twinPublicBase. */
|
|
54
70
|
export function twinSiteUrl(request: Request, hostname: string): string {
|
|
55
71
|
const at = request.headers.get(TWIN_SITES_HEADER);
|
|
56
|
-
|
|
57
|
-
return at && /^https?:\/\/\{host\}\.[A-Za-z0-9.-]+(:\d+)?$/.test(at) && /^[a-z0-9.-]+$/.test(host) ? at.replace('{host}', host) : `https://${host}`;
|
|
72
|
+
return (at ? siteUrlOf(at, hostname) : null) ?? `https://${hostname.toLowerCase()}`;
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
/** A twin's BYTE-STREAM door: a pack whose clients speak a TCP protocol (SMTP, the MySQL wire) serves
|