@grest-ts/http 0.0.67 → 0.0.68
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/README.md +23 -0
- package/dist/src/_dedupCheck.js +1 -1
- package/dist/src/client/GGHttpSchema.createClient.d.ts +10 -0
- package/dist/src/client/GGHttpSchema.createClient.d.ts.map +1 -1
- package/dist/src/client/GGHttpSchema.createClient.js +19 -2
- package/dist/src/client/GGHttpSchema.createClient.js.map +1 -1
- package/dist/src/client/GGHttpSchema.createClient.node.d.ts.map +1 -1
- package/dist/src/client/GGHttpSchema.createClient.node.js +3 -1
- package/dist/src/client/GGHttpSchema.createClient.node.js.map +1 -1
- package/dist/src/client/nodeConnectionTransport.node.d.ts +5 -0
- package/dist/src/client/nodeConnectionTransport.node.d.ts.map +1 -0
- package/dist/src/client/nodeConnectionTransport.node.js +168 -0
- package/dist/src/client/nodeConnectionTransport.node.js.map +1 -0
- package/dist/src/index-browser.d.ts +1 -0
- package/dist/src/index-browser.d.ts.map +1 -1
- package/dist/src/index-browser.js +1 -0
- package/dist/src/index-browser.js.map +1 -1
- package/dist/src/index-node.d.ts +2 -0
- package/dist/src/index-node.d.ts.map +1 -1
- package/dist/src/index-node.js +2 -0
- package/dist/src/index-node.js.map +1 -1
- package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.d.ts.map +1 -1
- package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.js +10 -1
- package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.js.map +1 -1
- package/dist/src/schema/GGConnectionSettingsKey.d.ts +21 -0
- package/dist/src/schema/GGConnectionSettingsKey.d.ts.map +1 -0
- package/dist/src/schema/GGConnectionSettingsKey.js +27 -0
- package/dist/src/schema/GGConnectionSettingsKey.js.map +1 -0
- package/dist/src/schema/GGHttpSchema.d.ts +2 -1
- package/dist/src/schema/GGHttpSchema.d.ts.map +1 -1
- package/dist/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/_dedupCheck.ts +1 -1
- package/src/client/GGHttpSchema.createClient.node.ts +3 -1
- package/src/client/GGHttpSchema.createClient.ts +32 -2
- package/src/client/nodeConnectionTransport.node.test.ts +320 -0
- package/src/client/nodeConnectionTransport.node.ts +181 -0
- package/src/index-browser.bundle.node.test.ts +51 -0
- package/src/index-browser.ts +1 -0
- package/src/index-node.ts +2 -0
- package/src/rpc/RpcRequest/GGRpcRequestBuilder.ts +10 -2
- package/src/schema/GGConnectionSettingsKey.ts +28 -0
- package/src/schema/GGHttpSchema.ts +2 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {describe, it, expect} from 'vitest'
|
|
2
|
+
import {readFileSync, existsSync} from 'node:fs'
|
|
3
|
+
import {dirname, resolve} from 'node:path'
|
|
4
|
+
import {fileURLToPath} from 'node:url'
|
|
5
|
+
|
|
6
|
+
// Walk the real import graph from the browser entry and assert nothing node-only is reachable:
|
|
7
|
+
// no `node:*` specifier and no `*.node` module. This is what would otherwise leak `node:https`
|
|
8
|
+
// (the pinned-TLS transport) into a browser build.
|
|
9
|
+
const SRC = dirname(fileURLToPath(import.meta.url))
|
|
10
|
+
|
|
11
|
+
function localImports(file: string): string[] {
|
|
12
|
+
const code = readFileSync(file, "utf8")
|
|
13
|
+
const specifiers = [...code.matchAll(/(?:from|import)\s+["']([^"']+)["']/g)].map(m => m[1])
|
|
14
|
+
return specifiers.filter(s => s.startsWith("."))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function resolveLocal(fromFile: string, spec: string): string | undefined {
|
|
18
|
+
const base = resolve(dirname(fromFile), spec)
|
|
19
|
+
for (const candidate of [`${base}.ts`, `${base}/index.ts`]) {
|
|
20
|
+
if (existsSync(candidate)) return candidate
|
|
21
|
+
}
|
|
22
|
+
return undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe('browser bundle safety', () => {
|
|
26
|
+
it('the browser entry graph references no node:* import and no *.node module', () => {
|
|
27
|
+
const offenders: string[] = []
|
|
28
|
+
const seen = new Set<string>()
|
|
29
|
+
const queue = [resolve(SRC, "index-browser.ts")]
|
|
30
|
+
|
|
31
|
+
while (queue.length) {
|
|
32
|
+
const file = queue.shift()!
|
|
33
|
+
if (seen.has(file)) continue
|
|
34
|
+
seen.add(file)
|
|
35
|
+
|
|
36
|
+
const code = readFileSync(file, "utf8")
|
|
37
|
+
if (/(?:from|import)\s+["']node:/.test(code)) offenders.push(`${file} imports a node:* module`)
|
|
38
|
+
|
|
39
|
+
for (const spec of localImports(file)) {
|
|
40
|
+
if (/\.node$/.test(spec)) {
|
|
41
|
+
offenders.push(`${file} imports node-only module "${spec}"`)
|
|
42
|
+
continue
|
|
43
|
+
}
|
|
44
|
+
const target = resolveLocal(file, spec)
|
|
45
|
+
if (target) queue.push(target)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
expect(offenders).toEqual([])
|
|
50
|
+
})
|
|
51
|
+
})
|
package/src/index-browser.ts
CHANGED
|
@@ -4,6 +4,7 @@ export * from "./schema/GGHttpSchema";
|
|
|
4
4
|
export * from "./schema/GGCookie";
|
|
5
5
|
export * from "./schema/GGWireContextKey";
|
|
6
6
|
export * from "./schema/GGHeader";
|
|
7
|
+
export * from "./schema/GGConnectionSettingsKey";
|
|
7
8
|
export * from "./rpc/GGHttpRouteRPC";
|
|
8
9
|
export * from "./rpc/RpcRequest/GGRpcRequestBuilder";
|
|
9
10
|
export * from "./rpc/RpcResponse/GGRpcResponseParser";
|
package/src/index-node.ts
CHANGED
|
@@ -25,6 +25,7 @@ export * from "./schema/GGCookie";
|
|
|
25
25
|
export * from "./schema/GGWireContextKey";
|
|
26
26
|
export * from "./schema/GGWireContextKey.node";
|
|
27
27
|
export * from "./schema/GGHeader";
|
|
28
|
+
export * from "./schema/GGConnectionSettingsKey";
|
|
28
29
|
export * from "./rpc/GGHttpRouteRPC";
|
|
29
30
|
export * from "./rpc/openApiSuccessResponse";
|
|
30
31
|
export * from "./rpc/openApiHelpers";
|
|
@@ -45,6 +46,7 @@ export * from "./schema/GGHttpPermissionsChecker";
|
|
|
45
46
|
// Client
|
|
46
47
|
export * from "./client/GGContextKeySynchronizer";
|
|
47
48
|
export * from "./client/GGHttpSchema.createClient";
|
|
49
|
+
export * from "./client/nodeConnectionTransport.node";
|
|
48
50
|
export * from "./server/GGHttpSchema.startServer";
|
|
49
51
|
|
|
50
52
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {HttpMethod} from "@grest-ts/common";
|
|
2
2
|
import {GGContractMethod} from "@grest-ts/schema";
|
|
3
3
|
import {ClientHttpRouteToRpcTransformClientConfig, GGHttpFetchRequest} from "../../schema/GGHttpSchema";
|
|
4
|
-
import {GGContextKey, type GGTransportMiddleware} from "@grest-ts/context";
|
|
4
|
+
import {GGContextKey, type GGConnectionSettings, type GGTransportMiddleware} from "@grest-ts/context";
|
|
5
5
|
import {GGContextKeySynchronizer} from "../../client/GGContextKeySynchronizer";
|
|
6
6
|
|
|
7
7
|
export class GGRpcRequestBuilder {
|
|
@@ -50,7 +50,15 @@ export class GGRpcRequestBuilder {
|
|
|
50
50
|
await GGContextKeySynchronizer.waitFor(mw)
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
let settings: GGConnectionSettings | undefined
|
|
54
|
+
for (const mw of this.middlewares ?? []) {
|
|
55
|
+
mw.update?.(result)
|
|
56
|
+
if (mw.connectionSettings) {
|
|
57
|
+
settings ??= {}
|
|
58
|
+
mw.connectionSettings(settings)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (settings) result.connectionSettings = settings
|
|
54
62
|
return result
|
|
55
63
|
}
|
|
56
64
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {GGContextKey, IsConnectionSettings, type GGConnectionSettings, type GGTransportMiddleware} from "@grest-ts/context"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A context key that is also a transport middleware: it holds per-request connection settings
|
|
5
|
+
* (e.g. a TLS pin) in ambient context and contributes them to the outbound request.
|
|
6
|
+
*
|
|
7
|
+
* export const CONN = new GGConnectionSettingsKey("conn")
|
|
8
|
+
* // schema: use: [CONN]
|
|
9
|
+
* CONN.set({host, port, tlsPin: {fingerprint256}}) // inside the request scope, then call the client
|
|
10
|
+
*
|
|
11
|
+
* Apps create their own instances (one per target class) — there is no framework singleton.
|
|
12
|
+
* Browser-safe: it only reads ambient context and copies plain data; the node transport
|
|
13
|
+
* consumes the settings, the browser fetch transport rejects them (settings are node-only).
|
|
14
|
+
*
|
|
15
|
+
* Nothing special — just a `GGContextKey<GGConnectionSettings>` whose `connectionSettings()`
|
|
16
|
+
* hook copies its own value out. The same could be written inline; this is the shortcut.
|
|
17
|
+
*/
|
|
18
|
+
export class GGConnectionSettingsKey extends GGContextKey<GGConnectionSettings> implements GGTransportMiddleware {
|
|
19
|
+
|
|
20
|
+
constructor(name: string) {
|
|
21
|
+
super(name, IsConnectionSettings)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public connectionSettings(settings: GGConnectionSettings): void {
|
|
25
|
+
const value = this.get()
|
|
26
|
+
if (value) Object.assign(settings, value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {ERROR, ERROR_JSON, GGContractApiDefinition, GGContractClass, GGContractMethod, GGSchema, GGSchemaDescription, OK} from "@grest-ts/schema";
|
|
2
2
|
import type {HttpMethod} from "@grest-ts/common";
|
|
3
3
|
import type http from "http";
|
|
4
|
-
import type {GGContextKey, GGTransportMiddleware} from "@grest-ts/context";
|
|
4
|
+
import type {GGConnectionSettings, GGContextKey, GGTransportMiddleware} from "@grest-ts/context";
|
|
5
5
|
import type {OpenAPIV3_1} from "openapi-types";
|
|
6
6
|
|
|
7
7
|
export interface GGHttpSchemaConfig<TContract extends GGContractApiDefinition> {
|
|
@@ -51,6 +51,7 @@ export interface GGHttpFetchRequest {
|
|
|
51
51
|
method: HttpMethod;
|
|
52
52
|
headers: Record<string, string>;
|
|
53
53
|
body: string | FormData | undefined;
|
|
54
|
+
connectionSettings?: GGConnectionSettings;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
// --------------------------------------------------------------------------------------------------------
|