@volter/world-core 2.0.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/LICENSE +202 -0
- package/README.md +29 -0
- package/app-route.cjs +154 -0
- package/app-route.d.cts +7 -0
- package/attach.cjs +80 -0
- package/dist/app-route.cjs +154 -0
- package/dist/app-route.d.cts +7 -0
- package/dist/attach.cjs +80 -0
- package/dist/generated/pack-facts.json +4306 -0
- package/dist/inject.cjs +1097 -0
- package/dist/network-policy.cjs +92 -0
- package/dist/network-policy.d.cts +10 -0
- package/dist/src/actions.d.ts +276 -0
- package/dist/src/actions.js +436 -0
- package/dist/src/ancestry.d.ts +22 -0
- package/dist/src/ancestry.js +238 -0
- package/dist/src/args.d.ts +3 -0
- package/dist/src/args.js +12 -0
- package/dist/src/blob-store.d.ts +55 -0
- package/dist/src/blob-store.js +186 -0
- package/dist/src/brand-tokens.d.ts +2 -0
- package/dist/src/brand-tokens.js +17 -0
- package/dist/src/changeset.d.ts +431 -0
- package/dist/src/changeset.js +0 -0
- package/dist/src/client-bundle.d.ts +1 -0
- package/dist/src/client-bundle.js +28 -0
- package/dist/src/credential.d.ts +38 -0
- package/dist/src/credential.js +114 -0
- package/dist/src/derived-core.d.ts +452 -0
- package/dist/src/derived-core.js +782 -0
- package/dist/src/derived.d.ts +84 -0
- package/dist/src/derived.js +122 -0
- package/dist/src/emit.d.ts +106 -0
- package/dist/src/emit.js +157 -0
- package/dist/src/executor.d.ts +120 -0
- package/dist/src/executor.js +387 -0
- package/dist/src/file-response.d.ts +3 -0
- package/dist/src/file-response.js +22 -0
- package/dist/src/fork.d.ts +26 -0
- package/dist/src/fork.js +68 -0
- package/dist/src/git/history.d.ts +36 -0
- package/dist/src/git/history.js +298 -0
- package/dist/src/git/index.d.ts +6 -0
- package/dist/src/git/index.js +6 -0
- package/dist/src/git/inflate.d.ts +11 -0
- package/dist/src/git/inflate.js +194 -0
- package/dist/src/git/objects.d.ts +64 -0
- package/dist/src/git/objects.js +161 -0
- package/dist/src/git/pack.d.ts +14 -0
- package/dist/src/git/pack.js +199 -0
- package/dist/src/git/refs.d.ts +19 -0
- package/dist/src/git/refs.js +35 -0
- package/dist/src/git/smart-http.d.ts +45 -0
- package/dist/src/git/smart-http.js +223 -0
- package/dist/src/hash.d.ts +38 -0
- package/dist/src/hash.js +48 -0
- package/dist/src/head.d.ts +140 -0
- package/dist/src/head.js +313 -0
- package/dist/src/history.d.ts +76 -0
- package/dist/src/history.js +322 -0
- package/dist/src/index.d.ts +73 -0
- package/dist/src/index.js +98 -0
- package/dist/src/lifecycle.d.ts +1 -0
- package/dist/src/lifecycle.js +8 -0
- package/dist/src/log.d.ts +254 -0
- package/dist/src/log.js +801 -0
- package/dist/src/mirror-shell.d.ts +2 -0
- package/dist/src/mirror-shell.js +13 -0
- package/dist/src/observe.d.ts +49 -0
- package/dist/src/observe.js +148 -0
- package/dist/src/pack-assets.d.ts +30 -0
- package/dist/src/pack-assets.js +88 -0
- package/dist/src/packRegistry.d.ts +374 -0
- package/dist/src/packRegistry.js +142 -0
- package/dist/src/placeholder-remote.d.ts +22 -0
- package/dist/src/placeholder-remote.js +86 -0
- package/dist/src/proxy.d.ts +25 -0
- package/dist/src/proxy.js +155 -0
- package/dist/src/rateBudget.d.ts +367 -0
- package/dist/src/rateBudget.js +925 -0
- package/dist/src/references.d.ts +18 -0
- package/dist/src/references.js +27 -0
- package/dist/src/remote-execute.d.ts +22 -0
- package/dist/src/remote-execute.js +1 -0
- package/dist/src/resource-blob.d.ts +10 -0
- package/dist/src/resource-blob.js +56 -0
- package/dist/src/scenario.d.ts +197 -0
- package/dist/src/scenario.js +425 -0
- package/dist/src/schemas.d.ts +78 -0
- package/dist/src/schemas.js +50 -0
- package/dist/src/serve-http.d.ts +48 -0
- package/dist/src/serve-http.js +340 -0
- package/dist/src/serve.d.ts +147 -0
- package/dist/src/serve.js +507 -0
- package/dist/src/shared-blob-index.d.ts +4 -0
- package/dist/src/shared-blob-index.js +126 -0
- package/dist/src/state-system.d.ts +70 -0
- package/dist/src/state-system.js +90 -0
- package/dist/src/storage.d.ts +101 -0
- package/dist/src/storage.js +337 -0
- package/dist/src/twin-fetch.d.ts +64 -0
- package/dist/src/twin-fetch.js +91 -0
- package/dist/src/types.d.ts +40 -0
- package/dist/src/types.js +1 -0
- package/dist/src/v1-removed.d.ts +159 -0
- package/dist/src/v1-removed.js +124 -0
- package/dist/src/volter-home.d.ts +5 -0
- package/dist/src/volter-home.js +10 -0
- package/dist/src/world-clock.d.ts +4 -0
- package/dist/src/world-clock.js +32 -0
- package/dist/src/world-env.d.ts +3 -0
- package/dist/src/world-env.js +22 -0
- package/dist/src/world-store-sql.d.ts +27 -0
- package/dist/src/world-store-sql.js +86 -0
- package/dist/src/world-store.d.ts +168 -0
- package/dist/src/world-store.js +475 -0
- package/dist/src/worldConfig.d.ts +9 -0
- package/dist/src/worldConfig.js +17 -0
- package/dist/stream-bridge.cjs +80 -0
- package/dist/vendor-hosts.cjs +200 -0
- package/generated/pack-facts.json +4306 -0
- package/inject.cjs +1097 -0
- package/network-policy.cjs +92 -0
- package/network-policy.d.cts +10 -0
- package/package.json +103 -0
- package/src/actions.ts +564 -0
- package/src/ancestry.ts +213 -0
- package/src/args.ts +14 -0
- package/src/blob-store.ts +185 -0
- package/src/brand-tokens.ts +17 -0
- package/src/changeset.ts +1032 -0
- package/src/client-bundle.ts +29 -0
- package/src/credential.ts +140 -0
- package/src/derived-core.ts +1004 -0
- package/src/derived.ts +176 -0
- package/src/emit.ts +242 -0
- package/src/executor.ts +431 -0
- package/src/file-response.ts +22 -0
- package/src/fork.ts +89 -0
- package/src/git/history.ts +177 -0
- package/src/git/index.ts +6 -0
- package/src/git/inflate.ts +125 -0
- package/src/git/objects.ts +110 -0
- package/src/git/pack.ts +105 -0
- package/src/git/refs.ts +25 -0
- package/src/git/smart-http.ts +149 -0
- package/src/hash.ts +66 -0
- package/src/head.ts +318 -0
- package/src/history.ts +246 -0
- package/src/index.ts +323 -0
- package/src/lifecycle.ts +8 -0
- package/src/log.ts +793 -0
- package/src/mirror-shell.ts +15 -0
- package/src/observe.ts +130 -0
- package/src/pack-assets.ts +81 -0
- package/src/packRegistry.ts +408 -0
- package/src/placeholder-remote.ts +81 -0
- package/src/proxy.ts +183 -0
- package/src/rateBudget.ts +1115 -0
- package/src/references.ts +46 -0
- package/src/remote-execute.ts +26 -0
- package/src/resource-blob.ts +57 -0
- package/src/scenario.ts +479 -0
- package/src/schemas.ts +56 -0
- package/src/serve-http.ts +299 -0
- package/src/serve.ts +618 -0
- package/src/shared-blob-index.ts +108 -0
- package/src/state-system.ts +115 -0
- package/src/storage.ts +407 -0
- package/src/twin-fetch.ts +147 -0
- package/src/types.ts +50 -0
- package/src/v1-removed.ts +172 -0
- package/src/volter-home.ts +11 -0
- package/src/world-clock.ts +33 -0
- package/src/world-env.ts +18 -0
- package/src/world-store-sql.ts +118 -0
- package/src/world-store.ts +572 -0
- package/src/worldConfig.ts +27 -0
- package/stream-bridge.cjs +80 -0
- package/vendor-hosts.cjs +200 -0
package/vendor-hosts.cjs
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// THE VENDOR HOST TABLE — which vendor's twin serves a hostname (and, where two vendors share a host, which path), the
|
|
3
|
+
// one home of that fact in a process, dependency-free and side-effect free. The injector (inject.cjs) routes by it; the
|
|
4
|
+
// application route (app-route.cjs) never answers a name it gives a vendor, in the injector or in a twin's delivery.
|
|
5
|
+
// Moved out of inject.cjs unchanged (2026-09-27).
|
|
6
|
+
// ── PATH-AWARE DISAMBIGUATION (the shared-host case) ─────────────────────────────────────────
|
|
7
|
+
// A predicate is called as `(hostname, pathname)`. `pathname` is OPTIONAL and is `undefined`
|
|
8
|
+
// wherever the caller genuinely does not have one yet — most importantly the proxy's CONNECT
|
|
9
|
+
// handler, which sees only the SNI host before TLS is terminated. So the contract is:
|
|
10
|
+
//
|
|
11
|
+
// • pathname === undefined ⇒ "could this vendor serve ANY path on this host?" (candidacy).
|
|
12
|
+
// The ambient proxy uses this to decide whether to MITM at all, then re-resolves WITH the
|
|
13
|
+
// path once the request is decrypted.
|
|
14
|
+
// • pathname supplied ⇒ "does this vendor serve THIS path on this host?" (routing).
|
|
15
|
+
//
|
|
16
|
+
// Nearly every predicate ignores the second argument, because nearly every vendor owns its host
|
|
17
|
+
// outright. `www.googleapis.com` is the exception: `googleauth` serves the OAuth2 token exchange
|
|
18
|
+
// there and `youtube` serves the Data API v3 at /youtube/v3/*. Since `resolveTwin` returns the
|
|
19
|
+
// FIRST matching vendor in insertion order, a host-only match would give whichever key is declared
|
|
20
|
+
// first the entire host — silently breaking the other twin whenever both are configured in one
|
|
21
|
+
// world. The two predicates below are therefore mutually exclusive on that host BY PATH.
|
|
22
|
+
//
|
|
23
|
+
// THE SHARED-HOST RULE (Cal.com incident, 2026-08): a shared-host predicate must claim ONLY the
|
|
24
|
+
// paths its twin actually serves — never "the rest of the host". Claiming the remainder is how
|
|
25
|
+
// every `@googleapis/calendar` call (37 methods, all defaulting to www.googleapis.com) was routed
|
|
26
|
+
// into the googleauth/gemini twin and answered with a plausible Google-shaped 404: a mis-route
|
|
27
|
+
// that fails OPEN and PLAUSIBLE, strictly worse than a coverage gap. An UNCLAIMED path on a
|
|
28
|
+
// claimed host is refused LOUDLY instead (see unclaimedTwinnedHostPathMessage below): the error
|
|
29
|
+
// names the host as twinned and the path as belonging to no pack in this world.
|
|
30
|
+
/**
|
|
31
|
+
* Does this path belong to the OAuth2 token-exchange surface the googleauth twin actually serves?
|
|
32
|
+
* Exactly the routes gemini-twin.ts §googleauth models: `POST /token` (the oauth2.googleapis.com
|
|
33
|
+
* path, also answered on the legacy host) and `POST /oauth2/v4/token` (the legacy
|
|
34
|
+
* www.googleapis.com token path older google-auth-library versions default to). NOTHING else:
|
|
35
|
+
* /calendar/v3/*, /drive/v3/*, … are other Google products with no twin in this repo, and
|
|
36
|
+
* claiming them would mis-route those SDKs into an auth twin that answers with vendor-shaped
|
|
37
|
+
* 404s (the Cal.com incident).
|
|
38
|
+
*/
|
|
39
|
+
// (The `googleauth` matcher itself is DATA on gemini's descriptor — packages/twin/gemini/src/index.ts.)
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Does this path belong to Google's user-facing OAuth 2.0 / OIDC surface — the one the
|
|
43
|
+
* `googleoauth` PACK serves?
|
|
44
|
+
*
|
|
45
|
+
* accounts.google.com is NOT an API host: it is Google's whole sign-in web property (the account
|
|
46
|
+
* chooser, Gmail SSO, security settings, the Workspace admin login). Claiming the host outright
|
|
47
|
+
* would be the Cal.com mis-route incident again in a much larger blast radius — every Google
|
|
48
|
+
* sign-in a browser in the world performs would land in a twin that models one protocol. So this
|
|
49
|
+
* claims EXACTLY the OAuth/OIDC paths the pack serves and refuses the rest LOUDLY
|
|
50
|
+
* (unclaimedTwinnedHostPathMessage).
|
|
51
|
+
*/
|
|
52
|
+
const isGoogleOAuthConsentPath = (p) =>
|
|
53
|
+
typeof p === 'string'
|
|
54
|
+
&& (/^\/(o\/oauth2\/v2\/auth(\/oauthchooseaccount)?|o\/oauth2\/auth|o\/oauth2\/token|signin\/oauth\/error|\.well-known\/openid-configuration)\/?$/.test(p)
|
|
55
|
+
|| /^\/_twin\//.test(p));
|
|
56
|
+
// ANCHORED, and `/o/oauth2/auth/oauthchooseaccount` deliberately absent. The first version had no
|
|
57
|
+
// terminal anchor, so `/o/oauth2/tokeninfo`, `/signin/oauth/errorPage` and
|
|
58
|
+
// `/.well-known/openid-configuration.json` were all claimed and all 404 — and its alternation also
|
|
59
|
+
// claimed an UN-VERSIONED chooser path the router does not serve (§9 round two). The claim set is
|
|
60
|
+
// now exactly `AUTH_PATHS` + the three singles + the twin-only prefix.
|
|
61
|
+
// NB `/o/oauth2/revoke` (the legacy revocation alias) is NOT claimed: the pack files it as a todo
|
|
62
|
+
// and its handler 404s it. An injector entry claiming a path the twin then refuses routes real
|
|
63
|
+
// traffic into a twin that cannot serve it — the Cal.com mis-route in miniature, and the reason
|
|
64
|
+
// every claim here is checked against what the router actually answers.
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* The oauth2.googleapis.com paths the googleoauth PACK serves: the token endpoint (all three
|
|
68
|
+
* spellings), revocation, and token introspection.
|
|
69
|
+
*/
|
|
70
|
+
const isGoogleOAuthTokenPath = (p) =>
|
|
71
|
+
typeof p === 'string' && /^\/(token|oauth2\/v4\/token|revoke|tokeninfo|device\/code)\/?$/.test(p);
|
|
72
|
+
// `/device/code` is a DELIBERATE exception to "never claim a path the twin refuses", and the two
|
|
73
|
+
// rules genuinely collide here (§9 round two). The twin's own discovery document advertises
|
|
74
|
+
// `device_authorization_endpoint` — because Google's does, and dropping it would be infidelity — so
|
|
75
|
+
// a discovery-driven client WILL dial it. Unclaimed, that client escapes a sealed world and reaches
|
|
76
|
+
// the real Google; claimed, it gets the twin's honest 404. Containment wins: an unmodelled
|
|
77
|
+
// operation must fail LOCALLY, not succeed remotely.
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The www.googleapis.com paths it serves: the v1 (PEM) and v3 (JWK) cert endpoints, and the v3
|
|
81
|
+
* userinfo alias. NOT `/oauth2/v2/*` — Google publishes no v2 certs endpoint at all, and the v2
|
|
82
|
+
* userinfo alias returns a DIFFERENT field set the pack does not model
|
|
83
|
+
* (`googleoauth.endpoints.userinfo_v2`, todo), so its handler refuses it.
|
|
84
|
+
*/
|
|
85
|
+
const isGoogleOAuthApisPath = (p) =>
|
|
86
|
+
typeof p === 'string' && /^\/oauth2\/(v1\/certs|v3\/(certs|userinfo))\/?$/.test(p);
|
|
87
|
+
|
|
88
|
+
// vendor → predicate(hostname, pathname?). A vendor is only active if its twin URL is set.
|
|
89
|
+
// THE HAND TABLE'S ONLY RESIDENTS: keys served by KERNEL packages (browser-assets serves
|
|
90
|
+
// `browserassets` and `googlefavicon`; kernel packages carry no pack descriptor) and
|
|
91
|
+
// `googleoauth`, which must precede gemini's `googleauth` key on the shared token host
|
|
92
|
+
// (`resolveTwin` is first-match in insertion order, and this table is inserted before the
|
|
93
|
+
// compiled descriptors below). Every vendor pack's hosts live on its descriptor as DATA —
|
|
94
|
+
// host | suffix | hostPattern, pathPattern, exclude, key — compiled from pack-facts.json.
|
|
95
|
+
const VENDOR_HOSTS = {
|
|
96
|
+
// google-auth-library exchanges a locally-signed JWT here before ANY
|
|
97
|
+
// Vertex/GCS call — a sealed world must model the exchange or every
|
|
98
|
+
// service-account flow dies in auth before reaching a modeled API.
|
|
99
|
+
//
|
|
100
|
+
// SHARES www.googleapis.com with the `youtube` PACK (whose `hosts` declaration carries the
|
|
101
|
+
// matching pathPattern): this vendor claims
|
|
102
|
+
// ONLY the token-exchange paths its twin serves there (`/token`, `/oauth2/v4/token` —
|
|
103
|
+
// gemini-twin.ts §googleauth; the `googleauth` key on gemini's descriptor). It used to claim "everything that
|
|
104
|
+
// is not YouTube" on that host, which silently swallowed Google Calendar (`/calendar/v3/*` —
|
|
105
|
+
// `@googleapis/calendar` defaults every method to www.googleapis.com) and answered it with
|
|
106
|
+
// plausible Google-shaped 404s from the wrong pack: the Cal.com mis-route incident. Unclaimed
|
|
107
|
+
// paths on this host now refuse loudly instead (unclaimedTwinnedHostPathMessage). With no
|
|
108
|
+
// pathname it still claims the host so the ambient proxy MITMs it; the post-decrypt resolve
|
|
109
|
+
// then routes each request to the right twin — or to the loud refusal.
|
|
110
|
+
//
|
|
111
|
+
// GOOGLEOAUTH — the real PACK (@volter/twin-googleoauth), declared BEFORE `googleauth` on purpose.
|
|
112
|
+
// `resolveTwin` returns the FIRST matching vendor in insertion order, so in a world where BOTH are
|
|
113
|
+
// configured the token endpoint goes to the pack rather than to the pack-less plumbing key — which
|
|
114
|
+
// is what you want, because the pack's token endpoint is a strict SUPERSET: it serves
|
|
115
|
+
// authorization_code and refresh_token (which googleauth has no state for) AND the
|
|
116
|
+
// jwt-bearer service-account exchange googleauth exists for, with a REAL RS256 id_token instead of
|
|
117
|
+
// gemini's `alg: none` stub. A world running ONLY the gemini twin still resolves through
|
|
118
|
+
// `googleauth` below, unchanged.
|
|
119
|
+
//
|
|
120
|
+
// FOUR hosts, every one path-scoped, because Google spreads ONE product across them and shares
|
|
121
|
+
// three of them with other products:
|
|
122
|
+
// • accounts.google.com the consent screen, the error page, OIDC discovery. NOT claimed
|
|
123
|
+
// outright: this host is Google's entire sign-in web property.
|
|
124
|
+
// • oauth2.googleapis.com token / revoke / tokeninfo. SHARED with `googleauth`.
|
|
125
|
+
// • www.googleapis.com the JWKS + legacy userinfo. SHARED with `googleauth` AND
|
|
126
|
+
// `youtube`, and disambiguated from both BY PATH.
|
|
127
|
+
// • openidconnect.googleapis.com the OIDC userinfo endpoint. Not shared.
|
|
128
|
+
googleoauth: (h, p) =>
|
|
129
|
+
(h === 'accounts.google.com' && (p === undefined || isGoogleOAuthConsentPath(p)))
|
|
130
|
+
|| (h === 'oauth2.googleapis.com' && (p === undefined || isGoogleOAuthTokenPath(p)))
|
|
131
|
+
|| (h === 'www.googleapis.com' && (p === undefined || isGoogleOAuthApisPath(p)))
|
|
132
|
+
|| h === 'openidconnect.googleapis.com',
|
|
133
|
+
googlefavicon: (h) => h === 'www.google.com' || h === 'google.com' || h === 't2.gstatic.com',
|
|
134
|
+
browserassets: (h) =>
|
|
135
|
+
h === 'cdnjs.cloudflare.com' ||
|
|
136
|
+
h === 'www.googletagmanager.com' ||
|
|
137
|
+
h === 'www.google-analytics.com' ||
|
|
138
|
+
h === 'connect.facebook.net' ||
|
|
139
|
+
h === 'snap.licdn.com' ||
|
|
140
|
+
h === 'px.ads.linkedin.com' ||
|
|
141
|
+
h === 'static.hotjar.com' ||
|
|
142
|
+
h === 'fonts.googleapis.com' ||
|
|
143
|
+
h === 'fonts.gstatic.com' ||
|
|
144
|
+
h === 'api.fontshare.com' ||
|
|
145
|
+
h === 'images.subscribe.dev' ||
|
|
146
|
+
h === 'www.youtube.com' ||
|
|
147
|
+
h === 'www.youtube-nocookie.com' ||
|
|
148
|
+
h === 'i.ytimg.com',
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// descriptor-first migration (adding-a-twin.md §3): packs now declare their hosts as DATA on their descriptor
|
|
152
|
+
// (`hosts` on TwinPack), compiled into the committed pack-facts artifact — a plain JSON this
|
|
153
|
+
// preloaded, dependency-free module can `require` natively. The hand table above shrinks toward
|
|
154
|
+
// empty as entries move; a vendor present in both homes throws (dual declaration is the drift
|
|
155
|
+
// this migration ends, and a broken checkout should refuse to inject rather than half-route).
|
|
156
|
+
{
|
|
157
|
+
const { packs } = require('./generated/pack-facts.json');
|
|
158
|
+
for (const vendor of Object.keys(packs)) {
|
|
159
|
+
const rules = packs[vendor].hosts;
|
|
160
|
+
if (!rules || rules.length === 0) continue;
|
|
161
|
+
if (VENDOR_HOSTS[vendor]) {
|
|
162
|
+
throw new Error(`inject: vendor "${vendor}" declares hosts on its pack descriptor AND in the hand VENDOR_HOSTS table — one home per fact; delete the hand entry.`);
|
|
163
|
+
}
|
|
164
|
+
// Rules group by `key` (default: the vendor id) — an aws descriptor declares the s3 /
|
|
165
|
+
// dynamodb / … routing identities its consolidated twin answers under; gemini declares
|
|
166
|
+
// `googleauth`. A key matches when ANY include rule matches AND NO exclude rule matches
|
|
167
|
+
// (upstash: `.upstash.io` minus the vector hosts).
|
|
168
|
+
const byKey = new Map();
|
|
169
|
+
for (const rule of rules) {
|
|
170
|
+
const key = rule.key === undefined ? vendor : rule.key;
|
|
171
|
+
if (!byKey.has(key)) byKey.set(key, []);
|
|
172
|
+
byKey.get(key).push(rule);
|
|
173
|
+
}
|
|
174
|
+
for (const [key, keyRules] of byKey) {
|
|
175
|
+
if (VENDOR_HOSTS[key]) {
|
|
176
|
+
throw new Error(`inject: key "${key}" (pack ${vendor}) is declared twice — on this descriptor and in the hand VENDOR_HOSTS table or another pack's descriptor; a key has one home.`);
|
|
177
|
+
}
|
|
178
|
+
const compile = (rule) => {
|
|
179
|
+
const selectors = ['host', 'suffix', 'hostPattern'].filter((k) => rule[k] !== undefined).length;
|
|
180
|
+
if (selectors !== 1) throw new Error(`inject: key "${key}" (pack ${vendor}) rule ${JSON.stringify(rule)} — exactly one of host | suffix | hostPattern (pack-facts.json is hand-edited or stale)`);
|
|
181
|
+
const hostRe = rule.hostPattern === undefined ? null : new RegExp(rule.hostPattern);
|
|
182
|
+
const pathRe = rule.pathPattern === undefined ? null : new RegExp(rule.pathPattern);
|
|
183
|
+
return (h, p) =>
|
|
184
|
+
(rule.host !== undefined ? h === rule.host : rule.suffix !== undefined ? h.endsWith(rule.suffix) : hostRe.test(h))
|
|
185
|
+
&& (pathRe === null || p === undefined || pathRe.test(p));
|
|
186
|
+
};
|
|
187
|
+
const includes = keyRules.filter((r) => r.exclude !== true).map(compile);
|
|
188
|
+
const excludes = keyRules.filter((r) => r.exclude === true).map(compile);
|
|
189
|
+
VENDOR_HOSTS[key] = (h, p) => includes.some((m) => m(h, p)) && !excludes.some((m) => m(h, p));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/** Whether any vendor's host rule names `host` (at the host level, whatever the path), whether or not its twin runs. */
|
|
195
|
+
function isVendorHost(host) {
|
|
196
|
+
const h = String(host || '').toLowerCase().replace(/\.$/, '');
|
|
197
|
+
return Object.keys(VENDOR_HOSTS).some((vendor) => VENDOR_HOSTS[vendor](h));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
module.exports = { VENDOR_HOSTS, isVendorHost };
|