@me1a/tool-async-api-builder 0.0.0-stage → 0.1.4

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 (66) hide show
  1. package/README.md +79 -2
  2. package/dist/application/build-pipeline.d.ts +11 -0
  3. package/dist/application/build-pipeline.d.ts.map +1 -0
  4. package/dist/application/build-pipeline.js +100 -0
  5. package/dist/application/build-pipeline.js.map +1 -0
  6. package/dist/application/resolve-config.d.ts +11 -0
  7. package/dist/application/resolve-config.d.ts.map +1 -0
  8. package/dist/application/resolve-config.js +31 -0
  9. package/dist/application/resolve-config.js.map +1 -0
  10. package/dist/application/verify-contracts.d.ts +6 -0
  11. package/dist/application/verify-contracts.d.ts.map +1 -0
  12. package/dist/application/verify-contracts.js +69 -0
  13. package/dist/application/verify-contracts.js.map +1 -0
  14. package/dist/cli/main.d.ts +3 -0
  15. package/dist/cli/main.d.ts.map +1 -0
  16. package/dist/cli/main.js +91 -0
  17. package/dist/cli/main.js.map +1 -0
  18. package/dist/domain/schema-routing.d.ts +8 -0
  19. package/dist/domain/schema-routing.d.ts.map +1 -0
  20. package/dist/domain/schema-routing.js +23 -0
  21. package/dist/domain/schema-routing.js.map +1 -0
  22. package/dist/domain/types.d.ts +56 -0
  23. package/dist/domain/types.d.ts.map +1 -0
  24. package/dist/domain/types.js +2 -0
  25. package/dist/domain/types.js.map +1 -0
  26. package/dist/index.d.ts +8 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +7 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/infrastructure/buf/buf-config.d.ts +7 -0
  31. package/dist/infrastructure/buf/buf-config.d.ts.map +1 -0
  32. package/dist/infrastructure/buf/buf-config.js +109 -0
  33. package/dist/infrastructure/buf/buf-config.js.map +1 -0
  34. package/dist/infrastructure/export-json-schema.d.ts +6 -0
  35. package/dist/infrastructure/export-json-schema.d.ts.map +1 -0
  36. package/dist/infrastructure/export-json-schema.js +40 -0
  37. package/dist/infrastructure/export-json-schema.js.map +1 -0
  38. package/dist/infrastructure/export-yaml.d.ts +6 -0
  39. package/dist/infrastructure/export-yaml.d.ts.map +1 -0
  40. package/dist/infrastructure/export-yaml.js +41 -0
  41. package/dist/infrastructure/export-yaml.js.map +1 -0
  42. package/dist/infrastructure/generate-proto.d.ts +5 -0
  43. package/dist/infrastructure/generate-proto.d.ts.map +1 -0
  44. package/dist/infrastructure/generate-proto.js +367 -0
  45. package/dist/infrastructure/generate-proto.js.map +1 -0
  46. package/dist/infrastructure/generate-sdk.d.ts +6 -0
  47. package/dist/infrastructure/generate-sdk.d.ts.map +1 -0
  48. package/dist/infrastructure/generate-sdk.js +209 -0
  49. package/dist/infrastructure/generate-sdk.js.map +1 -0
  50. package/dist/infrastructure/load-contracts.d.ts +5 -0
  51. package/dist/infrastructure/load-contracts.d.ts.map +1 -0
  52. package/dist/infrastructure/load-contracts.js +39 -0
  53. package/dist/infrastructure/load-contracts.js.map +1 -0
  54. package/dist/infrastructure/templates/native-ws-ts.d.ts +7 -0
  55. package/dist/infrastructure/templates/native-ws-ts.d.ts.map +1 -0
  56. package/dist/infrastructure/templates/native-ws-ts.js +334 -0
  57. package/dist/infrastructure/templates/native-ws-ts.js.map +1 -0
  58. package/dist/infrastructure/templates/nats-rust.d.ts +7 -0
  59. package/dist/infrastructure/templates/nats-rust.d.ts.map +1 -0
  60. package/dist/infrastructure/templates/nats-rust.js +345 -0
  61. package/dist/infrastructure/templates/nats-rust.js.map +1 -0
  62. package/dist/infrastructure/templates/nats-ts.d.ts +5 -0
  63. package/dist/infrastructure/templates/nats-ts.d.ts.map +1 -0
  64. package/dist/infrastructure/templates/nats-ts.js +200 -0
  65. package/dist/infrastructure/templates/nats-ts.js.map +1 -0
  66. package/package.json +68 -4
