create-canton-app 1.5.2 โ 2.0.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/README.md +10 -11
- package/package.json +1 -1
- package/src/commands/create.js +215 -57
package/README.md
CHANGED
|
@@ -24,8 +24,8 @@ npx create-canton-app
|
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
cd my-first-dapp
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
dpm build
|
|
28
|
+
dpm test
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
**That's it!** You now have a working Canton smart contract.
|
|
@@ -60,30 +60,29 @@ Edit `src/commands/create.js` line 43:
|
|
|
60
60
|
|
|
61
61
|
```javascript
|
|
62
62
|
choices: [
|
|
63
|
-
{ name: '
|
|
63
|
+
{ name: 'Token Transfer System Template', value: 'TokenTransfer' },
|
|
64
64
|
|
|
65
|
-
{ name: '
|
|
65
|
+
{ name: 'Multi-Party Agreement System Template', value: 'Multiparty' },
|
|
66
66
|
|
|
67
|
-
{ name: '
|
|
67
|
+
{ name: 'Asset Holding System Template', value: 'AssetOwner' }
|
|
68
68
|
|
|
69
|
-
{ name: '
|
|
69
|
+
{ name: 'My Template', value: 'my-template' }, // ADD THIS
|
|
70
70
|
]
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
4. Try it
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
dpm build
|
|
77
|
+
dpm test
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
## Template Checklist
|
|
81
81
|
|
|
82
|
-
- [ ] Compiles with `
|
|
83
|
-
- [ ] Tests pass with `
|
|
82
|
+
- [ ] Compiles with `dpm build`
|
|
83
|
+
- [ ] Tests pass with `dpm test`
|
|
84
84
|
- [ ] Includes inline comments
|
|
85
85
|
- [ ] Has clear use case
|
|
86
|
-
- [ ] daml.yaml includes `daml-script` dependency
|
|
87
86
|
|
|
88
87
|
<div align="center">
|
|
89
88
|
|
package/package.json
CHANGED
package/src/commands/create.js
CHANGED
|
@@ -14,13 +14,13 @@ const colors = {
|
|
|
14
14
|
bold: (text) => `\x1b[1m${text}\x1b[0m`
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
function
|
|
18
|
-
return shell.which('
|
|
17
|
+
function isDpmInstalled() {
|
|
18
|
+
return shell.which('dpm') !== null;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function
|
|
21
|
+
function getDpmVersion() {
|
|
22
22
|
try {
|
|
23
|
-
const result = shell.exec('
|
|
23
|
+
const result = shell.exec('dpm version --active', { silent: true });
|
|
24
24
|
const match = result.stdout.match(/(\d+\.\d+\.\d+)/);
|
|
25
25
|
return match ? match[1] : null;
|
|
26
26
|
} catch {
|
|
@@ -28,92 +28,161 @@ function getDamlVersion() {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
function getDpmTemplates() {
|
|
32
|
+
try {
|
|
33
|
+
const result = shell.exec('dpm new --list', { silent: true });
|
|
34
|
+
if (result.code !== 0) return [];
|
|
35
|
+
|
|
36
|
+
const lines = result.stdout.split('\n');
|
|
37
|
+
const templates = [];
|
|
38
|
+
let inTemplateList = false;
|
|
39
|
+
|
|
40
|
+
for (const line of lines) {
|
|
41
|
+
if (line.includes('following templates are available')) {
|
|
42
|
+
inTemplateList = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (inTemplateList && line.trim()) {
|
|
46
|
+
const templateName = line.trim();
|
|
47
|
+
if (templateName && !templateName.startsWith('The')) {
|
|
48
|
+
templates.push(templateName);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return templates;
|
|
54
|
+
} catch {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function installDpm() {
|
|
32
60
|
console.log('');
|
|
33
|
-
console.log(colors.yellow('โ ๏ธ
|
|
61
|
+
console.log(colors.yellow('โ ๏ธ DPM (Digital Asset Package Manager) not found!'));
|
|
34
62
|
console.log('');
|
|
35
|
-
console.log(colors.white('
|
|
63
|
+
console.log(colors.white('DPM is the official Canton development tool.'));
|
|
64
|
+
console.log(colors.dim('(Replaces the deprecated Daml Assistant)'));
|
|
36
65
|
console.log('');
|
|
37
66
|
|
|
38
67
|
const answers = await inquirer.prompt([
|
|
39
68
|
{
|
|
40
69
|
type: 'confirm',
|
|
41
|
-
name: '
|
|
42
|
-
message: 'Would you like to install
|
|
70
|
+
name: 'installDpm',
|
|
71
|
+
message: 'Would you like to install DPM now? (Recommended)',
|
|
43
72
|
default: true
|
|
44
73
|
}
|
|
45
74
|
]);
|
|
46
75
|
|
|
47
|
-
if (!answers.
|
|
76
|
+
if (!answers.installDpm) {
|
|
48
77
|
console.log('');
|
|
49
|
-
console.log(colors.yellow('โ ๏ธ
|
|
50
|
-
console.log(colors.dim('
|
|
51
|
-
console.log(colors.white(' curl
|
|
78
|
+
console.log(colors.yellow('โ ๏ธ Skipping DPM installation.'));
|
|
79
|
+
console.log(colors.dim('Install manually:'));
|
|
80
|
+
console.log(colors.white(' curl https://get.digitalasset.com/install/install.sh | sh'));
|
|
52
81
|
console.log('');
|
|
53
82
|
return false;
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
console.log('');
|
|
57
|
-
const spinner = ora('Installing
|
|
86
|
+
const spinner = ora('Installing DPM (this may take a few minutes)...').start();
|
|
58
87
|
|
|
59
88
|
try {
|
|
60
|
-
|
|
89
|
+
// FIXED: Use correct installation URL
|
|
90
|
+
const result = shell.exec('curl -sSL https://get.digitalasset.com/install/install.sh | sh', {
|
|
91
|
+
silent: false // Show output so user can see progress
|
|
92
|
+
});
|
|
61
93
|
|
|
62
94
|
if (result.code !== 0) {
|
|
63
|
-
spinner.fail(colors.red('Failed to install
|
|
95
|
+
spinner.fail(colors.red('Failed to install DPM'));
|
|
64
96
|
console.log('');
|
|
65
|
-
console.log(colors.yellow('
|
|
66
|
-
console.log(colors.white(' curl
|
|
97
|
+
console.log(colors.yellow('Install manually:'));
|
|
98
|
+
console.log(colors.white(' curl https://get.digitalasset.com/install/install.sh | sh'));
|
|
67
99
|
console.log('');
|
|
68
100
|
return false;
|
|
69
101
|
}
|
|
70
102
|
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
// Add to PATH for current session
|
|
104
|
+
const dpmPath = path.join(process.env.HOME, '.dpm', 'bin');
|
|
105
|
+
process.env.PATH = `${dpmPath}:${process.env.PATH}`;
|
|
73
106
|
|
|
74
|
-
spinner.succeed(colors.green('โจ
|
|
107
|
+
spinner.succeed(colors.green('โจ DPM installed successfully!'));
|
|
75
108
|
|
|
76
109
|
console.log('');
|
|
77
|
-
console.log(colors.cyan('
|
|
110
|
+
console.log(colors.cyan('Important: Add DPM to your PATH permanently'));
|
|
78
111
|
console.log(colors.dim('Add this line to your ~/.zshrc or ~/.bashrc:'));
|
|
79
112
|
console.log('');
|
|
80
|
-
console.log(colors.white(` export PATH="$HOME/.
|
|
113
|
+
console.log(colors.white(` export PATH="$HOME/.dpm/bin:$PATH"`));
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log(colors.yellow('Then reload your shell:'));
|
|
116
|
+
console.log(colors.white(' source ~/.zshrc'));
|
|
81
117
|
console.log('');
|
|
82
118
|
|
|
83
119
|
return true;
|
|
84
120
|
} catch (error) {
|
|
85
121
|
spinner.fail(colors.red('Installation failed: ' + error.message));
|
|
122
|
+
console.log('');
|
|
123
|
+
console.log(colors.yellow('Try installing manually:'));
|
|
124
|
+
console.log(colors.white(' curl https://get.digitalasset.com/install/install.sh | sh'));
|
|
125
|
+
console.log('');
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function createFromDpmTemplate(projectName, dpmTemplate) {
|
|
131
|
+
console.log('');
|
|
132
|
+
const spinner = ora(`Creating project from DPM template: ${dpmTemplate}...`).start();
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
// CORRECT DPM syntax: dpm new --template <template-name> <project-name>
|
|
136
|
+
const result = shell.exec(`dpm new --template ${dpmTemplate} ${projectName}`, {
|
|
137
|
+
silent: false
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
if (result.code !== 0) {
|
|
141
|
+
spinner.fail(colors.red('Failed to create project'));
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
spinner.succeed(colors.green('Project created successfully!'));
|
|
146
|
+
return true;
|
|
147
|
+
} catch (error) {
|
|
148
|
+
spinner.fail(colors.red('Error: ' + error.message));
|
|
86
149
|
return false;
|
|
87
150
|
}
|
|
88
151
|
}
|
|
89
152
|
|
|
90
153
|
async function create(projectName, options) {
|
|
91
154
|
try {
|
|
92
|
-
// Check prerequisites
|
|
93
155
|
console.log('');
|
|
94
156
|
console.log(colors.cyan('๐ Checking prerequisites...'));
|
|
95
157
|
console.log('');
|
|
96
158
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
159
|
+
let dpmJustInstalled = false;
|
|
160
|
+
|
|
161
|
+
if (!isDpmInstalled()) {
|
|
162
|
+
const installed = await installDpm();
|
|
163
|
+
if (installed) {
|
|
164
|
+
dpmJustInstalled = true;
|
|
165
|
+
// Give the system a moment to update PATH
|
|
166
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
167
|
+
} else {
|
|
168
|
+
console.log(colors.yellow('โ ๏ธ Continuing without DPM...'));
|
|
169
|
+
console.log(colors.dim('You can install it later and use DPM templates.'));
|
|
101
170
|
console.log('');
|
|
102
171
|
}
|
|
103
172
|
} else {
|
|
104
|
-
const version =
|
|
105
|
-
console.log(colors.green(`โ
|
|
173
|
+
const version = getDpmVersion();
|
|
174
|
+
console.log(colors.green(`โ
DPM found${version ? ` (v${version})` : ''}`));
|
|
106
175
|
}
|
|
107
176
|
|
|
108
177
|
if (!shell.which('java')) {
|
|
109
178
|
console.log(colors.yellow('โ ๏ธ Java not found (optional, needed for tests)'));
|
|
179
|
+
console.log(colors.dim(' Install: brew install openjdk@17'));
|
|
110
180
|
} else {
|
|
111
181
|
console.log(colors.green('โ
Java Runtime found'));
|
|
112
182
|
}
|
|
113
183
|
|
|
114
184
|
console.log('');
|
|
115
185
|
|
|
116
|
-
// Get project name
|
|
117
186
|
if (!projectName) {
|
|
118
187
|
const answers = await inquirer.prompt([
|
|
119
188
|
{
|
|
@@ -126,22 +195,97 @@ async function create(projectName, options) {
|
|
|
126
195
|
projectName = answers.projectName;
|
|
127
196
|
}
|
|
128
197
|
|
|
129
|
-
|
|
130
|
-
let template = options.template;
|
|
131
|
-
|
|
132
|
-
// Check if template was explicitly provided (not just the default)
|
|
198
|
+
let templateType;
|
|
133
199
|
const wasTemplateProvided = process.argv.includes('--template') || process.argv.includes('-t');
|
|
134
200
|
|
|
201
|
+
// Check if DPM is available NOW (after potential installation)
|
|
202
|
+
const dpmAvailable = isDpmInstalled();
|
|
203
|
+
|
|
204
|
+
if (!wasTemplateProvided) {
|
|
205
|
+
const choices = [
|
|
206
|
+
{ name: 'Beginner Templates (curated)', value: 'beginner' }
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
// Only show DPM option if DPM is actually installed
|
|
210
|
+
if (dpmAvailable) {
|
|
211
|
+
choices.push({ name: 'Official DPM Templates (advanced)', value: 'dpm' });
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const typeAnswers = await inquirer.prompt([
|
|
215
|
+
{
|
|
216
|
+
type: 'list',
|
|
217
|
+
name: 'templateType',
|
|
218
|
+
message: 'What type of template would you like?',
|
|
219
|
+
choices
|
|
220
|
+
}
|
|
221
|
+
]);
|
|
222
|
+
templateType = typeAnswers.templateType;
|
|
223
|
+
} else {
|
|
224
|
+
templateType = 'beginner';
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (templateType === 'dpm') {
|
|
228
|
+
if (!dpmAvailable) {
|
|
229
|
+
console.log(colors.red('โ DPM required for official templates.'));
|
|
230
|
+
console.log(colors.yellow('Please install DPM first:'));
|
|
231
|
+
console.log(colors.white(' curl https://get.digitalasset.com/install/install.sh | sh'));
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
console.log('');
|
|
236
|
+
console.log(colors.cyan('Fetching DPM templates...'));
|
|
237
|
+
|
|
238
|
+
const dpmTemplates = getDpmTemplates();
|
|
239
|
+
|
|
240
|
+
if (dpmTemplates.length === 0) {
|
|
241
|
+
console.log(colors.yellow('โ ๏ธ Could not fetch DPM templates.'));
|
|
242
|
+
console.log(colors.dim('Try running: dpm new --list'));
|
|
243
|
+
console.log('');
|
|
244
|
+
console.log(colors.yellow('Falling back to beginner templates...'));
|
|
245
|
+
templateType = 'beginner';
|
|
246
|
+
} else {
|
|
247
|
+
console.log(colors.green(`โ
Found ${dpmTemplates.length} DPM templates`));
|
|
248
|
+
console.log('');
|
|
249
|
+
|
|
250
|
+
const templateAnswers = await inquirer.prompt([
|
|
251
|
+
{
|
|
252
|
+
type: 'list',
|
|
253
|
+
name: 'dpmTemplate',
|
|
254
|
+
message: 'Select a DPM template:',
|
|
255
|
+
choices: dpmTemplates.map(t => ({ name: ` ${t}`, value: t })),
|
|
256
|
+
pageSize: 15
|
|
257
|
+
}
|
|
258
|
+
]);
|
|
259
|
+
|
|
260
|
+
const success = await createFromDpmTemplate(projectName, templateAnswers.dpmTemplate);
|
|
261
|
+
|
|
262
|
+
if (success) {
|
|
263
|
+
console.log('');
|
|
264
|
+
console.log(colors.cyan(colors.bold('๐ Next steps:')));
|
|
265
|
+
console.log('');
|
|
266
|
+
console.log(colors.white(` cd ${projectName}`));
|
|
267
|
+
console.log(colors.white(` dpm build`));
|
|
268
|
+
console.log(colors.white(` dpm test`));
|
|
269
|
+
console.log('');
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Handle beginner templates
|
|
277
|
+
let template = options.template;
|
|
278
|
+
|
|
135
279
|
if (!wasTemplateProvided) {
|
|
136
280
|
const answers = await inquirer.prompt([
|
|
137
281
|
{
|
|
138
282
|
type: 'list',
|
|
139
283
|
name: 'template',
|
|
140
|
-
message: 'Which template would you like
|
|
284
|
+
message: 'Which template would you like?',
|
|
141
285
|
choices: [
|
|
142
|
-
{ name: 'Token Transfer System
|
|
143
|
-
{ name: 'Multi-Party Agreement
|
|
144
|
-
{ name: 'Asset Holding System
|
|
286
|
+
{ name: 'Token Transfer System', value: 'TokenTransfer' },
|
|
287
|
+
{ name: 'Multi-Party Agreement', value: 'Multiparty' },
|
|
288
|
+
{ name: 'Asset Holding System', value: 'AssetOwner' }
|
|
145
289
|
]
|
|
146
290
|
}
|
|
147
291
|
]);
|
|
@@ -164,7 +308,7 @@ async function create(projectName, options) {
|
|
|
164
308
|
if (fs.existsSync(templatePath)) {
|
|
165
309
|
fs.copySync(templatePath, projectPath);
|
|
166
310
|
} else {
|
|
167
|
-
spinner.warn(colors.yellow(`Template ${template} not found
|
|
311
|
+
spinner.warn(colors.yellow(`Template ${template} not found.`));
|
|
168
312
|
fs.mkdirSync(path.join(projectPath, 'daml'), { recursive: true });
|
|
169
313
|
}
|
|
170
314
|
|
|
@@ -179,24 +323,34 @@ async function create(projectName, options) {
|
|
|
179
323
|
spinner.succeed(colors.green('โจ Project created successfully!'));
|
|
180
324
|
|
|
181
325
|
console.log('');
|
|
182
|
-
console.log(colors.cyan(colors.bold('
|
|
326
|
+
console.log(colors.cyan(colors.bold('Next steps:')));
|
|
183
327
|
console.log('');
|
|
184
328
|
console.log(colors.white(` cd ${projectName}`));
|
|
185
329
|
|
|
186
|
-
if (
|
|
187
|
-
console.log(colors.white(`
|
|
188
|
-
console.log(colors.white(`
|
|
330
|
+
if (dpmAvailable) {
|
|
331
|
+
console.log(colors.white(` dpm build ${colors.dim('# Compile')}`));
|
|
332
|
+
console.log(colors.white(` dpm test ${colors.dim('# Run tests')}`));
|
|
189
333
|
} else {
|
|
190
|
-
console.log(colors.yellow(` # First, install
|
|
191
|
-
console.log(colors.white(` curl
|
|
334
|
+
console.log(colors.yellow(` # First, install DPM:`));
|
|
335
|
+
console.log(colors.white(` curl https://get.digitalasset.com/install/install.sh | sh`));
|
|
336
|
+
console.log(colors.white(` source ~/.zshrc`));
|
|
337
|
+
console.log(colors.white(` dpm build`));
|
|
192
338
|
}
|
|
193
339
|
|
|
194
340
|
console.log('');
|
|
195
|
-
console.log(colors.dim('๐ Read README.md for more
|
|
341
|
+
console.log(colors.dim('๐ Read README.md for more'));
|
|
196
342
|
console.log('');
|
|
197
343
|
|
|
344
|
+
if (dpmJustInstalled) {
|
|
345
|
+
console.log(colors.cyan('๐ก Tip: Restart your terminal or run:'));
|
|
346
|
+
console.log(colors.white(` source ~/.zshrc`));
|
|
347
|
+
console.log(colors.dim('to use dpm commands immediately'));
|
|
348
|
+
console.log('');
|
|
349
|
+
}
|
|
350
|
+
|
|
198
351
|
} catch (error) {
|
|
199
|
-
console.error(colors.red('โ Error
|
|
352
|
+
console.error(colors.red('โ Error:'), error.message);
|
|
353
|
+
console.error(error.stack);
|
|
200
354
|
process.exit(1);
|
|
201
355
|
}
|
|
202
356
|
}
|
|
@@ -204,13 +358,13 @@ async function create(projectName, options) {
|
|
|
204
358
|
function createScripts(projectPath) {
|
|
205
359
|
const compileScript = `#!/bin/bash
|
|
206
360
|
echo "๐จ Compiling Daml contracts..."
|
|
207
|
-
|
|
361
|
+
dpm build
|
|
208
362
|
`;
|
|
209
363
|
fs.writeFileSync(path.join(projectPath, 'scripts/compile.sh'), compileScript);
|
|
210
364
|
|
|
211
365
|
const testScript = `#!/bin/bash
|
|
212
366
|
echo "๐งช Running tests..."
|
|
213
|
-
|
|
367
|
+
dpm test
|
|
214
368
|
`;
|
|
215
369
|
fs.writeFileSync(path.join(projectPath, 'scripts/test.sh'), testScript);
|
|
216
370
|
|
|
@@ -234,6 +388,7 @@ dependencies:
|
|
|
234
388
|
|
|
235
389
|
function createGitignore(projectPath) {
|
|
236
390
|
const gitignore = `.daml/
|
|
391
|
+
.dpm/
|
|
237
392
|
*.dar
|
|
238
393
|
*.log
|
|
239
394
|
node_modules/
|
|
@@ -245,28 +400,31 @@ node_modules/
|
|
|
245
400
|
function createReadme(projectPath, projectName, template) {
|
|
246
401
|
const readme = `# ${projectName}
|
|
247
402
|
|
|
248
|
-
>
|
|
403
|
+
> Built with create-canton-app
|
|
249
404
|
|
|
250
405
|
## Template: ${template}
|
|
251
406
|
|
|
252
407
|
## Quick Start
|
|
253
408
|
|
|
254
409
|
\`\`\`bash
|
|
255
|
-
# Compile
|
|
256
|
-
|
|
410
|
+
dpm build # Compile
|
|
411
|
+
dpm test # Run tests
|
|
412
|
+
\`\`\`
|
|
413
|
+
|
|
414
|
+
## Prerequisites
|
|
257
415
|
|
|
258
|
-
|
|
259
|
-
|
|
416
|
+
\`\`\`bash
|
|
417
|
+
curl https://get.digitalasset.com/install/install.sh | sh
|
|
260
418
|
\`\`\`
|
|
261
419
|
|
|
262
420
|
## Learn More
|
|
263
421
|
|
|
264
422
|
- [Canton Docs](https://docs.digitalasset.com)
|
|
265
|
-
- [
|
|
423
|
+
- [DPM Docs](https://docs.digitalasset.com/build/3.4/dpm/dpm.html)
|
|
266
424
|
- [Canton Network](https://canton.network)
|
|
267
425
|
`;
|
|
268
426
|
|
|
269
427
|
fs.writeFileSync(path.join(projectPath, 'README.md'), readme);
|
|
270
428
|
}
|
|
271
429
|
|
|
272
|
-
module.exports = create;
|
|
430
|
+
module.exports = create;
|