service-bridge 2.0.0-alpha.6 → 2.0.0-alpha.7

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.
@@ -0,0 +1,53 @@
1
+ import {
2
+ mintRootContext,
3
+ parseXSbTrace
4
+ } from "./chunk-BNKAGKEP.js";
5
+
6
+ // src/http/_common/body-capture.ts
7
+ var RAW_JSON_CONTRACT = "raw/json";
8
+ var encoder = new TextEncoder();
9
+ function bodyToBytes(body) {
10
+ if (body === void 0 || body === null) return null;
11
+ if (body instanceof Uint8Array) return body.byteLength ? body : null;
12
+ if (typeof body === "string") {
13
+ const s = body.trim();
14
+ if (!s || s === "{}" || s === "null") return null;
15
+ return encoder.encode(body);
16
+ }
17
+ try {
18
+ const json = JSON.stringify(body);
19
+ if (!json || json === "{}" || json === "null") return null;
20
+ return encoder.encode(json);
21
+ } catch {
22
+ return null;
23
+ }
24
+ }
25
+
26
+ // src/http/_common/trace-wrap.ts
27
+ function contextFromXSbTrace(header) {
28
+ if (header == null) return mintRootContext();
29
+ const parsed = parseXSbTrace(header);
30
+ if (parsed == null) return mintRootContext();
31
+ return parsed;
32
+ }
33
+
34
+ // src/http/endpoint.ts
35
+ var _warned = false;
36
+ function resolveHttpAdvertiseHost(explicit) {
37
+ if (explicit && explicit.length > 0) return explicit;
38
+ if (!_warned) {
39
+ _warned = true;
40
+ console.warn(
41
+ "[ServiceBridge] http advertise host not configured \u2014 falling back to 127.0.0.1. Pass { host } to the HTTP plugin for cross-host reachability."
42
+ );
43
+ }
44
+ return "127.0.0.1";
45
+ }
46
+
47
+ export {
48
+ RAW_JSON_CONTRACT,
49
+ bodyToBytes,
50
+ contextFromXSbTrace,
51
+ resolveHttpAdvertiseHost
52
+ };
53
+ //# sourceMappingURL=chunk-7BOF2Y52.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/http/_common/body-capture.ts","../src/http/_common/trace-wrap.ts","../src/http/endpoint.ts"],"sourcesContent":["// body-capture.ts — serialize an HTTP request/response body into the raw-JSON\n// payload bytes the runtime stores verbatim (mirrors runtime\n// telemetry.ContractRawJSON). HTTP bodies have no proto schema, so they are\n// captured as-is and rendered without proto decoding.\n// @internal — см. ../README.md\n\n/** Contract-hash marker for already-JSON payloads. Must equal the runtime's\n * telemetry.ContractRawJSON so DecodePayload returns the bytes verbatim. */\nexport const RAW_JSON_CONTRACT = \"raw/json\";\n\nconst encoder = new TextEncoder();\n\n/**\n * Best-effort serialize an HTTP body to bytes for payload capture. Returns\n * null when there is nothing worth capturing (empty / `{}` / unserializable),\n * so bodyless requests (e.g. GET) don't emit empty Input payloads.\n */\nexport function bodyToBytes(body: unknown): Uint8Array | null {\n\tif (body === undefined || body === null) return null;\n\tif (body instanceof Uint8Array) return body.byteLength ? body : null;\n\tif (typeof body === \"string\") {\n\t\tconst s = body.trim();\n\t\tif (!s || s === \"{}\" || s === \"null\") return null;\n\t\treturn encoder.encode(body);\n\t}\n\ttry {\n\t\tconst json = JSON.stringify(body);\n\t\tif (!json || json === \"{}\" || json === \"null\") return null;\n\t\treturn encoder.encode(json);\n\t} catch {\n\t\treturn null;\n\t}\n}\n","// trace-wrap.ts — общий helper для HTTP plugins.\n// Парсит X-SB-Trace header в TraceContext; при отсутствии/невалидном — мин’ит новый root.\n// @internal — см. ../README.md.\n\nimport {\n\tmintRootContext,\n\ttype TraceContext,\n} from \"../../telemetry/trace-context\";\nimport { parseXSbTrace } from \"../../telemetry/wire-trace\";\n\n/**\n * Парсит входящий X-SB-Trace header. Возвращает propagated context или\n * свежий root, если header отсутствует/невалиден. Никогда не throw'ит.\n */\nexport function contextFromXSbTrace(\n\theader: string | null | undefined,\n): TraceContext {\n\tif (header == null) return mintRootContext();\n\tconst parsed = parseXSbTrace(header);\n\tif (parsed == null) return mintRootContext();\n\treturn parsed;\n}\n","/**\n * Resolve the host that an SDK instance advertises as its public HTTP server\n * (ADR 0001). Mirrors `resolveAdvertise` semantics in src/connection, but for\n * the HTTP plane:\n *\n * 1. explicit `host` argument → used as-is\n * 2. fallback \"127.0.0.1\" → одноразовый console.warn\n *\n * @internal — потребляется только интеграциями.\n */\n\nlet _warned = false;\n\n/** Сбрасывает warn-флаг (для тестов). */\nexport function _resetHostWarn(): void {\n\t_warned = false;\n}\n\nexport function resolveHttpAdvertiseHost(explicit?: string): string {\n\tif (explicit && explicit.length > 0) return explicit;\n\tif (!_warned) {\n\t\t_warned = true;\n\t\tconsole.warn(\n\t\t\t\"[ServiceBridge] http advertise host not configured — falling back to 127.0.0.1. \" +\n\t\t\t\t\"Pass { host } to the HTTP plugin for cross-host reachability.\",\n\t\t);\n\t}\n\treturn \"127.0.0.1\";\n}\n"],"mappings":";;;;;;AAQO,IAAM,oBAAoB;AAEjC,IAAM,UAAU,IAAI,YAAY;AAOzB,SAAS,YAAY,MAAkC;AAC7D,MAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,MAAI,gBAAgB,WAAY,QAAO,KAAK,aAAa,OAAO;AAChE,MAAI,OAAO,SAAS,UAAU;AAC7B,UAAM,IAAI,KAAK,KAAK;AACpB,QAAI,CAAC,KAAK,MAAM,QAAQ,MAAM,OAAQ,QAAO;AAC7C,WAAO,QAAQ,OAAO,IAAI;AAAA,EAC3B;AACA,MAAI;AACH,UAAM,OAAO,KAAK,UAAU,IAAI;AAChC,QAAI,CAAC,QAAQ,SAAS,QAAQ,SAAS,OAAQ,QAAO;AACtD,WAAO,QAAQ,OAAO,IAAI;AAAA,EAC3B,QAAQ;AACP,WAAO;AAAA,EACR;AACD;;;AClBO,SAAS,oBACf,QACe;AACf,MAAI,UAAU,KAAM,QAAO,gBAAgB;AAC3C,QAAM,SAAS,cAAc,MAAM;AACnC,MAAI,UAAU,KAAM,QAAO,gBAAgB;AAC3C,SAAO;AACR;;;ACVA,IAAI,UAAU;AAOP,SAAS,yBAAyB,UAA2B;AACnE,MAAI,YAAY,SAAS,SAAS,EAAG,QAAO;AAC5C,MAAI,CAAC,SAAS;AACb,cAAU;AACV,YAAQ;AAAA,MACP;AAAA,IAED;AAAA,EACD;AACA,SAAO;AACR;","names":[]}
@@ -0,0 +1,29 @@
1
+ // src/serde/contract-hash.ts
2
+ import { createHash } from "crypto";
3
+ function computeContractHash(pair) {
4
+ const inputCanonical = canonicalize(pair.input.toJsonSchema());
5
+ const outputCanonical = canonicalize(pair.output.toJsonSchema());
6
+ return createHash("sha256").update(`${inputCanonical}:${outputCanonical}`).digest("hex");
7
+ }
8
+ function computeSerializerHash(s) {
9
+ const canonical = canonicalize(s.toJsonSchema());
10
+ return createHash("sha256").update(canonical).digest("hex");
11
+ }
12
+ function canonicalize(value) {
13
+ if (value === null || typeof value !== "object") {
14
+ return JSON.stringify(value);
15
+ }
16
+ if (Array.isArray(value)) {
17
+ return `[${value.map(canonicalize).join(",")}]`;
18
+ }
19
+ const obj = value;
20
+ const keys = Object.keys(obj).sort();
21
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`).join(",")}}`;
22
+ }
23
+
24
+ export {
25
+ computeContractHash,
26
+ computeSerializerHash,
27
+ canonicalize
28
+ };
29
+ //# sourceMappingURL=chunk-BBFSAJ5H.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/serde/contract-hash.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { SchemaPair, Serializer } from \"./serializer\";\n\n// computeContractHash returns the canonical SHA-256 (hex) of a SchemaPair.\n// The hash identifies an exact (input, output) schema combination — caller\n// and callee that load the SAME schema source MUST produce the SAME hash.\n//\n// Algorithm:\n// 1. Take input.toJsonSchema() and output.toJsonSchema() — both are\n// protobufjs Type descriptors (deterministic structure).\n// 2. Canonicalize each (sorted keys, no whitespace) into a JSON string.\n// Arrays preserve order; objects sort by key recursively.\n// 3. Concatenate as `<input_canonical>:<output_canonical>`.\n// 4. SHA-256, hex-encode.\n//\n// This is the SINGLE source of truth for contract hashing across the SDK.\n// Runtime stores the hash opaque and does NOT recompute (ADR 0005, variant 3).\n//\n// @public — см. ./README.md\nexport function computeContractHash(pair: SchemaPair): string {\n\tconst inputCanonical = canonicalize(pair.input.toJsonSchema());\n\tconst outputCanonical = canonicalize(pair.output.toJsonSchema());\n\treturn createHash(\"sha256\")\n\t\t.update(`${inputCanonical}:${outputCanonical}`)\n\t\t.digest(\"hex\");\n}\n\n// computeSerializerHash hashes a single Serializer (used when only one side\n// of the pair is relevant — e.g. event schemas in future branches).\nexport function computeSerializerHash(s: Serializer): string {\n\tconst canonical = canonicalize(s.toJsonSchema());\n\treturn createHash(\"sha256\").update(canonical).digest(\"hex\");\n}\n\n// canonicalize produces the deterministic JSON string used for hashing.\n// Rules:\n// - null / primitives → JSON.stringify (standard)\n// - arrays → preserve element order, recurse on each element\n// - objects → sort keys lexicographically, recurse on each value\n// - no whitespace, no trailing commas\n//\n// @internal — см. ./README.md\nexport function canonicalize(value: unknown): string {\n\tif (value === null || typeof value !== \"object\") {\n\t\treturn JSON.stringify(value);\n\t}\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(canonicalize).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${canonicalize(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAmBpB,SAAS,oBAAoB,MAA0B;AAC7D,QAAM,iBAAiB,aAAa,KAAK,MAAM,aAAa,CAAC;AAC7D,QAAM,kBAAkB,aAAa,KAAK,OAAO,aAAa,CAAC;AAC/D,SAAO,WAAW,QAAQ,EACxB,OAAO,GAAG,cAAc,IAAI,eAAe,EAAE,EAC7C,OAAO,KAAK;AACf;AAIO,SAAS,sBAAsB,GAAuB;AAC5D,QAAM,YAAY,aAAa,EAAE,aAAa,CAAC;AAC/C,SAAO,WAAW,QAAQ,EAAE,OAAO,SAAS,EAAE,OAAO,KAAK;AAC3D;AAUO,SAAS,aAAa,OAAwB;AACpD,MAAI,UAAU,QAAQ,OAAO,UAAU,UAAU;AAChD,WAAO,KAAK,UAAU,KAAK;AAAA,EAC5B;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACzB,WAAO,IAAI,MAAM,IAAI,YAAY,EAAE,KAAK,GAAG,CAAC;AAAA,EAC7C;AACA,QAAM,MAAM;AACZ,QAAM,OAAO,OAAO,KAAK,GAAG,EAAE,KAAK;AACnC,SAAO,IAAI,KACT,IAAI,CAAC,MAAM,GAAG,KAAK,UAAU,CAAC,CAAC,IAAI,aAAa,IAAI,CAAC,CAAC,CAAC,EAAE,EACzD,KAAK,GAAG,CAAC;AACZ;","names":[]}