@substrat-run/adapter-cloudflare 0.91.1 → 0.92.1
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/client-context.d.ts +46 -0
- package/dist/client-context.d.ts.map +1 -0
- package/dist/client-context.js +59 -0
- package/dist/client-context.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Cloudflare read of "who is on the other end" — normalised ONCE, here.
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare puts what it knows about a request's origin on `request.cf`: country,
|
|
5
|
+
* region, city, timezone, and a dozen more fields (colo, ASN, TLS version, bot
|
|
6
|
+
* score) that answer questions a vertical does not ask. This is the only place the
|
|
7
|
+
* platform reads that object. Everything above it — a host's harness, a vertical's
|
|
8
|
+
* operation input, a row in a table — sees `ClientContext` from contracts, and would
|
|
9
|
+
* see the identical shape from a node dev server or a future edge that says the same
|
|
10
|
+
* things in headers.
|
|
11
|
+
*
|
|
12
|
+
* What is normalised, and why:
|
|
13
|
+
*
|
|
14
|
+
* - `country` `T1` (Tor) and `XX` (unknown) are Cloudflare's sentinels, not
|
|
15
|
+
* countries. They become null rather than a two-letter code a UI would try to
|
|
16
|
+
* render as a flag.
|
|
17
|
+
* - `region` is the NAME (`Stockholm County`), not `regionCode`; codes are
|
|
18
|
+
* per-country schemes and a person reads the name.
|
|
19
|
+
* - Every field is a string or absent on `cf`, and absent on a request that did not
|
|
20
|
+
* come through the edge (`wrangler dev`, the vitest pool) — so each is read
|
|
21
|
+
* defensively and missing means null, never a throw.
|
|
22
|
+
* - Latitude, longitude and postal code are NOT carried. They locate a person to a
|
|
23
|
+
* street, and nothing a support desk does needs more than the city.
|
|
24
|
+
*
|
|
25
|
+
* `IncomingRequestCfProperties` is typed loosely (`unknown`) at the seam on purpose:
|
|
26
|
+
* the workers-types shape has changed between majors, and a structural read that
|
|
27
|
+
* tolerates a missing field survives that where a typed one would not compile.
|
|
28
|
+
*/
|
|
29
|
+
import { type ClientContext, type ClientGeo } from '@substrat-run/contracts';
|
|
30
|
+
/** What a Worker's `Request` carries beyond the standard: the edge's own facts. */
|
|
31
|
+
export interface CloudflareRequestLike {
|
|
32
|
+
readonly headers: {
|
|
33
|
+
get(name: string): string | null;
|
|
34
|
+
};
|
|
35
|
+
readonly cf?: unknown;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The geo half of `request.cf`, in the platform's shape.
|
|
39
|
+
*
|
|
40
|
+
* Takes the `cf` object rather than the request so a caller holding the object some
|
|
41
|
+
* other way (a queued job that stashed it, a test) can use it too.
|
|
42
|
+
*/
|
|
43
|
+
export declare function cloudflareGeo(cf: unknown): ClientGeo;
|
|
44
|
+
/** The whole `ClientContext` for a request that came through Cloudflare's edge. */
|
|
45
|
+
export declare function cloudflareClientContext(request: CloudflareRequestLike): ClientContext;
|
|
46
|
+
//# sourceMappingURL=client-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-context.d.ts","sourceRoot":"","sources":["../src/client-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAA8B,KAAK,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEzG,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,OAAO,EAAE;QAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC;CACvB;AASD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,OAAO,GAAG,SAAS,CAYpD;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa,CAErF"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Cloudflare read of "who is on the other end" — normalised ONCE, here.
|
|
3
|
+
*
|
|
4
|
+
* Cloudflare puts what it knows about a request's origin on `request.cf`: country,
|
|
5
|
+
* region, city, timezone, and a dozen more fields (colo, ASN, TLS version, bot
|
|
6
|
+
* score) that answer questions a vertical does not ask. This is the only place the
|
|
7
|
+
* platform reads that object. Everything above it — a host's harness, a vertical's
|
|
8
|
+
* operation input, a row in a table — sees `ClientContext` from contracts, and would
|
|
9
|
+
* see the identical shape from a node dev server or a future edge that says the same
|
|
10
|
+
* things in headers.
|
|
11
|
+
*
|
|
12
|
+
* What is normalised, and why:
|
|
13
|
+
*
|
|
14
|
+
* - `country` `T1` (Tor) and `XX` (unknown) are Cloudflare's sentinels, not
|
|
15
|
+
* countries. They become null rather than a two-letter code a UI would try to
|
|
16
|
+
* render as a flag.
|
|
17
|
+
* - `region` is the NAME (`Stockholm County`), not `regionCode`; codes are
|
|
18
|
+
* per-country schemes and a person reads the name.
|
|
19
|
+
* - Every field is a string or absent on `cf`, and absent on a request that did not
|
|
20
|
+
* come through the edge (`wrangler dev`, the vitest pool) — so each is read
|
|
21
|
+
* defensively and missing means null, never a throw.
|
|
22
|
+
* - Latitude, longitude and postal code are NOT carried. They locate a person to a
|
|
23
|
+
* street, and nothing a support desk does needs more than the city.
|
|
24
|
+
*
|
|
25
|
+
* `IncomingRequestCfProperties` is typed loosely (`unknown`) at the seam on purpose:
|
|
26
|
+
* the workers-types shape has changed between majors, and a structural read that
|
|
27
|
+
* tolerates a missing field survives that where a typed one would not compile.
|
|
28
|
+
*/
|
|
29
|
+
import { clientContextOf, EMPTY_GEO } from '@substrat-run/contracts';
|
|
30
|
+
const NOT_A_COUNTRY = new Set(['T1', 'XX']);
|
|
31
|
+
function str(cf, key) {
|
|
32
|
+
const v = cf[key];
|
|
33
|
+
return typeof v === 'string' && v.trim() !== '' ? v.trim() : null;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The geo half of `request.cf`, in the platform's shape.
|
|
37
|
+
*
|
|
38
|
+
* Takes the `cf` object rather than the request so a caller holding the object some
|
|
39
|
+
* other way (a queued job that stashed it, a test) can use it too.
|
|
40
|
+
*/
|
|
41
|
+
export function cloudflareGeo(cf) {
|
|
42
|
+
if (!cf || typeof cf !== 'object')
|
|
43
|
+
return EMPTY_GEO;
|
|
44
|
+
const o = cf;
|
|
45
|
+
const country = str(o, 'country');
|
|
46
|
+
const continent = str(o, 'continent');
|
|
47
|
+
return {
|
|
48
|
+
country: country && /^[A-Z]{2}$/.test(country) && !NOT_A_COUNTRY.has(country) ? country : null,
|
|
49
|
+
region: str(o, 'region'),
|
|
50
|
+
city: str(o, 'city'),
|
|
51
|
+
timezone: str(o, 'timezone'),
|
|
52
|
+
continent: continent && /^[A-Z]{2}$/.test(continent) ? continent : null,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** The whole `ClientContext` for a request that came through Cloudflare's edge. */
|
|
56
|
+
export function cloudflareClientContext(request) {
|
|
57
|
+
return clientContextOf(request.headers, cloudflareGeo(request.cf));
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=client-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-context.js","sourceRoot":"","sources":["../src/client-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,EAAE,eAAe,EAAE,SAAS,EAAsC,MAAM,yBAAyB,CAAC;AAQzG,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;AAE5C,SAAS,GAAG,CAAC,EAA2B,EAAE,GAAW;IACnD,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;IAClB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACpE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,EAAW;IACvC,IAAI,CAAC,EAAE,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,CAAC,GAAG,EAA6B,CAAC;IACxC,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAClC,MAAM,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;IACtC,OAAO;QACL,OAAO,EAAE,OAAO,IAAI,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC9F,MAAM,EAAE,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;QACxB,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC;QAC5B,SAAS,EAAE,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;KACxE,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,uBAAuB,CAAC,OAA8B;IACpE,OAAO,eAAe,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,4 +31,6 @@ export type { R2BlobStores, R2BlobStoresOptions } from './r2.js';
|
|
|
31
31
|
export { createRouteResolver } from './route-resolver.js';
|
|
32
32
|
export type { RouteResolver } from './route-resolver.js';
|
|
33
33
|
export type { ControlPlaneReader, DoCheckerDeps } from './checker.js';
|
|
34
|
+
export { cloudflareClientContext, cloudflareGeo } from './client-context.js';
|
|
35
|
+
export type { CloudflareRequestLike } from './client-context.js';
|
|
34
36
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAChD,YAAY,EAAE,0BAA0B,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,YAAY,EACV,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -24,4 +24,5 @@ export { defineScopeSweeperDO, SCOPE_SWEEPER_NAME } from './scope-sweeper-do.js'
|
|
|
24
24
|
export { createD1TenantStores, d1TenantRelationalStore, tenantStoreDatabaseName, } from './d1.js';
|
|
25
25
|
export { blobStoreBucketName, createR2BlobStores, r2TenantBlobStore, } from './r2.js';
|
|
26
26
|
export { createRouteResolver } from './route-resolver.js';
|
|
27
|
+
export { cloudflareClientContext, cloudflareGeo } from './client-context.js';
|
|
27
28
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQjF,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAQjF,OAAO,EACL,oBAAoB,EACpB,uBAAuB,EACvB,uBAAuB,GACxB,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1D,OAAO,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/adapter-cloudflare",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.92.1",
|
|
4
4
|
"description": "Cloudflare Durable-Object scope host (D-14): DO-per-scope, real kernel semantics on Workers",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"dist"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@substrat-run/contracts": "^0.
|
|
30
|
-
"@substrat-run/kernel": "^0.
|
|
29
|
+
"@substrat-run/contracts": "^0.92.1",
|
|
30
|
+
"@substrat-run/kernel": "^0.92.1"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@cloudflare/vitest-pool-workers": "^0.9.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"typescript": "^7.0.0",
|
|
36
36
|
"vitest": "^3.2.7",
|
|
37
37
|
"wrangler": "^4.110.0",
|
|
38
|
-
"@substrat-run/contract-tests": "^0.
|
|
38
|
+
"@substrat-run/contract-tests": "^0.92.1"
|
|
39
39
|
},
|
|
40
40
|
"publishConfig": {
|
|
41
41
|
"access": "public"
|