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.
@@ -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
- content += `export const ${namespace}Module = {\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 Object.keys(contracts)) {
170
- content += ` ${namespace}: ${namespace}Module,\n`;
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 += ` "${ns}": {\n`;
213
- content += ` contractUrl: "${contractPath}",\n`;
214
- content += ` baseUrl: "${def.baseUrl}"\n`;
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.2.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,6 +1,6 @@
1
1
  {
2
2
  "name": "atmx-cli",
3
- "version": "0.131.0",
3
+ "version": "0.135.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -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
- content += `export const ${namespace}Module = {\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 = (${namespace}Module as any)[\`get\${methodName.charAt(0).toUpperCase() + methodName.slice(1)}Def\`](args);\n`;
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 Object.keys(contracts)) {
178
- content += ` ${namespace}: ${namespace}Module,\n`;
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 += ` "${ns}": {\n`;
225
- content += ` contractUrl: "${contractPath}",\n`;
226
- content += ` baseUrl: "${def.baseUrl}"\n`;
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.2.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}`);