@caatinga/core 0.2.0 → 0.2.2
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/LICENSE +1 -1
- package/README.md +89 -15
- package/dist/browser-DUcSR5D3.d.cts +173 -0
- package/dist/browser-DUcSR5D3.d.ts +173 -0
- package/dist/browser.cjs +106 -0
- package/dist/browser.d.cts +2 -0
- package/dist/browser.d.ts +2 -0
- package/dist/browser.js +10 -0
- package/dist/chunk-GMABXVEY.js +78 -0
- package/dist/index.cjs +472 -85
- package/dist/index.d.cts +50 -177
- package/dist/index.d.ts +50 -177
- package/dist/index.js +474 -155
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -1,72 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
UNEXPECTED_ERROR: "CAATINGA_UNEXPECTED_ERROR",
|
|
7
|
-
STELLAR_CLI_NOT_FOUND: "CAATINGA_STELLAR_CLI_NOT_FOUND",
|
|
8
|
-
STELLAR_CLI_VERSION_PARSE_FAILED: "CAATINGA_STELLAR_CLI_VERSION_PARSE_FAILED",
|
|
9
|
-
UNSUPPORTED_CLI_VERSION: "CAATINGA_UNSUPPORTED_CLI_VERSION",
|
|
10
|
-
UNTESTED_CLI_VERSION: "CAATINGA_UNTESTED_CLI_VERSION",
|
|
11
|
-
RUST_NOT_FOUND: "CAATINGA_RUST_NOT_FOUND",
|
|
12
|
-
RUST_TARGET_NOT_FOUND: "CAATINGA_RUST_TARGET_NOT_FOUND",
|
|
13
|
-
DEPLOY_FAILED: "CAATINGA_DEPLOY_FAILED",
|
|
14
|
-
BUILD_FAILED: "CAATINGA_BUILD_FAILED",
|
|
15
|
-
BINDINGS_FAILED: "CAATINGA_BINDINGS_FAILED",
|
|
16
|
-
INVOKE_FAILED: "CAATINGA_INVOKE_FAILED",
|
|
17
|
-
CONTRACT_NOT_FOUND: "CAATINGA_CONTRACT_NOT_FOUND",
|
|
18
|
-
NETWORK_NOT_FOUND: "CAATINGA_NETWORK_NOT_FOUND",
|
|
19
|
-
ARTIFACT_NOT_FOUND: "CAATINGA_ARTIFACT_NOT_FOUND",
|
|
20
|
-
ARTIFACT_INVALID: "CAATINGA_ARTIFACT_INVALID",
|
|
21
|
-
CONTRACT_ID_NOT_FOUND: "CAATINGA_CONTRACT_ID_NOT_FOUND",
|
|
22
|
-
CONTRACT_ARTIFACT_NOT_FOUND: "CAATINGA_CONTRACT_ARTIFACT_NOT_FOUND",
|
|
23
|
-
CONTRACT_DEPENDENCY_NOT_FOUND: "CAATINGA_CONTRACT_DEPENDENCY_NOT_FOUND",
|
|
24
|
-
CONTRACT_DEPENDENCY_CYCLE: "CAATINGA_CONTRACT_DEPENDENCY_CYCLE",
|
|
25
|
-
CONTRACT_DEPENDENCY_ARTIFACT_NOT_FOUND: "CAATINGA_CONTRACT_DEPENDENCY_ARTIFACT_NOT_FOUND",
|
|
26
|
-
DEPLOY_ARG_PLACEHOLDER_INVALID: "CAATINGA_DEPLOY_ARG_PLACEHOLDER_INVALID",
|
|
27
|
-
DEPLOY_ARG_PLACEHOLDER_UNRESOLVED: "CAATINGA_DEPLOY_ARG_PLACEHOLDER_UNRESOLVED",
|
|
28
|
-
BINDING_CLIENT_NOT_FOUND: "CAATINGA_BINDING_CLIENT_NOT_FOUND",
|
|
29
|
-
BINDING_METHOD_NOT_FOUND: "CAATINGA_BINDING_METHOD_NOT_FOUND",
|
|
30
|
-
XDR_BUILD_FAILED: "CAATINGA_XDR_BUILD_FAILED",
|
|
31
|
-
XDR_PREPARE_FAILED: "CAATINGA_XDR_PREPARE_FAILED",
|
|
32
|
-
XDR_SIGN_FAILED: "CAATINGA_XDR_SIGN_FAILED",
|
|
33
|
-
XDR_SUBMIT_FAILED: "CAATINGA_XDR_SUBMIT_FAILED",
|
|
34
|
-
XDR_RESULT_FAILED: "CAATINGA_XDR_RESULT_FAILED",
|
|
35
|
-
WALLET_NOT_CONNECTED: "CAATINGA_WALLET_NOT_CONNECTED",
|
|
36
|
-
SOURCE_ACCOUNT_REQUIRED: "CAATINGA_SOURCE_ACCOUNT_REQUIRED",
|
|
37
|
-
UNSAFE_SOURCE_ACCOUNT: "CAATINGA_UNSAFE_SOURCE_ACCOUNT",
|
|
38
|
-
INVOKE_TARGET_INVALID: "CAATINGA_INVOKE_TARGET_INVALID",
|
|
39
|
-
TEMPLATE_NOT_FOUND: "CAATINGA_TEMPLATE_NOT_FOUND",
|
|
40
|
-
INVALID_TEMPLATE_MANIFEST: "CAATINGA_INVALID_TEMPLATE_MANIFEST",
|
|
41
|
-
TEMPLATE_MANIFEST_NOT_FOUND: "CAATINGA_TEMPLATE_MANIFEST_NOT_FOUND",
|
|
42
|
-
TEMPLATE_INCOMPATIBLE: "CAATINGA_TEMPLATE_INCOMPATIBLE"
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// src/errors/CaatingaError.ts
|
|
46
|
-
var CaatingaError = class extends Error {
|
|
47
|
-
constructor(message, code, hint, cause) {
|
|
48
|
-
super(message);
|
|
49
|
-
this.code = code;
|
|
50
|
-
this.hint = hint;
|
|
51
|
-
this.cause = cause;
|
|
52
|
-
this.name = "CaatingaError";
|
|
53
|
-
}
|
|
54
|
-
code;
|
|
55
|
-
hint;
|
|
56
|
-
cause;
|
|
57
|
-
};
|
|
58
|
-
function toCaatingaError(error) {
|
|
59
|
-
if (error instanceof CaatingaError) {
|
|
60
|
-
return error;
|
|
61
|
-
}
|
|
62
|
-
if (error instanceof Error) {
|
|
63
|
-
return new CaatingaError(error.message, CaatingaErrorCode.UNEXPECTED_ERROR, void 0, error);
|
|
64
|
-
}
|
|
65
|
-
return new CaatingaError("An unexpected error occurred.", CaatingaErrorCode.UNEXPECTED_ERROR);
|
|
66
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
CaatingaError,
|
|
3
|
+
CaatingaErrorCode,
|
|
4
|
+
toCaatingaError
|
|
5
|
+
} from "./chunk-GMABXVEY.js";
|
|
67
6
|
|
|
68
7
|
// src/version.ts
|
|
69
|
-
var CAATINGA_CORE_VERSION = "0.2.
|
|
8
|
+
var CAATINGA_CORE_VERSION = "0.2.2";
|
|
70
9
|
|
|
71
10
|
// src/config/config.schema.ts
|
|
72
11
|
import { z } from "zod";
|
|
@@ -253,7 +192,7 @@ import { execa } from "execa";
|
|
|
253
192
|
|
|
254
193
|
// src/stellar-cli/version.ts
|
|
255
194
|
import semver from "semver";
|
|
256
|
-
var STELLAR_CLI_MIN_VERSION = "
|
|
195
|
+
var STELLAR_CLI_MIN_VERSION = "23.0.0";
|
|
257
196
|
var STELLAR_CLI_TESTED_MAX_VERSION = "25.2.0";
|
|
258
197
|
var STELLAR_CLI_SEMVER_REGEX = /\b(\d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)?(?:\+[0-9A-Za-z-.]+)?)\b/;
|
|
259
198
|
function parseStellarCliVersion(output) {
|
|
@@ -386,6 +325,146 @@ function parseContractId(output) {
|
|
|
386
325
|
return match[0];
|
|
387
326
|
}
|
|
388
327
|
|
|
328
|
+
// src/stellar-cli/build-stellar-network-args.ts
|
|
329
|
+
function matchesWellKnownNetwork(name, config) {
|
|
330
|
+
const known = WELL_KNOWN_NETWORKS[name];
|
|
331
|
+
if (!known) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
return known.rpcUrl === config.rpcUrl && known.networkPassphrase === config.networkPassphrase;
|
|
335
|
+
}
|
|
336
|
+
function buildRpcNetworkArgs(config) {
|
|
337
|
+
return [
|
|
338
|
+
"--rpc-url",
|
|
339
|
+
config.rpcUrl,
|
|
340
|
+
"--network-passphrase",
|
|
341
|
+
config.networkPassphrase
|
|
342
|
+
];
|
|
343
|
+
}
|
|
344
|
+
function buildStellarNetworkArgsFromConfig(config) {
|
|
345
|
+
for (const [name, known] of Object.entries(WELL_KNOWN_NETWORKS)) {
|
|
346
|
+
if (known.rpcUrl === config.rpcUrl && known.networkPassphrase === config.networkPassphrase) {
|
|
347
|
+
return ["--network", name];
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return buildRpcNetworkArgs(config);
|
|
351
|
+
}
|
|
352
|
+
function buildStellarNetworkArgs(network) {
|
|
353
|
+
if (matchesWellKnownNetwork(network.name, network.config)) {
|
|
354
|
+
return ["--network", network.name];
|
|
355
|
+
}
|
|
356
|
+
return buildStellarNetworkArgsFromConfig(network.config);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/stellar-cli/recover-deploy-contract-id.ts
|
|
360
|
+
var TX_HASH_REGEX = /Transaction hash is ([a-f0-9]{64})/i;
|
|
361
|
+
var DEPLOY_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i;
|
|
362
|
+
var HORIZON_URL_BY_PASSPHRASE = {
|
|
363
|
+
"Test SDF Network ; September 2015": "https://horizon-testnet.stellar.org",
|
|
364
|
+
"Public Global Stellar Network ; September 2015": "https://horizon.stellar.org"
|
|
365
|
+
};
|
|
366
|
+
function isLikelyPublicKeySource(source) {
|
|
367
|
+
return /^G[A-Z2-7]{55}$/.test(source);
|
|
368
|
+
}
|
|
369
|
+
function decimalSaltToHex(salt) {
|
|
370
|
+
return BigInt(salt).toString(16).padStart(64, "0");
|
|
371
|
+
}
|
|
372
|
+
function resolveHorizonUrl(network) {
|
|
373
|
+
const horizonUrl = HORIZON_URL_BY_PASSPHRASE[network.networkPassphrase];
|
|
374
|
+
if (!horizonUrl) {
|
|
375
|
+
throw new CaatingaError(
|
|
376
|
+
`No Horizon URL mapping for network passphrase "${network.networkPassphrase}".`,
|
|
377
|
+
CaatingaErrorCode.NETWORK_NOT_FOUND,
|
|
378
|
+
"Use testnet or mainnet, or extend Caatinga network metadata."
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
return horizonUrl;
|
|
382
|
+
}
|
|
383
|
+
async function fetchCreateContractSalt(horizonUrl, transactionHash, fetchImpl = fetch) {
|
|
384
|
+
const response = await fetchImpl(`${horizonUrl}/transactions/${transactionHash}/operations`);
|
|
385
|
+
if (!response.ok) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
const body = await response.json();
|
|
389
|
+
const operation = body._embedded?.records?.find(
|
|
390
|
+
(record) => record.transaction_successful === true && record.type === "invoke_host_function" && record.function === "HostFunctionTypeHostFunctionTypeCreateContract" && typeof record.salt === "string"
|
|
391
|
+
);
|
|
392
|
+
return operation?.salt ?? null;
|
|
393
|
+
}
|
|
394
|
+
async function resolveContractIdFromDeploySalt(options) {
|
|
395
|
+
const saltHex = decimalSaltToHex(options.salt);
|
|
396
|
+
const result = await runCommand("stellar", [
|
|
397
|
+
"contract",
|
|
398
|
+
"id",
|
|
399
|
+
"wasm",
|
|
400
|
+
"--salt",
|
|
401
|
+
saltHex,
|
|
402
|
+
"--source-account",
|
|
403
|
+
options.source,
|
|
404
|
+
...buildStellarNetworkArgsFromConfig(options.network)
|
|
405
|
+
], {
|
|
406
|
+
cwd: options.cwd,
|
|
407
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
408
|
+
skipStellarVersionCheck: true
|
|
409
|
+
});
|
|
410
|
+
return parseContractId(result.all || `${result.stdout}
|
|
411
|
+
${result.stderr}`);
|
|
412
|
+
}
|
|
413
|
+
async function tryRecoverContractIdFromDeployFailure(options) {
|
|
414
|
+
if (!DEPLOY_SIGNING_FAILURE_REGEX.test(options.output)) {
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
const hashMatch = options.output.match(TX_HASH_REGEX);
|
|
418
|
+
if (!hashMatch) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
const horizonUrl = resolveHorizonUrl(options.network);
|
|
422
|
+
const salt = await fetchCreateContractSalt(horizonUrl, hashMatch[1], options.fetchImpl);
|
|
423
|
+
if (!salt) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
return resolveContractIdFromDeploySalt({
|
|
427
|
+
salt,
|
|
428
|
+
source: options.source,
|
|
429
|
+
network: options.network,
|
|
430
|
+
cwd: options.cwd,
|
|
431
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// src/contracts/validate-source-shape.ts
|
|
436
|
+
function validateSourceShape(source) {
|
|
437
|
+
if (source.startsWith("S")) {
|
|
438
|
+
return new CaatingaError(
|
|
439
|
+
"Refusing to accept a Stellar secret key as --source.",
|
|
440
|
+
CaatingaErrorCode.SOURCE_IS_SECRET_KEY,
|
|
441
|
+
"Use a Stellar CLI identity alias instead, for example: --source alice"
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
if (source.trim().includes(" ")) {
|
|
445
|
+
return new CaatingaError(
|
|
446
|
+
"Refusing to accept a seed phrase as --source.",
|
|
447
|
+
CaatingaErrorCode.SOURCE_IS_SEED_PHRASE,
|
|
448
|
+
"Use a Stellar CLI identity alias instead, for example: --source alice"
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
if (isLikelyPublicKeySource(source)) {
|
|
452
|
+
return new CaatingaError(
|
|
453
|
+
`Public account address cannot sign transactions: ${source}`,
|
|
454
|
+
CaatingaErrorCode.SOURCE_IS_PUBLIC_KEY,
|
|
455
|
+
"Use a Stellar CLI identity with a secret key. Example: stellar keys generate alice --fund --network testnet, then --source alice"
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
if (source.startsWith("G")) {
|
|
459
|
+
return new CaatingaError(
|
|
460
|
+
"Refusing to accept a public account address as --source.",
|
|
461
|
+
CaatingaErrorCode.UNSAFE_SOURCE_ACCOUNT,
|
|
462
|
+
"Use a Stellar CLI identity alias, not a public address. Example: --source alice"
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return void 0;
|
|
466
|
+
}
|
|
467
|
+
|
|
389
468
|
// src/contracts/resolve-contract.ts
|
|
390
469
|
import path4 from "path";
|
|
391
470
|
function resolveContract(config, contractName, cwd = process.cwd()) {
|
|
@@ -407,25 +486,99 @@ function resolveContract(config, contractName, cwd = process.cwd()) {
|
|
|
407
486
|
|
|
408
487
|
// src/contracts/wasm.ts
|
|
409
488
|
import { createHash } from "crypto";
|
|
410
|
-
import { access as access2, readFile as readFile2 } from "fs/promises";
|
|
411
|
-
|
|
489
|
+
import { access as access2, readdir, readFile as readFile2, stat } from "fs/promises";
|
|
490
|
+
import path5 from "path";
|
|
491
|
+
var LEGACY_RUST_WASM_TARGET = "wasm32-unknown-unknown";
|
|
492
|
+
var CURRENT_RUST_WASM_TARGET = "wasm32v1-none";
|
|
493
|
+
function toCurrentWasmTargetPath(wasmPath) {
|
|
494
|
+
if (!wasmPath.includes(LEGACY_RUST_WASM_TARGET)) {
|
|
495
|
+
return wasmPath;
|
|
496
|
+
}
|
|
497
|
+
return wasmPath.replaceAll(LEGACY_RUST_WASM_TARGET, CURRENT_RUST_WASM_TARGET);
|
|
498
|
+
}
|
|
499
|
+
function wasmNotFoundError(configuredWasmPath, options) {
|
|
500
|
+
const migratedPath = options?.migratedPath;
|
|
501
|
+
const hint = migratedPath === void 0 ? "Run caatinga build before deploy or generate." : [
|
|
502
|
+
"Run caatinga build before deploy or generate.",
|
|
503
|
+
`Soroban builds use the "${CURRENT_RUST_WASM_TARGET}" target.`,
|
|
504
|
+
`Update wasm in caatinga.config.ts to "${toConfigRelativeWasmPath(migratedPath)}" or an equivalent path under target/${CURRENT_RUST_WASM_TARGET}/release/.`
|
|
505
|
+
].join(" ");
|
|
506
|
+
return new CaatingaError(
|
|
507
|
+
`WASM output was not found at ${configuredWasmPath}.`,
|
|
508
|
+
CaatingaErrorCode.ARTIFACT_NOT_FOUND,
|
|
509
|
+
hint
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
function toConfigRelativeWasmPath(absoluteWasmPath) {
|
|
513
|
+
const relative = path5.relative(process.cwd(), absoluteWasmPath);
|
|
514
|
+
return relative.startsWith("..") ? absoluteWasmPath : `./${relative.split(path5.sep).join("/")}`;
|
|
515
|
+
}
|
|
516
|
+
async function resolveWasmArtifactPath(configuredWasmPath) {
|
|
412
517
|
try {
|
|
413
|
-
await access2(
|
|
518
|
+
await access2(configuredWasmPath);
|
|
519
|
+
return configuredWasmPath;
|
|
414
520
|
} catch {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
521
|
+
const currentTargetPath = toCurrentWasmTargetPath(configuredWasmPath);
|
|
522
|
+
if (currentTargetPath === configuredWasmPath) {
|
|
523
|
+
throw wasmNotFoundError(configuredWasmPath);
|
|
524
|
+
}
|
|
525
|
+
try {
|
|
526
|
+
await access2(currentTargetPath);
|
|
527
|
+
return currentTargetPath;
|
|
528
|
+
} catch {
|
|
529
|
+
throw wasmNotFoundError(configuredWasmPath, { migratedPath: currentTargetPath });
|
|
530
|
+
}
|
|
420
531
|
}
|
|
421
532
|
}
|
|
422
533
|
async function hashWasm(wasmPath) {
|
|
423
534
|
const bytes = await readFile2(wasmPath);
|
|
424
535
|
return createHash("sha256").update(bytes).digest("hex");
|
|
425
536
|
}
|
|
537
|
+
async function getNewestMtimeInDirectory(directory) {
|
|
538
|
+
try {
|
|
539
|
+
await access2(directory);
|
|
540
|
+
} catch {
|
|
541
|
+
return void 0;
|
|
542
|
+
}
|
|
543
|
+
let newest = 0;
|
|
544
|
+
async function walk(dir) {
|
|
545
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
546
|
+
for (const entry of entries) {
|
|
547
|
+
const entryPath = path5.join(dir, entry.name);
|
|
548
|
+
if (entry.isDirectory()) {
|
|
549
|
+
await walk(entryPath);
|
|
550
|
+
continue;
|
|
551
|
+
}
|
|
552
|
+
if (!entry.isFile()) {
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
const fileStat = await stat(entryPath);
|
|
556
|
+
newest = Math.max(newest, fileStat.mtimeMs);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
await walk(directory);
|
|
560
|
+
return newest > 0 ? newest : void 0;
|
|
561
|
+
}
|
|
562
|
+
async function isWasmOlderThanSources(input) {
|
|
563
|
+
const srcDir = path5.join(input.contractPath, "src");
|
|
564
|
+
const newestSourceMtime = await getNewestMtimeInDirectory(srcDir);
|
|
565
|
+
if (newestSourceMtime === void 0) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
let wasmStat;
|
|
569
|
+
try {
|
|
570
|
+
wasmStat = await stat(input.wasmPath);
|
|
571
|
+
} catch {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
return wasmStat.mtimeMs < newestSourceMtime;
|
|
575
|
+
}
|
|
576
|
+
function formatStaleWasmWarning(contractName) {
|
|
577
|
+
return `WASM for "${contractName}" may be stale: contract sources under src/ are newer than the WASM file. Run \`caatinga build\` before deploy.`;
|
|
578
|
+
}
|
|
426
579
|
|
|
427
580
|
// src/contracts/build-contract.ts
|
|
428
|
-
var RUST_WASM_TARGET = "
|
|
581
|
+
var RUST_WASM_TARGET = "wasm32v1-none";
|
|
429
582
|
var MISSING_WASM_TARGET_HINT_SUBSTRINGS = [
|
|
430
583
|
"not installed",
|
|
431
584
|
"not found",
|
|
@@ -467,21 +620,24 @@ async function buildContract(options) {
|
|
|
467
620
|
throw new CaatingaError(
|
|
468
621
|
`Required Rust wasm target "${RUST_WASM_TARGET}" is missing.`,
|
|
469
622
|
CaatingaErrorCode.RUST_TARGET_NOT_FOUND,
|
|
470
|
-
`Run \`rustup target add ${RUST_WASM_TARGET}\` and retry
|
|
623
|
+
`Run \`rustup target add ${RUST_WASM_TARGET}\` and retry.`,
|
|
471
624
|
error
|
|
472
625
|
);
|
|
473
626
|
}
|
|
474
627
|
throw error;
|
|
475
628
|
}
|
|
476
|
-
await
|
|
629
|
+
const wasmPath = await resolveWasmArtifactPath(contract.wasmPath);
|
|
477
630
|
return {
|
|
478
|
-
contract
|
|
631
|
+
contract: {
|
|
632
|
+
...contract,
|
|
633
|
+
wasmPath
|
|
634
|
+
},
|
|
479
635
|
output: result.all || result.stdout
|
|
480
636
|
};
|
|
481
637
|
}
|
|
482
638
|
|
|
483
639
|
// src/contracts/deploy-contract.ts
|
|
484
|
-
import
|
|
640
|
+
import path6 from "path";
|
|
485
641
|
|
|
486
642
|
// src/contracts/dependency-graph.ts
|
|
487
643
|
function buildDependencyGraph(contracts) {
|
|
@@ -529,15 +685,12 @@ function assertSafeSourceAccount(source) {
|
|
|
529
685
|
throw new CaatingaError(
|
|
530
686
|
"A source account or Stellar CLI identity is required.",
|
|
531
687
|
CaatingaErrorCode.SOURCE_ACCOUNT_REQUIRED,
|
|
532
|
-
"Pass
|
|
688
|
+
"Pass a Stellar CLI identity alias, for example: --source alice"
|
|
533
689
|
);
|
|
534
690
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
CaatingaErrorCode.UNSAFE_SOURCE_ACCOUNT,
|
|
539
|
-
"Use a Stellar CLI identity alias or public account address instead."
|
|
540
|
-
);
|
|
691
|
+
const unsafeSource = validateSourceShape(source);
|
|
692
|
+
if (unsafeSource) {
|
|
693
|
+
throw unsafeSource;
|
|
541
694
|
}
|
|
542
695
|
return source;
|
|
543
696
|
}
|
|
@@ -565,17 +718,32 @@ async function deployContract(options) {
|
|
|
565
718
|
await checkBinary("stellar", "Install Stellar CLI before running caatinga deploy.", {
|
|
566
719
|
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
567
720
|
});
|
|
568
|
-
await
|
|
721
|
+
const wasmPath = await resolveWasmArtifactPath(contract.wasmPath);
|
|
722
|
+
const contractWithWasm = {
|
|
723
|
+
...contract,
|
|
724
|
+
wasmPath
|
|
725
|
+
};
|
|
726
|
+
let staleWasmWarning;
|
|
727
|
+
if (options.checkStaleWasm !== false) {
|
|
728
|
+
const stale = await isWasmOlderThanSources({
|
|
729
|
+
wasmPath,
|
|
730
|
+
contractPath: contract.sourcePath
|
|
731
|
+
});
|
|
732
|
+
if (stale) {
|
|
733
|
+
staleWasmWarning = formatStaleWasmWarning(contract.name);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
569
736
|
const artifactsBefore = await readArtifacts(cwd);
|
|
570
737
|
const existing = artifactsBefore.networks[network.name]?.contracts[contract.name];
|
|
571
738
|
if (existing?.contractId && !options.force) {
|
|
572
739
|
return {
|
|
573
|
-
contract,
|
|
740
|
+
contract: contractWithWasm,
|
|
574
741
|
network,
|
|
575
742
|
contractId: existing.contractId,
|
|
576
|
-
artifactsPath:
|
|
743
|
+
artifactsPath: path6.resolve(cwd, "caatinga.artifacts.json"),
|
|
577
744
|
output: "",
|
|
578
|
-
skipped: true
|
|
745
|
+
skipped: true,
|
|
746
|
+
staleWasmWarning
|
|
579
747
|
};
|
|
580
748
|
}
|
|
581
749
|
const rawDeployArgs = contract.config.deployArgs;
|
|
@@ -606,24 +774,46 @@ async function deployContract(options) {
|
|
|
606
774
|
"contract",
|
|
607
775
|
"deploy",
|
|
608
776
|
"--wasm",
|
|
609
|
-
|
|
777
|
+
wasmPath,
|
|
610
778
|
"--source-account",
|
|
611
779
|
source,
|
|
612
|
-
|
|
613
|
-
network.config.rpcUrl,
|
|
614
|
-
"--network-passphrase",
|
|
615
|
-
network.config.networkPassphrase,
|
|
780
|
+
...buildStellarNetworkArgs(network),
|
|
616
781
|
...constructorArgs
|
|
617
782
|
];
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
783
|
+
let output = "";
|
|
784
|
+
let contractId;
|
|
785
|
+
try {
|
|
786
|
+
const result = await runCommand("stellar", stellarArgs, {
|
|
787
|
+
cwd,
|
|
788
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
789
|
+
failureCode: CaatingaErrorCode.DEPLOY_FAILED
|
|
790
|
+
});
|
|
791
|
+
output = result.all || `${result.stdout}
|
|
624
792
|
${result.stderr}`;
|
|
625
|
-
|
|
626
|
-
|
|
793
|
+
contractId = parseContractId(output);
|
|
794
|
+
} catch (error) {
|
|
795
|
+
if (!(error instanceof CaatingaError) || error.code !== CaatingaErrorCode.DEPLOY_FAILED) {
|
|
796
|
+
throw error;
|
|
797
|
+
}
|
|
798
|
+
const recoveredContractId = await tryRecoverContractIdFromDeployFailure({
|
|
799
|
+
output: `${error.message}
|
|
800
|
+
${error.hint ?? ""}`,
|
|
801
|
+
source,
|
|
802
|
+
network: network.config,
|
|
803
|
+
cwd,
|
|
804
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
805
|
+
});
|
|
806
|
+
if (!recoveredContractId) {
|
|
807
|
+
throw error;
|
|
808
|
+
}
|
|
809
|
+
contractId = recoveredContractId;
|
|
810
|
+
output = [
|
|
811
|
+
error.hint ?? "",
|
|
812
|
+
"Caatinga recovered the contract ID from the on-chain deploy transaction.",
|
|
813
|
+
`Contract ID: ${contractId}`
|
|
814
|
+
].filter(Boolean).join("\n");
|
|
815
|
+
}
|
|
816
|
+
const wasmHash = await hashWasm(wasmPath);
|
|
627
817
|
const dependencyGraph = buildDependencyGraph(options.config.contracts);
|
|
628
818
|
const dependencies = options.dependencies ?? contract.config.dependsOn;
|
|
629
819
|
const nextArtifacts = updateArtifact(
|
|
@@ -643,12 +833,13 @@ ${result.stderr}`;
|
|
|
643
833
|
);
|
|
644
834
|
const artifactsPath = await writeArtifacts(nextArtifacts, cwd);
|
|
645
835
|
return {
|
|
646
|
-
contract,
|
|
836
|
+
contract: contractWithWasm,
|
|
647
837
|
network,
|
|
648
838
|
contractId,
|
|
649
839
|
artifactsPath,
|
|
650
840
|
output,
|
|
651
|
-
skipped: false
|
|
841
|
+
skipped: false,
|
|
842
|
+
staleWasmWarning
|
|
652
843
|
};
|
|
653
844
|
}
|
|
654
845
|
|
|
@@ -703,6 +894,53 @@ function resolveDeployOrder(input) {
|
|
|
703
894
|
}
|
|
704
895
|
}
|
|
705
896
|
|
|
897
|
+
// src/contracts/verify-dependency-contract.ts
|
|
898
|
+
async function verifyDependencyContract(options) {
|
|
899
|
+
try {
|
|
900
|
+
await runCommand("stellar", [
|
|
901
|
+
"contract",
|
|
902
|
+
"info",
|
|
903
|
+
"interface",
|
|
904
|
+
"--contract-id",
|
|
905
|
+
options.contractId,
|
|
906
|
+
...buildStellarNetworkArgs(options.network)
|
|
907
|
+
], {
|
|
908
|
+
cwd: options.cwd,
|
|
909
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
910
|
+
failureCode: CaatingaErrorCode.DEPENDENCY_CONTRACT_NOT_FOUND
|
|
911
|
+
});
|
|
912
|
+
} catch (error) {
|
|
913
|
+
if (error instanceof CaatingaError && error.code === CaatingaErrorCode.DEPENDENCY_CONTRACT_NOT_FOUND) {
|
|
914
|
+
throw new CaatingaError(
|
|
915
|
+
`Dependency "${options.dependencyName}" is not deployed on "${options.network.name}" (contract ID ${options.contractId}).`,
|
|
916
|
+
CaatingaErrorCode.DEPENDENCY_CONTRACT_NOT_FOUND,
|
|
917
|
+
"Deploy the dependency on this network, fix caatinga.artifacts.json, or omit --verify-deps.",
|
|
918
|
+
error.cause
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
throw error;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
async function verifyDependencyContracts(options) {
|
|
925
|
+
for (const dependencyName of options.dependencies) {
|
|
926
|
+
const contractArtifact = options.artifacts.networks[options.network.name]?.contracts[dependencyName];
|
|
927
|
+
if (!contractArtifact?.contractId) {
|
|
928
|
+
throw new CaatingaError(
|
|
929
|
+
`No dependency artifact found for "${dependencyName}" on "${options.network.name}".`,
|
|
930
|
+
CaatingaErrorCode.CONTRACT_DEPENDENCY_ARTIFACT_NOT_FOUND,
|
|
931
|
+
"Deploy the dependency first or run deploy without --no-deps."
|
|
932
|
+
);
|
|
933
|
+
}
|
|
934
|
+
await verifyDependencyContract({
|
|
935
|
+
dependencyName,
|
|
936
|
+
contractId: contractArtifact.contractId,
|
|
937
|
+
network: options.network,
|
|
938
|
+
cwd: options.cwd,
|
|
939
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
|
|
706
944
|
// src/contracts/deploy-contract-graph.ts
|
|
707
945
|
async function deployContractGraph(options) {
|
|
708
946
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -713,17 +951,33 @@ async function deployContractGraph(options) {
|
|
|
713
951
|
includeDependencies: options.includeDependencies
|
|
714
952
|
});
|
|
715
953
|
const deployedContracts = [];
|
|
954
|
+
const skippedContracts = [];
|
|
955
|
+
const staleWasmWarnings = [];
|
|
716
956
|
for (const contractName of order) {
|
|
717
957
|
const artifacts = await readArtifacts(cwd);
|
|
718
958
|
const existing = artifacts.networks[network.name]?.contracts[contractName];
|
|
719
959
|
const contractConfig = options.config.contracts[contractName];
|
|
960
|
+
if (options.verifyDeps && contractConfig.dependsOn.length > 0) {
|
|
961
|
+
await verifyDependencyContracts({
|
|
962
|
+
dependencies: contractConfig.dependsOn,
|
|
963
|
+
artifacts,
|
|
964
|
+
network,
|
|
965
|
+
cwd,
|
|
966
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
967
|
+
});
|
|
968
|
+
}
|
|
720
969
|
const resolvedDeployArgs = resolveDeployArgs({
|
|
721
970
|
deployArgs: contractConfig.deployArgs,
|
|
722
971
|
artifacts,
|
|
723
972
|
network: network.name
|
|
724
973
|
});
|
|
725
974
|
if (existing?.contractId && !options.force) {
|
|
726
|
-
|
|
975
|
+
skippedContracts.push({
|
|
976
|
+
name: contractName,
|
|
977
|
+
contractId: existing.contractId,
|
|
978
|
+
network: network.name,
|
|
979
|
+
reason: "already-deployed"
|
|
980
|
+
});
|
|
727
981
|
continue;
|
|
728
982
|
}
|
|
729
983
|
const result = await deployContract({
|
|
@@ -734,20 +988,38 @@ async function deployContractGraph(options) {
|
|
|
734
988
|
cwd,
|
|
735
989
|
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
736
990
|
force: options.force,
|
|
991
|
+
checkStaleWasm: options.checkStaleWasm,
|
|
737
992
|
resolvedDeployArgs,
|
|
738
993
|
dependencies: contractConfig.dependsOn
|
|
739
994
|
});
|
|
740
|
-
|
|
995
|
+
if (result.staleWasmWarning) {
|
|
996
|
+
staleWasmWarnings.push({
|
|
997
|
+
contract: contractName,
|
|
998
|
+
message: result.staleWasmWarning
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
if (result.skipped) {
|
|
1002
|
+
skippedContracts.push({
|
|
1003
|
+
name: contractName,
|
|
1004
|
+
contractId: result.contractId,
|
|
1005
|
+
network: network.name,
|
|
1006
|
+
reason: "already-deployed"
|
|
1007
|
+
});
|
|
1008
|
+
} else {
|
|
1009
|
+
deployedContracts.push({ name: contractName, contractId: result.contractId });
|
|
1010
|
+
}
|
|
741
1011
|
}
|
|
742
1012
|
return {
|
|
743
1013
|
network,
|
|
744
|
-
deployedContracts
|
|
1014
|
+
deployedContracts,
|
|
1015
|
+
skippedContracts,
|
|
1016
|
+
staleWasmWarnings
|
|
745
1017
|
};
|
|
746
1018
|
}
|
|
747
1019
|
|
|
748
1020
|
// src/contracts/generate-bindings.ts
|
|
749
1021
|
import { mkdir as mkdir2 } from "fs/promises";
|
|
750
|
-
import
|
|
1022
|
+
import path7 from "path";
|
|
751
1023
|
async function generateBindings(options) {
|
|
752
1024
|
const cwd = options.cwd ?? process.cwd();
|
|
753
1025
|
const network = resolveNetwork(options.config, options.networkName);
|
|
@@ -763,7 +1035,7 @@ async function generateBindings(options) {
|
|
|
763
1035
|
await checkBinary("stellar", "Install Stellar CLI before running caatinga generate.", {
|
|
764
1036
|
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
765
1037
|
});
|
|
766
|
-
const outputDir =
|
|
1038
|
+
const outputDir = path7.resolve(cwd, options.config.frontend.bindingsOutput, options.contractName);
|
|
767
1039
|
await mkdir2(outputDir, { recursive: true });
|
|
768
1040
|
const result = await runCommand("stellar", [
|
|
769
1041
|
"contract",
|
|
@@ -774,10 +1046,7 @@ async function generateBindings(options) {
|
|
|
774
1046
|
"--output-dir",
|
|
775
1047
|
outputDir,
|
|
776
1048
|
"--overwrite",
|
|
777
|
-
|
|
778
|
-
network.config.rpcUrl,
|
|
779
|
-
"--network-passphrase",
|
|
780
|
-
network.config.networkPassphrase
|
|
1049
|
+
...buildStellarNetworkArgs(network)
|
|
781
1050
|
], {
|
|
782
1051
|
cwd,
|
|
783
1052
|
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
@@ -792,6 +1061,7 @@ async function generateBindings(options) {
|
|
|
792
1061
|
}
|
|
793
1062
|
|
|
794
1063
|
// src/contracts/invoke-contract.ts
|
|
1064
|
+
var INVOKE_SIGNING_FAILURE_REGEX = /xdr processing error: xdr value invalid/i;
|
|
795
1065
|
function parseInvokeTarget(target) {
|
|
796
1066
|
const [contractName, method, extra] = target.split(".");
|
|
797
1067
|
if (!contractName || !method || extra) {
|
|
@@ -820,25 +1090,43 @@ async function invokeContract(options) {
|
|
|
820
1090
|
await checkBinary("stellar", "Install Stellar CLI before running caatinga invoke.", {
|
|
821
1091
|
allowUntestedStellarCli: options.allowUntestedStellarCli
|
|
822
1092
|
});
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
"
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
})
|
|
1093
|
+
let result;
|
|
1094
|
+
try {
|
|
1095
|
+
result = await runCommand("stellar", [
|
|
1096
|
+
"contract",
|
|
1097
|
+
"invoke",
|
|
1098
|
+
"--id",
|
|
1099
|
+
contractArtifact.contractId,
|
|
1100
|
+
"--source-account",
|
|
1101
|
+
source,
|
|
1102
|
+
...buildStellarNetworkArgs(network),
|
|
1103
|
+
"--",
|
|
1104
|
+
target.method,
|
|
1105
|
+
...options.args ?? []
|
|
1106
|
+
], {
|
|
1107
|
+
cwd,
|
|
1108
|
+
allowUntestedStellarCli: options.allowUntestedStellarCli,
|
|
1109
|
+
failureCode: CaatingaErrorCode.INVOKE_FAILED
|
|
1110
|
+
});
|
|
1111
|
+
} catch (error) {
|
|
1112
|
+
if (error instanceof CaatingaError && error.code === CaatingaErrorCode.INVOKE_FAILED && INVOKE_SIGNING_FAILURE_REGEX.test(`${error.message}
|
|
1113
|
+
${error.hint ?? ""}`)) {
|
|
1114
|
+
throw new CaatingaError(
|
|
1115
|
+
error.message,
|
|
1116
|
+
error.code,
|
|
1117
|
+
[
|
|
1118
|
+
"Stellar CLI could not sign the invoke transaction (xdr value invalid).",
|
|
1119
|
+
"Stellar CLI 22.x has a known invoke signing bug; upgrade to 23.0.0 or newer (25.2.0 recommended).",
|
|
1120
|
+
" stellar --version",
|
|
1121
|
+
"Then retry with a funded identity, for example:",
|
|
1122
|
+
" stellar keys generate alice --fund --network testnet",
|
|
1123
|
+
" npx caatinga invoke counter.increment --network testnet --source alice"
|
|
1124
|
+
].join("\n"),
|
|
1125
|
+
error
|
|
1126
|
+
);
|
|
1127
|
+
}
|
|
1128
|
+
throw error;
|
|
1129
|
+
}
|
|
842
1130
|
return {
|
|
843
1131
|
target,
|
|
844
1132
|
network,
|
|
@@ -847,8 +1135,8 @@ async function invokeContract(options) {
|
|
|
847
1135
|
}
|
|
848
1136
|
|
|
849
1137
|
// src/templates/create-project-from-template.ts
|
|
850
|
-
import { cp, mkdir as mkdir3, readFile as readFile3, readdir, stat, writeFile as writeFile2 } from "fs/promises";
|
|
851
|
-
import
|
|
1138
|
+
import { cp, mkdir as mkdir3, readFile as readFile3, readdir as readdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
1139
|
+
import path8 from "path";
|
|
852
1140
|
import { z as z6 } from "zod";
|
|
853
1141
|
|
|
854
1142
|
// src/templates/template-manifest.schema.ts
|
|
@@ -876,16 +1164,52 @@ var TemplateManifestSchema = z5.object({
|
|
|
876
1164
|
artifacts: z5.string().default("caatinga.artifacts.json")
|
|
877
1165
|
})
|
|
878
1166
|
});
|
|
1167
|
+
function defaultCompatibleCoreRange(coreVersion = CAATINGA_CORE_VERSION) {
|
|
1168
|
+
const version = semver2.valid(semver2.coerce(coreVersion));
|
|
1169
|
+
if (!version) {
|
|
1170
|
+
throw new Error(`Invalid core version: ${coreVersion}`);
|
|
1171
|
+
}
|
|
1172
|
+
return `^${version}`;
|
|
1173
|
+
}
|
|
879
1174
|
function isCoreVersionCompatible(range, coreVersion = CAATINGA_CORE_VERSION) {
|
|
880
1175
|
return semver2.satisfies(coreVersion, range);
|
|
881
1176
|
}
|
|
1177
|
+
function getTemplateCompatibilityIssue(manifest, coreVersion = CAATINGA_CORE_VERSION) {
|
|
1178
|
+
if (manifest.caatinga.templateVersion !== CURRENT_TEMPLATE_VERSION) {
|
|
1179
|
+
return {
|
|
1180
|
+
kind: "template-version",
|
|
1181
|
+
expected: CURRENT_TEMPLATE_VERSION,
|
|
1182
|
+
actual: manifest.caatinga.templateVersion
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
if (!isCoreVersionCompatible(manifest.caatinga.compatibleCore, coreVersion)) {
|
|
1186
|
+
return {
|
|
1187
|
+
kind: "core-range",
|
|
1188
|
+
requiredRange: manifest.caatinga.compatibleCore,
|
|
1189
|
+
runningVersion: coreVersion
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
return null;
|
|
1193
|
+
}
|
|
1194
|
+
function formatTemplateCompatibilityMessage(issue) {
|
|
1195
|
+
if (issue.kind === "template-version") {
|
|
1196
|
+
return `Template manifest version ${issue.actual} is not supported; Caatinga requires templateVersion ${issue.expected}.`;
|
|
1197
|
+
}
|
|
1198
|
+
return `Template requires @caatinga/core ${issue.requiredRange} but running ${issue.runningVersion}.`;
|
|
1199
|
+
}
|
|
1200
|
+
function formatTemplateCompatibilityHint(issue) {
|
|
1201
|
+
if (issue.kind === "template-version") {
|
|
1202
|
+
return "Use a template built for this Caatinga release or upgrade Caatinga.";
|
|
1203
|
+
}
|
|
1204
|
+
return `Use a template with compatibleCore ${defaultCompatibleCoreRange(issue.runningVersion)} or install a matching Caatinga version.`;
|
|
1205
|
+
}
|
|
882
1206
|
|
|
883
1207
|
// src/templates/create-project-from-template.ts
|
|
884
1208
|
async function createProjectFromTemplate(options) {
|
|
885
|
-
const targetDir =
|
|
886
|
-
const templateDir =
|
|
1209
|
+
const targetDir = path8.resolve(options.targetDir);
|
|
1210
|
+
const templateDir = path8.resolve(options.templateDir);
|
|
887
1211
|
try {
|
|
888
|
-
await
|
|
1212
|
+
await stat2(templateDir);
|
|
889
1213
|
} catch {
|
|
890
1214
|
throw new CaatingaError(
|
|
891
1215
|
`Template directory was not found: ${templateDir}`,
|
|
@@ -905,22 +1229,16 @@ async function createProjectFromTemplate(options) {
|
|
|
905
1229
|
return { targetDir, template: manifest };
|
|
906
1230
|
}
|
|
907
1231
|
async function readTemplateManifest(templateDir) {
|
|
908
|
-
const manifestPath =
|
|
1232
|
+
const manifestPath = path8.join(templateDir, "caatinga.template.json");
|
|
909
1233
|
try {
|
|
910
1234
|
const rawManifest = await readFile3(manifestPath, "utf8");
|
|
911
1235
|
const manifest = TemplateManifestSchema.parse(JSON.parse(rawManifest));
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
"Template is not compatible with this Caatinga version.",
|
|
915
|
-
CaatingaErrorCode.TEMPLATE_INCOMPATIBLE,
|
|
916
|
-
"Use a compatible template version or upgrade Caatinga."
|
|
917
|
-
);
|
|
918
|
-
}
|
|
919
|
-
if (!isCoreVersionCompatible(manifest.caatinga.compatibleCore)) {
|
|
1236
|
+
const compatibilityIssue = getTemplateCompatibilityIssue(manifest);
|
|
1237
|
+
if (compatibilityIssue) {
|
|
920
1238
|
throw new CaatingaError(
|
|
921
|
-
|
|
1239
|
+
formatTemplateCompatibilityMessage(compatibilityIssue),
|
|
922
1240
|
CaatingaErrorCode.TEMPLATE_INCOMPATIBLE,
|
|
923
|
-
|
|
1241
|
+
formatTemplateCompatibilityHint(compatibilityIssue)
|
|
924
1242
|
);
|
|
925
1243
|
}
|
|
926
1244
|
return manifest;
|
|
@@ -946,10 +1264,10 @@ async function readTemplateManifest(templateDir) {
|
|
|
946
1264
|
}
|
|
947
1265
|
}
|
|
948
1266
|
async function replaceTemplateVariables(dir, projectName) {
|
|
949
|
-
const entries = await
|
|
1267
|
+
const entries = await readdir2(dir);
|
|
950
1268
|
await Promise.all(entries.map(async (entry) => {
|
|
951
|
-
const entryPath =
|
|
952
|
-
const entryStat = await
|
|
1269
|
+
const entryPath = path8.join(dir, entry);
|
|
1270
|
+
const entryStat = await stat2(entryPath);
|
|
953
1271
|
if (entryStat.isDirectory()) {
|
|
954
1272
|
await replaceTemplateVariables(entryPath, projectName);
|
|
955
1273
|
return;
|
|
@@ -971,7 +1289,7 @@ function isTextTemplateFile(filePath) {
|
|
|
971
1289
|
".tsx",
|
|
972
1290
|
".css",
|
|
973
1291
|
".html"
|
|
974
|
-
].includes(
|
|
1292
|
+
].includes(path8.extname(filePath));
|
|
975
1293
|
}
|
|
976
1294
|
|
|
977
1295
|
// src/ci/is-transient-testnet-smoke-failure.ts
|
|
@@ -1029,5 +1347,6 @@ export {
|
|
|
1029
1347
|
runCommand,
|
|
1030
1348
|
toCaatingaError,
|
|
1031
1349
|
updateArtifact,
|
|
1350
|
+
validateSourceShape,
|
|
1032
1351
|
writeArtifacts
|
|
1033
1352
|
};
|