@grest-ts/http 0.0.66 → 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.
Files changed (43) hide show
  1. package/README.md +23 -0
  2. package/dist/src/_dedupCheck.js +1 -1
  3. package/dist/src/client/GGHttpSchema.createClient.d.ts +10 -0
  4. package/dist/src/client/GGHttpSchema.createClient.d.ts.map +1 -1
  5. package/dist/src/client/GGHttpSchema.createClient.js +19 -2
  6. package/dist/src/client/GGHttpSchema.createClient.js.map +1 -1
  7. package/dist/src/client/GGHttpSchema.createClient.node.d.ts.map +1 -1
  8. package/dist/src/client/GGHttpSchema.createClient.node.js +3 -1
  9. package/dist/src/client/GGHttpSchema.createClient.node.js.map +1 -1
  10. package/dist/src/client/nodeConnectionTransport.node.d.ts +5 -0
  11. package/dist/src/client/nodeConnectionTransport.node.d.ts.map +1 -0
  12. package/dist/src/client/nodeConnectionTransport.node.js +168 -0
  13. package/dist/src/client/nodeConnectionTransport.node.js.map +1 -0
  14. package/dist/src/index-browser.d.ts +1 -0
  15. package/dist/src/index-browser.d.ts.map +1 -1
  16. package/dist/src/index-browser.js +1 -0
  17. package/dist/src/index-browser.js.map +1 -1
  18. package/dist/src/index-node.d.ts +2 -0
  19. package/dist/src/index-node.d.ts.map +1 -1
  20. package/dist/src/index-node.js +2 -0
  21. package/dist/src/index-node.js.map +1 -1
  22. package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.d.ts.map +1 -1
  23. package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.js +10 -1
  24. package/dist/src/rpc/RpcRequest/GGRpcRequestBuilder.js.map +1 -1
  25. package/dist/src/schema/GGConnectionSettingsKey.d.ts +21 -0
  26. package/dist/src/schema/GGConnectionSettingsKey.d.ts.map +1 -0
  27. package/dist/src/schema/GGConnectionSettingsKey.js +27 -0
  28. package/dist/src/schema/GGConnectionSettingsKey.js.map +1 -0
  29. package/dist/src/schema/GGHttpSchema.d.ts +2 -1
  30. package/dist/src/schema/GGHttpSchema.d.ts.map +1 -1
  31. package/dist/tsconfig.publish.tsbuildinfo +1 -1
  32. package/package.json +10 -10
  33. package/src/_dedupCheck.ts +1 -1
  34. package/src/client/GGHttpSchema.createClient.node.ts +3 -1
  35. package/src/client/GGHttpSchema.createClient.ts +32 -2
  36. package/src/client/nodeConnectionTransport.node.test.ts +320 -0
  37. package/src/client/nodeConnectionTransport.node.ts +181 -0
  38. package/src/index-browser.bundle.node.test.ts +51 -0
  39. package/src/index-browser.ts +1 -0
  40. package/src/index-node.ts +2 -0
  41. package/src/rpc/RpcRequest/GGRpcRequestBuilder.ts +10 -2
  42. package/src/schema/GGConnectionSettingsKey.ts +28 -0
  43. 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
+ })
@@ -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
- this.middlewares?.forEach(mw => mw.update?.(result))
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
  // --------------------------------------------------------------------------------------------------------