atmx-cli 0.131.0 → 0.135.0
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/generators/sdk-generator.js +47 -11
- package/dist/index.js +3 -1
- package/package.json +1 -1
- package/src/generators/sdk-generator.ts +50 -11
- package/src/index.ts +3 -1
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.generateSDKContent = generateSDKContent;
|
|
4
|
+
const utils_js_1 = require("./utils.js");
|
|
5
|
+
// Contract namespaces are runtime strings, and can legitimately contain
|
|
6
|
+
// hyphens (for example `first-project`). They must never be interpolated
|
|
7
|
+
// directly into TypeScript identifiers. Keep the runtime namespace exact,
|
|
8
|
+
// while using this stable safe form only for generated bindings.
|
|
9
|
+
function namespaceIdentifier(namespace) {
|
|
10
|
+
const candidate = (0, utils_js_1.camelCase)(namespace).replace(/[^A-Za-z0-9_$]/g, "");
|
|
11
|
+
if (!candidate)
|
|
12
|
+
return "contract";
|
|
13
|
+
return /^[A-Za-z_$]/.test(candidate) ? candidate : `contract${candidate}`;
|
|
14
|
+
}
|
|
15
|
+
function moduleIdentifier(namespace) {
|
|
16
|
+
return `${namespaceIdentifier(namespace)}Module`;
|
|
17
|
+
}
|
|
4
18
|
// Helper to convert Axiom TypeRef to TypeScript Types
|
|
5
19
|
function getTsType(namespace, typeRef) {
|
|
6
20
|
if (!typeRef)
|
|
7
21
|
return "any";
|
|
8
22
|
if (typeRef.kind === "named") {
|
|
9
|
-
return `models.${namespace}.${typeRef.value}`;
|
|
23
|
+
return `models.${namespaceIdentifier(namespace)}.${typeRef.value}`;
|
|
10
24
|
}
|
|
11
25
|
else if (typeRef.kind === "list") {
|
|
12
26
|
return `${getTsType(namespace, typeRef.value)}[]`;
|
|
@@ -29,7 +43,7 @@ function getDecoder(namespace, typeRef) {
|
|
|
29
43
|
if (!typeRef)
|
|
30
44
|
return `(json: any) => json`;
|
|
31
45
|
if (typeRef.kind === "named") {
|
|
32
|
-
return `models.Mappers.${namespace}.${typeRef.value}.fromJson`;
|
|
46
|
+
return `models.Mappers.${namespaceIdentifier(namespace)}.${typeRef.value}.fromJson`;
|
|
33
47
|
}
|
|
34
48
|
else if (typeRef.kind === "list" &&
|
|
35
49
|
typeRef.value.kind === "named") {
|
|
@@ -49,8 +63,15 @@ function generateSDKContent(contracts, isReact) {
|
|
|
49
63
|
content += `import type { AxiomQueryDef } from "atmx-react";\n\n`;
|
|
50
64
|
}
|
|
51
65
|
// 1. Generate Individual Modules
|
|
66
|
+
const namespaces = Object.keys(contracts);
|
|
67
|
+
const aliasCounts = new Map();
|
|
68
|
+
for (const namespace of namespaces) {
|
|
69
|
+
const alias = namespaceIdentifier(namespace);
|
|
70
|
+
aliasCounts.set(alias, (aliasCounts.get(alias) ?? 0) + 1);
|
|
71
|
+
}
|
|
52
72
|
for (const [namespace, contract] of Object.entries(contracts)) {
|
|
53
|
-
|
|
73
|
+
const moduleName = moduleIdentifier(namespace);
|
|
74
|
+
content += `export const ${moduleName} = {\n`;
|
|
54
75
|
content += ` axiom: {\n`;
|
|
55
76
|
content += ` setAuthToken(methodName: string, token: string) {\n`;
|
|
56
77
|
if (isReact) {
|
|
@@ -70,7 +91,7 @@ function generateSDKContent(contracts, isReact) {
|
|
|
70
91
|
content += ` },\n`;
|
|
71
92
|
content += ` connect(methodName: string, args?: Record<string, any>) {\n`;
|
|
72
93
|
if (isReact) {
|
|
73
|
-
content += ` const def = (${
|
|
94
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
74
95
|
content += ` axiomQueryManager.connect(def);\n`;
|
|
75
96
|
}
|
|
76
97
|
else {
|
|
@@ -80,7 +101,7 @@ function generateSDKContent(contracts, isReact) {
|
|
|
80
101
|
content += ` },\n`;
|
|
81
102
|
content += ` disconnect(methodName: string, args?: Record<string, any>) {\n`;
|
|
82
103
|
if (isReact) {
|
|
83
|
-
content += ` const def = (${
|
|
104
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
84
105
|
content += ` axiomQueryManager.disconnect(def);\n`;
|
|
85
106
|
}
|
|
86
107
|
else {
|
|
@@ -90,7 +111,7 @@ function generateSDKContent(contracts, isReact) {
|
|
|
90
111
|
content += ` },\n`;
|
|
91
112
|
content += ` send(methodName: string, payload: any, args?: Record<string, any>) {\n`;
|
|
92
113
|
if (isReact) {
|
|
93
|
-
content += ` const def = (${
|
|
114
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
94
115
|
content += ` axiomQueryManager.send(def, payload);\n`;
|
|
95
116
|
}
|
|
96
117
|
else {
|
|
@@ -166,8 +187,16 @@ function generateSDKContent(contracts, isReact) {
|
|
|
166
187
|
}
|
|
167
188
|
// 2. Generate the Smart Proxy SDK
|
|
168
189
|
content += `const internalSdk: Record<string, any> = {\n`;
|
|
169
|
-
for (const namespace of
|
|
170
|
-
|
|
190
|
+
for (const namespace of namespaces) {
|
|
191
|
+
const alias = namespaceIdentifier(namespace);
|
|
192
|
+
const moduleName = moduleIdentifier(namespace);
|
|
193
|
+
// The canonical key is always the exact contract namespace. Add a safe
|
|
194
|
+
// dot-notation alias when it is unambiguous, so `sdk.firstProject` and
|
|
195
|
+
// `sdk["first-project"]` both address the same contract.
|
|
196
|
+
content += ` ${JSON.stringify(namespace)}: ${moduleName},\n`;
|
|
197
|
+
if (alias !== namespace && aliasCounts.get(alias) === 1 && !contracts[alias]) {
|
|
198
|
+
content += ` ${alias}: ${moduleName},\n`;
|
|
199
|
+
}
|
|
171
200
|
}
|
|
172
201
|
content += `};\n\n`;
|
|
173
202
|
content += `// ✨ The Magic Proxy: Safely intercepts Alpine.js evaluations during boot!\n`;
|
|
@@ -209,9 +238,16 @@ function generateSDKContent(contracts, isReact) {
|
|
|
209
238
|
for (const [ns, def] of Object.entries(contracts)) {
|
|
210
239
|
// Determine file path or default to namespace
|
|
211
240
|
const contractPath = def.file ? def.file : `/${ns}.axiom`;
|
|
212
|
-
content += `
|
|
213
|
-
content += ` contractUrl:
|
|
214
|
-
content += ` baseUrl:
|
|
241
|
+
content += ` ${JSON.stringify(ns)}: {\n`;
|
|
242
|
+
content += ` contractUrl: ${JSON.stringify(contractPath)},\n`;
|
|
243
|
+
content += ` baseUrl: ${JSON.stringify(def.baseUrl)}`;
|
|
244
|
+
if (def.signature && def.publicKey) {
|
|
245
|
+
content += `,\n contractSignature: ${JSON.stringify(def.signature)},\n`;
|
|
246
|
+
content += ` contractPublicKey: ${JSON.stringify(def.publicKey)}\n`;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
content += `\n`;
|
|
250
|
+
}
|
|
215
251
|
content += ` },\n`;
|
|
216
252
|
}
|
|
217
253
|
content += ` }\n`;
|
package/dist/index.js
CHANGED
|
@@ -46,7 +46,7 @@ const program = new commander_1.Command();
|
|
|
46
46
|
program
|
|
47
47
|
.name("atmx")
|
|
48
48
|
.description("Generate TypeScript SDK from AxiomDeps.toml")
|
|
49
|
-
.version("0.
|
|
49
|
+
.version("0.131.0");
|
|
50
50
|
program
|
|
51
51
|
.command("generate")
|
|
52
52
|
.requiredOption("-c, --config <path>", "Path to AxiomDeps.toml")
|
|
@@ -86,6 +86,8 @@ program
|
|
|
86
86
|
ir: multiIr[namespace],
|
|
87
87
|
baseUrl: contract.base_url || "http://localhost:8080",
|
|
88
88
|
file: `/${namespace}.axiom`,
|
|
89
|
+
signature: contract.signature,
|
|
90
|
+
publicKey: contract.public_key,
|
|
89
91
|
};
|
|
90
92
|
console.log(`✅ Loaded contract: [${namespace}] -> ${axiomFilePath}`);
|
|
91
93
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
import { AxiomIR, AxiomEndpoint, AxiomTypeRef } from "../types.js";
|
|
2
|
+
import { camelCase } from "./utils.js";
|
|
2
3
|
|
|
3
4
|
export interface ContractPayload {
|
|
4
5
|
ir: AxiomIR;
|
|
5
6
|
baseUrl: string;
|
|
6
7
|
file: string;
|
|
8
|
+
signature?: string;
|
|
9
|
+
publicKey?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Contract namespaces are runtime strings, and can legitimately contain
|
|
13
|
+
// hyphens (for example `first-project`). They must never be interpolated
|
|
14
|
+
// directly into TypeScript identifiers. Keep the runtime namespace exact,
|
|
15
|
+
// while using this stable safe form only for generated bindings.
|
|
16
|
+
function namespaceIdentifier(namespace: string): string {
|
|
17
|
+
const candidate = camelCase(namespace).replace(/[^A-Za-z0-9_$]/g, "");
|
|
18
|
+
if (!candidate) return "contract";
|
|
19
|
+
return /^[A-Za-z_$]/.test(candidate) ? candidate : `contract${candidate}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function moduleIdentifier(namespace: string): string {
|
|
23
|
+
return `${namespaceIdentifier(namespace)}Module`;
|
|
7
24
|
}
|
|
8
25
|
|
|
9
26
|
// Helper to convert Axiom TypeRef to TypeScript Types
|
|
10
27
|
function getTsType(namespace: string, typeRef?: AxiomTypeRef): string {
|
|
11
28
|
if (!typeRef) return "any";
|
|
12
29
|
if (typeRef.kind === "named") {
|
|
13
|
-
return `models.${namespace}.${typeRef.value}`;
|
|
30
|
+
return `models.${namespaceIdentifier(namespace)}.${typeRef.value}`;
|
|
14
31
|
} else if (typeRef.kind === "list") {
|
|
15
32
|
return `${getTsType(namespace, typeRef.value as AxiomTypeRef)}[]`;
|
|
16
33
|
} else if (typeRef.kind === "primitive") {
|
|
@@ -29,7 +46,7 @@ function getDecoder(namespace: string, typeRef?: AxiomTypeRef): string {
|
|
|
29
46
|
if (!typeRef) return `(json: any) => json`;
|
|
30
47
|
|
|
31
48
|
if (typeRef.kind === "named") {
|
|
32
|
-
return `models.Mappers.${namespace}.${typeRef.value}.fromJson`;
|
|
49
|
+
return `models.Mappers.${namespaceIdentifier(namespace)}.${typeRef.value}.fromJson`;
|
|
33
50
|
} else if (
|
|
34
51
|
typeRef.kind === "list" &&
|
|
35
52
|
(typeRef.value as AxiomTypeRef).kind === "named"
|
|
@@ -56,8 +73,16 @@ export function generateSDKContent(
|
|
|
56
73
|
}
|
|
57
74
|
|
|
58
75
|
// 1. Generate Individual Modules
|
|
76
|
+
const namespaces = Object.keys(contracts);
|
|
77
|
+
const aliasCounts = new Map<string, number>();
|
|
78
|
+
for (const namespace of namespaces) {
|
|
79
|
+
const alias = namespaceIdentifier(namespace);
|
|
80
|
+
aliasCounts.set(alias, (aliasCounts.get(alias) ?? 0) + 1);
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
for (const [namespace, contract] of Object.entries(contracts)) {
|
|
60
|
-
|
|
84
|
+
const moduleName = moduleIdentifier(namespace);
|
|
85
|
+
content += `export const ${moduleName} = {\n`;
|
|
61
86
|
content += ` axiom: {\n`;
|
|
62
87
|
content += ` setAuthToken(methodName: string, token: string) {\n`;
|
|
63
88
|
if (isReact) {
|
|
@@ -75,7 +100,7 @@ export function generateSDKContent(
|
|
|
75
100
|
content += ` },\n`;
|
|
76
101
|
content += ` connect(methodName: string, args?: Record<string, any>) {\n`;
|
|
77
102
|
if (isReact) {
|
|
78
|
-
content += ` const def = (${
|
|
103
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
79
104
|
content += ` axiomQueryManager.connect(def);\n`;
|
|
80
105
|
} else {
|
|
81
106
|
content += ` const argsStr = args && Object.keys(args).length > 0 ? JSON.stringify(args) : '';\n`;
|
|
@@ -84,7 +109,7 @@ export function generateSDKContent(
|
|
|
84
109
|
content += ` },\n`;
|
|
85
110
|
content += ` disconnect(methodName: string, args?: Record<string, any>) {\n`;
|
|
86
111
|
if (isReact) {
|
|
87
|
-
content += ` const def = (${
|
|
112
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
88
113
|
content += ` axiomQueryManager.disconnect(def);\n`;
|
|
89
114
|
} else {
|
|
90
115
|
content += ` const argsStr = args && Object.keys(args).length > 0 ? JSON.stringify(args) : '';\n`;
|
|
@@ -93,7 +118,7 @@ export function generateSDKContent(
|
|
|
93
118
|
content += ` },\n`;
|
|
94
119
|
content += ` send(methodName: string, payload: any, args?: Record<string, any>) {\n`;
|
|
95
120
|
if (isReact) {
|
|
96
|
-
content += ` const def = (${
|
|
121
|
+
content += ` const def = (${moduleName} as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
|
|
97
122
|
content += ` axiomQueryManager.send(def, payload);\n`;
|
|
98
123
|
} else {
|
|
99
124
|
content += ` const argsStr = args && Object.keys(args).length > 0 ? JSON.stringify(args) : '';\n`;
|
|
@@ -174,8 +199,16 @@ export function generateSDKContent(
|
|
|
174
199
|
|
|
175
200
|
// 2. Generate the Smart Proxy SDK
|
|
176
201
|
content += `const internalSdk: Record<string, any> = {\n`;
|
|
177
|
-
for (const namespace of
|
|
178
|
-
|
|
202
|
+
for (const namespace of namespaces) {
|
|
203
|
+
const alias = namespaceIdentifier(namespace);
|
|
204
|
+
const moduleName = moduleIdentifier(namespace);
|
|
205
|
+
// The canonical key is always the exact contract namespace. Add a safe
|
|
206
|
+
// dot-notation alias when it is unambiguous, so `sdk.firstProject` and
|
|
207
|
+
// `sdk["first-project"]` both address the same contract.
|
|
208
|
+
content += ` ${JSON.stringify(namespace)}: ${moduleName},\n`;
|
|
209
|
+
if (alias !== namespace && aliasCounts.get(alias) === 1 && !contracts[alias]) {
|
|
210
|
+
content += ` ${alias}: ${moduleName},\n`;
|
|
211
|
+
}
|
|
179
212
|
}
|
|
180
213
|
content += `};\n\n`;
|
|
181
214
|
|
|
@@ -221,9 +254,15 @@ export function generateSDKContent(
|
|
|
221
254
|
// Determine file path or default to namespace
|
|
222
255
|
const contractPath = def.file ? def.file : `/${ns}.axiom`;
|
|
223
256
|
|
|
224
|
-
content += `
|
|
225
|
-
content += ` contractUrl:
|
|
226
|
-
content += ` baseUrl:
|
|
257
|
+
content += ` ${JSON.stringify(ns)}: {\n`;
|
|
258
|
+
content += ` contractUrl: ${JSON.stringify(contractPath)},\n`;
|
|
259
|
+
content += ` baseUrl: ${JSON.stringify(def.baseUrl)}`;
|
|
260
|
+
if (def.signature && def.publicKey) {
|
|
261
|
+
content += `,\n contractSignature: ${JSON.stringify(def.signature)},\n`;
|
|
262
|
+
content += ` contractPublicKey: ${JSON.stringify(def.publicKey)}\n`;
|
|
263
|
+
} else {
|
|
264
|
+
content += `\n`;
|
|
265
|
+
}
|
|
227
266
|
content += ` },\n`;
|
|
228
267
|
}
|
|
229
268
|
content += ` }\n`;
|
package/src/index.ts
CHANGED
|
@@ -17,7 +17,7 @@ const program = new Command();
|
|
|
17
17
|
program
|
|
18
18
|
.name("atmx")
|
|
19
19
|
.description("Generate TypeScript SDK from AxiomDeps.toml")
|
|
20
|
-
.version("0.
|
|
20
|
+
.version("0.131.0");
|
|
21
21
|
|
|
22
22
|
program
|
|
23
23
|
.command("generate")
|
|
@@ -71,6 +71,8 @@ program
|
|
|
71
71
|
ir: multiIr[namespace],
|
|
72
72
|
baseUrl: (contract as any).base_url || "http://localhost:8080",
|
|
73
73
|
file: `/${namespace}.axiom`,
|
|
74
|
+
signature: (contract as any).signature,
|
|
75
|
+
publicKey: (contract as any).public_key,
|
|
74
76
|
};
|
|
75
77
|
|
|
76
78
|
console.log(`✅ Loaded contract: [${namespace}] -> ${axiomFilePath}`);
|