@@ -0,0 +1,209 @@
1
+ import { Parser } from "@asyncapi/parser";
2
+ import { spawnSync } from "node:child_process";
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { isNatsSchemaName, isWebSocketSchemaName, } from "../domain/schema-routing.js";
6
+ import { discoverContracts } from "./load-contracts.js";
7
+ import { generateNativeWsTsSdk } from "./templates/native-ws-ts.js";
8
+ import { generateNatsConsumerClient, generateNatsProducerClient, generateNatsSubjects, } from "./templates/nats-ts.js";
9
+ import { generateRustNatsConsumerClient, generateRustNatsProducerClient, generateRustNatsSubjects, } from "./templates/nats-rust.js";
10
+ /** Re-exported from protobuf-es SDK barrels so apps can import `create` / `fromBinary` next to schemas. */
11
+ const tsProtobufEsRuntimeExport = 'export { create, fromBinary, toBinary } from "@bufbuild/protobuf";\n';
12
+ export function collectProtoMessageNames(document) {
13
+ const s = new Set();
14
+ for (const op of document.operations().all()) {
15
+ for (const m of op.messages().all()) {
16
+ const id = m.payload()?.id();
17
+ if (id)
18
+ s.add(id);
19
+ }
20
+ }
21
+ return [...s].sort();
22
+ }
23
+ function rustCrateCargoTomlProtobuf(crateName) {
24
+ return `[package]
25
+ name = "${crateName}"
26
+ version = "0.1.0"
27
+ edition = "2021"
28
+ publish = false
29
+ description = "Generated AsyncAPI WebSocket protobuf types — DO NOT EDIT"
30
+
31
+ [lib]
32
+ path = "lib.rs"
33
+
34
+ [dependencies]
35
+ prost = { version = "0.13", default-features = false, features = ["std", "derive"] }
36
+ `;
37
+ }
38
+ async function writeRustProtobufCrate(rustSdkBaseDir, normalizedPkgName, schemaName) {
39
+ const rustCrateDir = path.join(rustSdkBaseDir, normalizedPkgName);
40
+ const prostPath = path.join(rustCrateDir, `${normalizedPkgName}.rs`);
41
+ try {
42
+ await fs.access(prostPath);
43
+ }
44
+ catch {
45
+ console.error(`❌ ${schemaName}: expected prost output at rust/sdk/${normalizedPkgName}/${normalizedPkgName}.rs (run buf generate first)`);
46
+ return false;
47
+ }
48
+ await fs.mkdir(rustCrateDir, { recursive: true });
49
+ await fs.writeFile(path.join(rustCrateDir, "lib.rs"), `//! Generated AsyncAPI WebSocket protobuf types — DO NOT EDIT.
50
+ #![allow(clippy::all)]
51
+ #![allow(dead_code)]
52
+
53
+ mod ${normalizedPkgName};
54
+ pub use ${normalizedPkgName}::*;
55
+ `);
56
+ await fs.writeFile(path.join(rustCrateDir, "Cargo.toml"), rustCrateCargoTomlProtobuf(normalizedPkgName));
57
+ console.log(`✅ Generated WebSocket protobuf Rust crate for ${schemaName}`);
58
+ return true;
59
+ }
60
+ function rustCrateCargoTomlNats(crateName) {
61
+ return `[package]
62
+ name = "${crateName}"
63
+ version = "0.1.0"
64
+ edition = "2021"
65
+ publish = false
66
+ description = "Generated AsyncAPI SDK — DO NOT EDIT"
67
+
68
+ [lib]
69
+ path = "lib.rs"
70
+
71
+ [dependencies]
72
+ prost = { version = "0.13", default-features = false, features = ["std", "derive"] }
73
+ `;
74
+ }
75
+ async function writeRustWorkspace(rustWorkspaceRoot, memberCrateNames) {
76
+ if (memberCrateNames.length === 0) {
77
+ await fs.rm(path.join(rustWorkspaceRoot, "Cargo.toml"), {
78
+ force: true,
79
+ });
80
+ return;
81
+ }
82
+ const members = memberCrateNames.map((n) => ` "sdk/${n}",`).join("\n");
83
+ const body = `[workspace]
84
+ resolver = "2"
85
+ members = [
86
+ ${members}
87
+ ]
88
+ `;
89
+ await fs.writeFile(path.join(rustWorkspaceRoot, "Cargo.toml"), body);
90
+ }
91
+ export { isCompanionDocOnlySpec, isNatsSchemaName, isWebSocketSchemaName, } from "../domain/schema-routing.js";
92
+ export async function generateSdk(layout) {
93
+ const parser = new Parser();
94
+ const tsSdkBaseDir = layout.tsSdkDir;
95
+ const rustWorkspaceRoot = layout.rustWorkspaceDir;
96
+ const rustSdkBaseDir = layout.rustSdkDir;
97
+ const generatedSchemaNames = [];
98
+ const rustCrateNames = [];
99
+ await fs.mkdir(tsSdkBaseDir, { recursive: true });
100
+ await fs.mkdir(rustSdkBaseDir, { recursive: true });
101
+ const contracts = await discoverContracts(layout);
102
+ for (const contract of contracts) {
103
+ const { schemaName, spec, companionOnly, filePath } = contract;
104
+ const file = path.basename(filePath);
105
+ try {
106
+ if (companionOnly) {
107
+ console.log(`⏭️ Skipping SDK for companion spec ${file}`);
108
+ continue;
109
+ }
110
+ const tsSchemaOutputDir = path.join(tsSdkBaseDir, schemaName);
111
+ const normalizedPkgName = schemaName.replace(/[-.]/g, "_");
112
+ const tsDir = tsSchemaOutputDir;
113
+ await fs.mkdir(tsDir, { recursive: true });
114
+ const { document } = await parser.parse(spec);
115
+ if (!document) {
116
+ console.error(`❌ Failed to parse ${file}`);
117
+ continue;
118
+ }
119
+ const isWebSocket = isWebSocketSchemaName(schemaName);
120
+ const isNats = isNatsSchemaName(schemaName);
121
+ if (!isWebSocket && !isNats) {
122
+ console.error(`❌ ${file}: basename must include websocket, -ws., nats, -mq., or -pubsub. (no other transports are generated)`);
123
+ continue;
124
+ }
125
+ const tsTypeNames = collectProtoMessageNames(document);
126
+ const tsTypesContent = `/**
127
+ * @generated — Protocol Buffer message types (protobuf-es).
128
+ */
129
+ export * from "./${normalizedPkgName}_pb.js";
130
+ `;
131
+ await fs.writeFile(path.join(tsDir, "types.ts"), tsTypesContent);
132
+ if (isWebSocket) {
133
+ console.log(`📡 Generating typed native WebSocket SDK for ${schemaName}...`);
134
+ const nativeWsCode = generateNativeWsTsSdk(document, schemaName, tsTypeNames);
135
+ await fs.writeFile(path.join(tsDir, "client.ts"), nativeWsCode);
136
+ console.log(`✅ Generated native WebSocket TypeScript SDK for ${schemaName}`);
137
+ await fs.writeFile(path.join(tsSchemaOutputDir, "index.ts"), `export * from "./types.js";\nexport * from "./client.js";\n${tsProtobufEsRuntimeExport}`);
138
+ if (await writeRustProtobufCrate(rustSdkBaseDir, normalizedPkgName, schemaName)) {
139
+ rustCrateNames.push(normalizedPkgName);
140
+ }
141
+ }
142
+ else {
143
+ console.log(`📡 Generating typed NATS Core SDK for ${schemaName}...`);
144
+ const subjectsContent = generateNatsSubjects(spec);
145
+ await fs.writeFile(path.join(tsDir, "subjects.ts"), subjectsContent);
146
+ const natsProducer = generateNatsProducerClient(document, schemaName, tsTypeNames);
147
+ await fs.writeFile(path.join(tsDir, "producer.ts"), natsProducer);
148
+ const natsConsumer = generateNatsConsumerClient(document, schemaName, tsTypeNames);
149
+ await fs.writeFile(path.join(tsDir, "consumer.ts"), natsConsumer);
150
+ console.log(`✅ Generated NATS Core TypeScript SDK for ${schemaName}`);
151
+ await fs.writeFile(path.join(tsSchemaOutputDir, "index.ts"), `export * from "./types.js";\nexport * from "./subjects.js";\nexport * from "./producer.js";\nexport * from "./consumer.js";\n${tsProtobufEsRuntimeExport}`);
152
+ }
153
+ generatedSchemaNames.push(schemaName);
154
+ if (isWebSocket) {
155
+ continue;
156
+ }
157
+ const rustCrateDir = path.join(rustSdkBaseDir, normalizedPkgName);
158
+ await fs.mkdir(rustCrateDir, { recursive: true });
159
+ await fs.writeFile(path.join(rustCrateDir, "subjects.rs"), generateRustNatsSubjects(spec));
160
+ await fs.writeFile(path.join(rustCrateDir, "producer.rs"), generateRustNatsProducerClient(document, schemaName));
161
+ await fs.writeFile(path.join(rustCrateDir, "consumer.rs"), generateRustNatsConsumerClient(document, schemaName));
162
+ await fs.writeFile(path.join(rustCrateDir, "lib.rs"), `//! Generated AsyncAPI NATS SDK — DO NOT EDIT.
163
+ #![allow(clippy::all)]
164
+ #![allow(dead_code)]
165
+
166
+ mod ${normalizedPkgName};
167
+ pub use ${normalizedPkgName}::*;
168
+
169
+ pub mod subjects;
170
+ pub mod producer;
171
+ pub mod consumer;
172
+ `);
173
+ await fs.writeFile(path.join(rustCrateDir, "Cargo.toml"), rustCrateCargoTomlNats(normalizedPkgName));
174
+ rustCrateNames.push(normalizedPkgName);
175
+ console.log(`✅ Generated NATS Core Rust SDK for ${schemaName}`);
176
+ }
177
+ catch (err) {
178
+ console.error(`❌ Error generating SDK for ${file}:`, err);
179
+ throw err;
180
+ }
181
+ }
182
+ await writeRustWorkspace(rustWorkspaceRoot, rustCrateNames);
183
+ if (rustCrateNames.length > 0) {
184
+ console.log("✅ Generated rust/Cargo.toml workspace");
185
+ const fmt = spawnSync("cargo", ["fmt"], {
186
+ cwd: rustWorkspaceRoot,
187
+ stdio: "ignore",
188
+ });
189
+ if (fmt.status !== 0) {
190
+ console.warn("WARN: cargo fmt on generated Rust SDK crates failed");
191
+ }
192
+ }
193
+ if (generatedSchemaNames.length > 0) {
194
+ const toPascalCase = (s) => s
195
+ .split(/[-._]/)
196
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
197
+ .join("");
198
+ const barrelContent = `// Auto-generated — DO NOT EDIT MANUALLY\n` +
199
+ tsProtobufEsRuntimeExport +
200
+ generatedSchemaNames
201
+ .map((name) => `export * as ${toPascalCase(name)}Sdk from "./${name}/index.js";`)
202
+ .join("\n") +
203
+ "\n";
204
+ await fs.writeFile(path.join(tsSdkBaseDir, "index.ts"), barrelContent);
205
+ console.log("✅ Generated sdk/index.ts barrel");
206
+ }
207
+ console.log("✨ SDK generation completed!");
208
+ }
209
+ //# sourceMappingURL=generate-sdk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-sdk.js","sourceRoot":"","sources":["../../src/infrastructure/generate-sdk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { AsyncApiProjectLayout, LoadedContract } from "../domain/types.js";
2
+ export declare function loadSpecFromFile(filePath: string): Promise<Record<string, unknown> | null>;
3
+ export declare function listSchemaFiles(layout: AsyncApiProjectLayout): string[];
4
+ export declare function discoverContracts(layout: AsyncApiProjectLayout): Promise<LoadedContract[]>;
5
+ //# sourceMappingURL=load-contracts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-contracts.d.ts","sourceRoot":"","sources":["../../src/infrastructure/load-contracts.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEhF,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,EAAE,CAIvE;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,cAAc,EAAE,CAAC,CAkB3B"}
@@ -0,0 +1,39 @@
1
+ import { readdirSync } from "node:fs";
2
+ import { basename, join } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+ import { isCompanionDocOnlySpec } from "../domain/schema-routing.js";
5
+ export async function loadSpecFromFile(filePath) {
6
+ const url = `${pathToFileURL(filePath).href}?update=${Date.now()}`;
7
+ const apiModule = await import(url);
8
+ for (const exportName of Object.keys(apiModule)) {
9
+ const value = apiModule[exportName];
10
+ if (value?.asyncapi) {
11
+ return value;
12
+ }
13
+ }
14
+ return null;
15
+ }
16
+ export function listSchemaFiles(layout) {
17
+ return readdirSync(layout.schemasDir)
18
+ .filter((f) => f.endsWith(".schema.ts"))
19
+ .sort((a, b) => a.localeCompare(b));
20
+ }
21
+ export async function discoverContracts(layout) {
22
+ const files = listSchemaFiles(layout);
23
+ const contracts = [];
24
+ for (const file of files) {
25
+ const filePath = join(layout.schemasDir, file);
26
+ const spec = await loadSpecFromFile(filePath);
27
+ if (!spec)
28
+ continue;
29
+ const schemaName = basename(file, ".schema.ts");
30
+ contracts.push({
31
+ schemaName,
32
+ filePath,
33
+ spec,
34
+ companionOnly: isCompanionDocOnlySpec(spec),
35
+ });
36
+ }
37
+ return contracts;
38
+ }
39
+ //# sourceMappingURL=load-contracts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-contracts.js","sourceRoot":"","sources":["../../src/infrastructure/load-contracts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAGrE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB;IAEhB,MAAM,GAAG,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACnE,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAChD,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAsC,CAAC;QACzE,IAAI,KAAK,EAAE,QAAQ,EAAE,CAAC;YACpB,OAAO,KAAgC,CAAC;QAC1C,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAA6B;IAC3D,OAAO,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;SAClC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;SACvC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA6B;IAE7B,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,SAAS,GAAqB,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC/C,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAChD,SAAS,CAAC,IAAI,CAAC;YACb,UAAU;YACV,QAAQ;YACR,IAAI;YACJ,aAAa,EAAE,sBAAsB,CAAC,IAAI,CAAC;SAC5C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { AsyncAPIDocumentInterface } from "@asyncapi/parser";
2
+ /**
3
+ * Emits a browser native WebSocket client: **protobuf** `ClientEnvelope` / `ServerEnvelope` frames,
4
+ * JWT via `?token=`, auto-reconnect with backoff, typed send/on/off.
5
+ */
6
+ export declare function generateNativeWsTsSdk(doc: AsyncAPIDocumentInterface, schemaName: string, typeNames: string[]): string;
7
+ //# sourceMappingURL=native-ws-ts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-ws-ts.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/templates/native-ws-ts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAkB7D;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,yBAAyB,EAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EAAE,GAClB,MAAM,CAiUR"}
@@ -0,0 +1,334 @@
1
+ /**
2
+ * PascalCase schema basename → e.g. `CustomerStreamingWsV1` + `Client`
3
+ */
4
+ function toClientClassName(schemaName) {
5
+ return (schemaName
6
+ .split(/[-._]/)
7
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
8
+ .join("") + "Client");
9
+ }
10
+ function protoPkgFromSchemaName(schemaName) {
11
+ return schemaName.replace(/[-.]/g, "_");
12
+ }
13
+ /**
14
+ * Emits a browser native WebSocket client: **protobuf** `ClientEnvelope` / `ServerEnvelope` frames,
15
+ * JWT via `?token=`, auto-reconnect with backoff, typed send/on/off.
16
+ */
17
+ export function generateNativeWsTsSdk(doc, schemaName, typeNames) {
18
+ const typeImports = typeNames.join(", ");
19
+ const className = toClientClassName(schemaName);
20
+ const protoPkg = protoPkgFromSchemaName(schemaName);
21
+ const pbFile = `./${protoPkg}_pb.js`;
22
+ const servers = doc.servers();
23
+ const apiServer = servers.get("api");
24
+ const wsPath = apiServer?.pathname() || "/";
25
+ const clientMapLines = [];
26
+ const serverMapLines = [];
27
+ for (const op of doc.operations().all()) {
28
+ const action = op.action();
29
+ const channels = op.channels();
30
+ if (channels.length === 0)
31
+ continue;
32
+ const channel = channels.all()[0];
33
+ const eventName = channel.address() || channel.id();
34
+ const messages = op.messages().all();
35
+ if (messages.length === 0)
36
+ continue;
37
+ const messageNames = messages
38
+ .map((m) => m.payload()?.id() ?? "unknown")
39
+ .join(" | ");
40
+ const line = ` "${eventName}": ${messageNames};`;
41
+ if (action === "send") {
42
+ clientMapLines.push(line);
43
+ }
44
+ else if (action === "receive") {
45
+ serverMapLines.push(line);
46
+ }
47
+ }
48
+ const clientMapBody = clientMapLines.join("\n");
49
+ const serverMapBody = serverMapLines.join("\n");
50
+ return `/// <reference lib="dom" />
51
+ /**
52
+ * This file was automatically generated.
53
+ * DO NOT MODIFY IT MANUALLY.
54
+ *
55
+ * Native browser WebSocket client — protobuf wire (ClientEnvelope / ServerEnvelope),
56
+ * auth token on the handshake query string (?token=), same as customer-streaming gateway.
57
+ */
58
+
59
+ import { create, toBinary, fromBinary } from "@bufbuild/protobuf";
60
+ import {
61
+ ClientEnvelopeSchema,
62
+ ServerEnvelopeSchema,
63
+ type ClientEnvelope,
64
+ type ServerEnvelope,
65
+ } from "${pbFile}";
66
+ import type { ${typeImports} } from "./types.js";
67
+ export type { ${typeImports} };
68
+
69
+ /** join_note → joinNote (protobuf-es oneof case) */
70
+ function wsEventToProtobufCase(e: string): string {
71
+ return e.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());
72
+ }
73
+
74
+ /** chatProgress → chat_progress */
75
+ function protobufCaseToWsEvent(c: string | undefined): string | undefined {
76
+ if (c === undefined) return undefined;
77
+ return c
78
+ .replace(/[A-Z]/g, (ch) => "_" + ch.toLowerCase())
79
+ .replace(/^_/, "");
80
+ }
81
+
82
+ /** WebSocket pathname from AsyncAPI (combine with origin in the app). */
83
+ export const WS_PATH = "${wsPath}";
84
+
85
+ /** Client → server events and payload types from the contract. */
86
+ export interface ClientEventMap {
87
+ ${clientMapBody}
88
+ }
89
+
90
+ /** Server → client events and payload types from the contract. */
91
+ export interface ServerEventMap {
92
+ ${serverMapBody}
93
+ }
94
+
95
+ type ServerHandler<E extends keyof ServerEventMap> = (
96
+ data: ServerEventMap[E]
97
+ ) => void;
98
+
99
+ const INITIAL_BACKOFF_MS = 1_000;
100
+ const MAX_BACKOFF_MS = 30_000;
101
+
102
+ function appendTokenQuery(wsUrl: string, token: string): string {
103
+ const sep = wsUrl.includes("?") ? "&" : "?";
104
+ return \`\${wsUrl}\${sep}token=\${encodeURIComponent(token)}\`;
105
+ }
106
+
107
+ /**
108
+ * Typed WebSocket client with reconnect and ?token= auth (re-fetches token each connect attempt).
109
+ */
110
+ export class ${className} {
111
+ private ws: WebSocket | null = null;
112
+
113
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null;
114
+
115
+ private backoffMs = INITIAL_BACKOFF_MS;
116
+
117
+ private destroyed = false;
118
+
119
+ private connectRequested = false;
120
+
121
+ private readonly outboundQueue: Uint8Array[] = [];
122
+
123
+ private readonly serverListeners = new Map<
124
+ string,
125
+ Set<(data: unknown) => void>
126
+ >();
127
+
128
+ private readonly connectionListeners = new Set<(connected: boolean) => void>();
129
+
130
+ constructor(
131
+ private readonly wsUrl: string,
132
+ private readonly getToken: () => Promise<string | null>
133
+ ) {}
134
+
135
+ get isConnected(): boolean {
136
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
137
+ }
138
+
139
+ /** Start connecting (or schedule reconnect). Idempotent until destroy(). */
140
+ connect(): void {
141
+ if (this.destroyed) return;
142
+ this.connectRequested = true;
143
+ void this.tryOpen();
144
+ }
145
+
146
+ /** Stop reconnecting and close the socket. */
147
+ destroy(): void {
148
+ this.destroyed = true;
149
+ this.connectRequested = false;
150
+ if (this.reconnectTimer !== null) {
151
+ clearTimeout(this.reconnectTimer);
152
+ this.reconnectTimer = null;
153
+ }
154
+ if (this.ws) {
155
+ this.ws.close(1000, "client_destroy");
156
+ this.ws = null;
157
+ }
158
+ this.outboundQueue.length = 0;
159
+ this.emitConnection(false);
160
+ }
161
+
162
+ send<E extends keyof ClientEventMap>(
163
+ event: E,
164
+ data: ClientEventMap[E]
165
+ ): void {
166
+ const pCase = wsEventToProtobufCase(String(event));
167
+ const envelope = create(ClientEnvelopeSchema, {
168
+ payload: {
169
+ case: pCase,
170
+ value: data,
171
+ },
172
+ } as never);
173
+ const frame = toBinary(ClientEnvelopeSchema, envelope);
174
+ if (this.ws?.readyState === WebSocket.OPEN) {
175
+ this.ws.send(frame as unknown as BufferSource);
176
+ } else {
177
+ this.outboundQueue.push(frame);
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Subscribe to a server event. Returns an unsubscribe function.
183
+ */
184
+ on<E extends keyof ServerEventMap>(
185
+ event: E,
186
+ handler: ServerHandler<E>
187
+ ): () => void {
188
+ const key = String(event);
189
+ let set = this.serverListeners.get(key);
190
+ if (!set) {
191
+ set = new Set();
192
+ this.serverListeners.set(key, set);
193
+ }
194
+ const wrapped = handler as (data: unknown) => void;
195
+ set.add(wrapped);
196
+ return () => {
197
+ const s = this.serverListeners.get(key);
198
+ if (!s) return;
199
+ s.delete(wrapped);
200
+ if (s.size === 0) this.serverListeners.delete(key);
201
+ };
202
+ }
203
+
204
+ off<E extends keyof ServerEventMap>(
205
+ event: E,
206
+ handler: ServerHandler<E>
207
+ ): void {
208
+ const key = String(event);
209
+ const set = this.serverListeners.get(key);
210
+ if (!set) return;
211
+ set.delete(handler as (data: unknown) => void);
212
+ if (set.size === 0) this.serverListeners.delete(key);
213
+ }
214
+
215
+ /** Listen to open/close (boolean true = connected). */
216
+ onConnectionChange(fn: (connected: boolean) => void): () => void {
217
+ this.connectionListeners.add(fn);
218
+ return () => this.connectionListeners.delete(fn);
219
+ }
220
+
221
+ private emitConnection(connected: boolean): void {
222
+ for (const fn of this.connectionListeners) {
223
+ try {
224
+ fn(connected);
225
+ } catch {
226
+ /* ignore listener errors */
227
+ }
228
+ }
229
+ }
230
+
231
+ private flushQueue(): void {
232
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return;
233
+ while (this.outboundQueue.length > 0) {
234
+ const item = this.outboundQueue.shift()!;
235
+ this.ws.send(item as unknown as BufferSource);
236
+ }
237
+ }
238
+
239
+ private dispatchServerEvent(eventName: string, data: unknown): void {
240
+ const set = this.serverListeners.get(eventName);
241
+ if (!set) return;
242
+ for (const h of [...set]) {
243
+ try {
244
+ h(data);
245
+ } catch {
246
+ /* ignore handler errors */
247
+ }
248
+ }
249
+ }
250
+
251
+ private scheduleReconnect(): void {
252
+ if (this.destroyed || !this.connectRequested) return;
253
+ if (this.reconnectTimer !== null) return;
254
+ const delay = this.backoffMs;
255
+ this.backoffMs = Math.min(this.backoffMs * 2, MAX_BACKOFF_MS);
256
+ this.reconnectTimer = setTimeout(() => {
257
+ this.reconnectTimer = null;
258
+ void this.tryOpen();
259
+ }, delay);
260
+ }
261
+
262
+ private async tryOpen(): Promise<void> {
263
+ if (this.destroyed || !this.connectRequested) return;
264
+ if (this.ws?.readyState === WebSocket.OPEN) return;
265
+ if (this.ws && this.ws.readyState === WebSocket.CONNECTING) return;
266
+
267
+ const token = await this.getToken();
268
+ if (this.destroyed || !this.connectRequested) return;
269
+ if (!token) {
270
+ this.scheduleReconnect();
271
+ return;
272
+ }
273
+
274
+ const url = appendTokenQuery(this.wsUrl, token);
275
+
276
+ if (this.ws) {
277
+ this.ws.close();
278
+ this.ws = null;
279
+ }
280
+
281
+ let socket: WebSocket;
282
+ try {
283
+ socket = new WebSocket(url);
284
+ } catch {
285
+ this.scheduleReconnect();
286
+ return;
287
+ }
288
+
289
+ socket.binaryType = "arraybuffer";
290
+ this.ws = socket;
291
+
292
+ socket.onopen = () => {
293
+ if (this.destroyed) return;
294
+ this.backoffMs = INITIAL_BACKOFF_MS;
295
+ this.emitConnection(true);
296
+ this.flushQueue();
297
+ };
298
+
299
+ socket.onmessage = (ev: MessageEvent<string | ArrayBuffer>) => {
300
+ if (this.destroyed) return;
301
+ const raw =
302
+ typeof ev.data === "string"
303
+ ? new TextEncoder().encode(ev.data)
304
+ : new Uint8Array(ev.data);
305
+ let env: ServerEnvelope;
306
+ try {
307
+ env = fromBinary(ServerEnvelopeSchema, raw);
308
+ } catch {
309
+ return;
310
+ }
311
+ const c = env.payload.case;
312
+ const eventName = protobufCaseToWsEvent(c);
313
+ if (!eventName || c === undefined) return;
314
+ if ("value" in env.payload) {
315
+ this.dispatchServerEvent(eventName, (env.payload as { value?: unknown }).value);
316
+ }
317
+ };
318
+
319
+ socket.onerror = () => {
320
+ /* closed event will handle reconnect */
321
+ };
322
+
323
+ socket.onclose = () => {
324
+ this.ws = null;
325
+ this.emitConnection(false);
326
+ if (!this.destroyed && this.connectRequested) {
327
+ this.scheduleReconnect();
328
+ }
329
+ };
330
+ }
331
+ }
332
+ `;
333
+ }
334
+ //# sourceMappingURL=native-ws-ts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native-ws-ts.js","sourceRoot":"","sources":["../../../src/infrastructure/templates/native-ws-ts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { AsyncAPIDocumentInterface } from "@asyncapi/parser";
2
+ /** Rust structs from AsyncAPI components.messages (JSON Schema payloads). */
3
+ export declare function generateRustNatsTypes(doc: AsyncAPIDocumentInterface, _crateIdent: string): string;
4
+ export declare function generateRustNatsSubjects(_spec: Record<string, unknown>): string;
5
+ export declare function generateRustNatsProducerClient(doc: AsyncAPIDocumentInterface, schemaName: string): string;
6
+ export declare function generateRustNatsConsumerClient(doc: AsyncAPIDocumentInterface, schemaName: string): string;
7
+ //# sourceMappingURL=nats-rust.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nats-rust.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/templates/nats-rust.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EAG1B,MAAM,kBAAkB,CAAC;AA+K1B,6EAA6E;AAC7E,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,yBAAyB,EAC9B,WAAW,EAAE,MAAM,GAClB,MAAM,CAoCR;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CA8CR;AAED,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,yBAAyB,EAC9B,UAAU,EAAE,MAAM,GACjB,MAAM,CA0ER;AAED,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,yBAAyB,EAC9B,UAAU,EAAE,MAAM,GACjB,MAAM,CA+ER"}