@true-sight/model-cli 1.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/dist/build/assemble-manifest.d.ts +2 -0
- package/dist/build/assemble-manifest.js +11 -0
- package/dist/build/compile-entry.d.ts +5 -0
- package/dist/build/compile-entry.js +79 -0
- package/dist/build/load-entry-runner.d.ts +1 -0
- package/dist/build/load-entry-runner.js +46 -0
- package/dist/build/load-entry.d.ts +5 -0
- package/dist/build/load-entry.js +62 -0
- package/dist/build/write-manifest.d.ts +2 -0
- package/dist/build/write-manifest.js +52 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +45 -0
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.js +29 -0
- package/dist/commands/sync.d.ts +7 -0
- package/dist/commands/sync.js +51 -0
- package/dist/commands/validate.d.ts +5 -0
- package/dist/commands/validate.js +26 -0
- package/dist/sync/post-manifest.d.ts +5 -0
- package/dist/sync/post-manifest.js +15 -0
- package/dist/sync/sign-body.d.ts +1 -0
- package/dist/sync/sign-body.js +8 -0
- package/dist/util/print-errors.d.ts +2 -0
- package/dist/util/print-errors.js +9 -0
- package/package.json +49 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.assembleManifest = assembleManifest;
|
|
4
|
+
const model_schema_1 = require("@true-sight/model-schema");
|
|
5
|
+
function assembleManifest(models) {
|
|
6
|
+
return {
|
|
7
|
+
schemaVersion: model_schema_1.SCHEMA_VERSION,
|
|
8
|
+
generatedAt: new Date().toISOString(),
|
|
9
|
+
models,
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileEntryIfNeeded = compileEntryIfNeeded;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_os_1 = require("node:os");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
function findProjectTsconfig(absoluteEntry) {
|
|
9
|
+
let dir = (0, node_path_1.dirname)(absoluteEntry);
|
|
10
|
+
while (dir !== (0, node_path_1.dirname)(dir)) {
|
|
11
|
+
const candidate = (0, node_path_1.join)(dir, 'tsconfig.json');
|
|
12
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
13
|
+
if (absoluteEntry.includes(`${(0, node_path_1.join)('packages', 'model-cli', 'test', 'fixtures')}`)) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return candidate;
|
|
17
|
+
}
|
|
18
|
+
dir = (0, node_path_1.dirname)(dir);
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function writeFixtureTsconfig(absoluteEntry, tempDir) {
|
|
23
|
+
const entryDir = (0, node_path_1.dirname)(absoluteEntry);
|
|
24
|
+
const compileConfigPath = (0, node_path_1.join)(tempDir, 'compile-tsconfig.json');
|
|
25
|
+
(0, node_fs_1.writeFileSync)(compileConfigPath, JSON.stringify({
|
|
26
|
+
compilerOptions: {
|
|
27
|
+
target: 'ES2023',
|
|
28
|
+
module: 'nodenext',
|
|
29
|
+
moduleResolution: 'nodenext',
|
|
30
|
+
strict: false,
|
|
31
|
+
experimentalDecorators: true,
|
|
32
|
+
emitDecoratorMetadata: true,
|
|
33
|
+
outDir: tempDir,
|
|
34
|
+
rootDir: entryDir,
|
|
35
|
+
},
|
|
36
|
+
include: [absoluteEntry],
|
|
37
|
+
}));
|
|
38
|
+
return compileConfigPath;
|
|
39
|
+
}
|
|
40
|
+
function readRootDir(tsconfigPath, absoluteEntry) {
|
|
41
|
+
const config = JSON.parse((0, node_fs_1.readFileSync)(tsconfigPath, 'utf8'));
|
|
42
|
+
if (config.compilerOptions?.rootDir) {
|
|
43
|
+
return (0, node_path_1.resolve)((0, node_path_1.dirname)(tsconfigPath), config.compilerOptions.rootDir);
|
|
44
|
+
}
|
|
45
|
+
return (0, node_path_1.dirname)(absoluteEntry);
|
|
46
|
+
}
|
|
47
|
+
async function compileEntryIfNeeded(absoluteEntry) {
|
|
48
|
+
if (!absoluteEntry.endsWith('.ts')) {
|
|
49
|
+
return { jsPath: absoluteEntry, cleanup: () => undefined };
|
|
50
|
+
}
|
|
51
|
+
const tempDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'model-cli-compile-'));
|
|
52
|
+
const projectTsconfig = findProjectTsconfig(absoluteEntry);
|
|
53
|
+
const compileConfigPath = projectTsconfig
|
|
54
|
+
? projectTsconfig
|
|
55
|
+
: writeFixtureTsconfig(absoluteEntry, tempDir);
|
|
56
|
+
const tscArgs = projectTsconfig
|
|
57
|
+
? ['tsc', '-p', compileConfigPath, '--outDir', tempDir, '--noCheck']
|
|
58
|
+
: ['tsc', '-p', compileConfigPath, '--noCheck'];
|
|
59
|
+
const result = (0, node_child_process_1.spawnSync)('npx', tscArgs, {
|
|
60
|
+
encoding: 'utf8',
|
|
61
|
+
cwd: projectTsconfig ? (0, node_path_1.dirname)(projectTsconfig) : undefined,
|
|
62
|
+
});
|
|
63
|
+
if (result.status !== 0) {
|
|
64
|
+
(0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
|
|
65
|
+
const message = (result.stderr || result.stdout || 'tsc failed').trim();
|
|
66
|
+
throw new Error(message);
|
|
67
|
+
}
|
|
68
|
+
const rootDir = readRootDir(projectTsconfig ?? compileConfigPath, absoluteEntry);
|
|
69
|
+
const relJs = (0, node_path_1.relative)(rootDir, absoluteEntry).replace(/\.ts$/, '.js');
|
|
70
|
+
const jsPath = (0, node_path_1.join)(tempDir, relJs);
|
|
71
|
+
if (!(0, node_fs_1.existsSync)(jsPath)) {
|
|
72
|
+
(0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
|
|
73
|
+
throw new Error(`Compiled entry not found: ${jsPath}`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
jsPath,
|
|
77
|
+
cleanup: () => (0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true }),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
require("reflect-metadata");
|
|
4
|
+
const model_schema_1 = require("@true-sight/model-schema");
|
|
5
|
+
const node_module_1 = require("node:module");
|
|
6
|
+
const node_url_1 = require("node:url");
|
|
7
|
+
const requireEntry = (0, node_module_1.createRequire)(__filename);
|
|
8
|
+
function isModelConstructor(value) {
|
|
9
|
+
return typeof value === 'function';
|
|
10
|
+
}
|
|
11
|
+
async function loadEntry(entryPath) {
|
|
12
|
+
if (entryPath.endsWith('.cjs')) {
|
|
13
|
+
return requireEntry(entryPath);
|
|
14
|
+
}
|
|
15
|
+
return (await import((0, node_url_1.pathToFileURL)(entryPath).href));
|
|
16
|
+
}
|
|
17
|
+
async function main() {
|
|
18
|
+
const entryPath = process.argv[2];
|
|
19
|
+
if (!entryPath) {
|
|
20
|
+
console.error('Missing entry path');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const loaded = await loadEntry(entryPath);
|
|
25
|
+
const models = loaded.models ?? loaded.default?.models;
|
|
26
|
+
if (!Array.isArray(models)) {
|
|
27
|
+
console.error('Entry must export `models` array of model classes');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
if (!models.every(isModelConstructor)) {
|
|
31
|
+
console.error('Entry must export model class constructors in `models`');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
process.stdout.write(JSON.stringify((0, model_schema_1.compileModels)(models)));
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
38
|
+
console.error(message);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
main().catch((error) => {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
44
|
+
console.error(message);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoadEntryError = void 0;
|
|
4
|
+
exports.loadModelsFromEntry = loadModelsFromEntry;
|
|
5
|
+
const node_child_process_1 = require("node:child_process");
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const compile_entry_js_1 = require("./compile-entry.js");
|
|
9
|
+
class LoadEntryError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'LoadEntryError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.LoadEntryError = LoadEntryError;
|
|
16
|
+
function resolveNodePath(cwd) {
|
|
17
|
+
const candidates = [];
|
|
18
|
+
let dir = cwd;
|
|
19
|
+
while (dir !== (0, node_path_1.dirname)(dir)) {
|
|
20
|
+
candidates.push((0, node_path_1.join)(dir, 'node_modules'));
|
|
21
|
+
dir = (0, node_path_1.dirname)(dir);
|
|
22
|
+
}
|
|
23
|
+
return candidates.filter(node_fs_1.existsSync).join(process.platform === 'win32' ? ';' : ':');
|
|
24
|
+
}
|
|
25
|
+
function resolveRunnerPath() {
|
|
26
|
+
const adjacent = (0, node_path_1.resolve)((0, node_path_1.dirname)(__filename), 'load-entry-runner.js');
|
|
27
|
+
if ((0, node_fs_1.existsSync)(adjacent)) {
|
|
28
|
+
return adjacent;
|
|
29
|
+
}
|
|
30
|
+
const packageDist = (0, node_path_1.resolve)((0, node_path_1.dirname)(__filename), '../../dist/build/load-entry-runner.js');
|
|
31
|
+
if ((0, node_fs_1.existsSync)(packageDist)) {
|
|
32
|
+
return packageDist;
|
|
33
|
+
}
|
|
34
|
+
throw new LoadEntryError('Run npm run build -w @true-sight/model-cli first');
|
|
35
|
+
}
|
|
36
|
+
async function loadModelsFromEntry(entryPath, cwd) {
|
|
37
|
+
const absoluteEntry = (0, node_path_1.resolve)(cwd, entryPath);
|
|
38
|
+
if (!(0, node_fs_1.existsSync)(absoluteEntry)) {
|
|
39
|
+
throw new LoadEntryError(`Entry file not found: ${entryPath}`);
|
|
40
|
+
}
|
|
41
|
+
const { jsPath, cleanup } = await (0, compile_entry_js_1.compileEntryIfNeeded)(absoluteEntry);
|
|
42
|
+
const runnerPath = resolveRunnerPath();
|
|
43
|
+
try {
|
|
44
|
+
const result = (0, node_child_process_1.spawnSync)(process.execPath, [runnerPath, jsPath], {
|
|
45
|
+
encoding: 'utf8',
|
|
46
|
+
cwd,
|
|
47
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
48
|
+
env: {
|
|
49
|
+
...process.env,
|
|
50
|
+
NODE_PATH: resolveNodePath(cwd),
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
if (result.status !== 0) {
|
|
54
|
+
const message = (result.stderr || result.stdout || 'Failed to load entry').trim();
|
|
55
|
+
throw new LoadEntryError(message);
|
|
56
|
+
}
|
|
57
|
+
return JSON.parse(result.stdout);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
cleanup();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.writeManifest = writeManifest;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const MANIFEST_KEY_ORDER = [
|
|
7
|
+
'schemaVersion',
|
|
8
|
+
'generatedAt',
|
|
9
|
+
'sourceCommit',
|
|
10
|
+
'models',
|
|
11
|
+
];
|
|
12
|
+
const MODEL_KEY_ORDER = ['name', 'label', 'connectionName', 'explores'];
|
|
13
|
+
const EXPLORE_KEY_ORDER = ['name', 'label', 'from', 'joins', 'views'];
|
|
14
|
+
const VIEW_KEY_ORDER = [
|
|
15
|
+
'name',
|
|
16
|
+
'label',
|
|
17
|
+
'sql',
|
|
18
|
+
'dimensions',
|
|
19
|
+
'measurements',
|
|
20
|
+
];
|
|
21
|
+
function orderKeys(value, keyOrder) {
|
|
22
|
+
const ordered = {};
|
|
23
|
+
for (const key of keyOrder) {
|
|
24
|
+
if (key in value) {
|
|
25
|
+
ordered[key] = value[key];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
for (const key of Object.keys(value)) {
|
|
29
|
+
if (!(key in ordered)) {
|
|
30
|
+
ordered[key] = value[key];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return ordered;
|
|
34
|
+
}
|
|
35
|
+
function stableManifest(manifest) {
|
|
36
|
+
return orderKeys({
|
|
37
|
+
...manifest,
|
|
38
|
+
models: manifest.models.map((model) => orderKeys({
|
|
39
|
+
...model,
|
|
40
|
+
explores: model.explores.map((explore) => orderKeys({
|
|
41
|
+
...explore,
|
|
42
|
+
views: explore.views.map((view) => orderKeys({ ...view }, VIEW_KEY_ORDER)),
|
|
43
|
+
}, EXPLORE_KEY_ORDER)),
|
|
44
|
+
}, MODEL_KEY_ORDER)),
|
|
45
|
+
}, MANIFEST_KEY_ORDER);
|
|
46
|
+
}
|
|
47
|
+
function writeManifest(manifest, outPath, cwd) {
|
|
48
|
+
const absoluteOut = (0, node_path_1.resolve)(cwd, outPath);
|
|
49
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(absoluteOut), { recursive: true });
|
|
50
|
+
const json = `${JSON.stringify(stableManifest(manifest), null, 2)}\n`;
|
|
51
|
+
(0, node_fs_1.writeFileSync)(absoluteOut, json, 'utf8');
|
|
52
|
+
}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const build_js_1 = require("./commands/build.js");
|
|
6
|
+
const sync_js_1 = require("./commands/sync.js");
|
|
7
|
+
const validate_js_1 = require("./commands/validate.js");
|
|
8
|
+
const program = new commander_1.Command();
|
|
9
|
+
program.name('truesight-model').description('True Sight model manifest CLI');
|
|
10
|
+
program
|
|
11
|
+
.command('build')
|
|
12
|
+
.description('Compile TS model definitions into manifest JSON')
|
|
13
|
+
.argument('[entry]', 'entry module path', 'src/index.ts')
|
|
14
|
+
.option('--out <path>', 'output manifest path', 'true-sight/manifest.json')
|
|
15
|
+
.action(async (entry, options) => {
|
|
16
|
+
const exitCode = await (0, build_js_1.runBuild)({ entry, out: options.out });
|
|
17
|
+
process.exit(exitCode);
|
|
18
|
+
});
|
|
19
|
+
program
|
|
20
|
+
.command('validate')
|
|
21
|
+
.description('Validate a pre-built manifest JSON file')
|
|
22
|
+
.argument('[path]', 'manifest path', 'true-sight/manifest.json')
|
|
23
|
+
.action(async (path) => {
|
|
24
|
+
const exitCode = await (0, validate_js_1.runValidate)({ path });
|
|
25
|
+
process.exit(exitCode);
|
|
26
|
+
});
|
|
27
|
+
program
|
|
28
|
+
.command('sync')
|
|
29
|
+
.description('Upload local manifest JSON to True Sight')
|
|
30
|
+
.argument('[path]', 'manifest path', 'true-sight/manifest.json')
|
|
31
|
+
.option('--url <url>', 'sync endpoint URL')
|
|
32
|
+
.option('--secret <secret>', 'HMAC signing secret')
|
|
33
|
+
.action(async (path, options) => {
|
|
34
|
+
const exitCode = await (0, sync_js_1.runSync)({
|
|
35
|
+
path,
|
|
36
|
+
url: options.url,
|
|
37
|
+
secret: options.secret,
|
|
38
|
+
});
|
|
39
|
+
process.exit(exitCode);
|
|
40
|
+
});
|
|
41
|
+
program.parseAsync(process.argv).catch((error) => {
|
|
42
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43
|
+
console.error(message);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runBuild = runBuild;
|
|
4
|
+
const model_schema_1 = require("@true-sight/model-schema");
|
|
5
|
+
const assemble_manifest_js_1 = require("../build/assemble-manifest.js");
|
|
6
|
+
const load_entry_js_1 = require("../build/load-entry.js");
|
|
7
|
+
const write_manifest_js_1 = require("../build/write-manifest.js");
|
|
8
|
+
const print_errors_js_1 = require("../util/print-errors.js");
|
|
9
|
+
async function runBuild(options) {
|
|
10
|
+
const cwd = options.cwd ?? process.cwd();
|
|
11
|
+
try {
|
|
12
|
+
const models = await (0, load_entry_js_1.loadModelsFromEntry)(options.entry, cwd);
|
|
13
|
+
const manifest = (0, assemble_manifest_js_1.assembleManifest)(models);
|
|
14
|
+
const validation = (0, model_schema_1.validateManifest)(manifest);
|
|
15
|
+
if (!validation.ok) {
|
|
16
|
+
(0, print_errors_js_1.printValidationErrors)(validation.errors);
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
(0, write_manifest_js_1.writeManifest)(manifest, options.out, cwd);
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (error instanceof load_entry_js_1.LoadEntryError) {
|
|
24
|
+
console.error(error.message);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runSync = runSync;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const dotenv_1 = require("dotenv");
|
|
7
|
+
const model_schema_1 = require("@true-sight/model-schema");
|
|
8
|
+
const post_manifest_js_1 = require("../sync/post-manifest.js");
|
|
9
|
+
const sign_body_js_1 = require("../sync/sign-body.js");
|
|
10
|
+
const print_errors_js_1 = require("../util/print-errors.js");
|
|
11
|
+
async function runSync(options) {
|
|
12
|
+
const cwd = options.cwd ?? process.cwd();
|
|
13
|
+
(0, dotenv_1.config)({ path: (0, node_path_1.resolve)(cwd, '.env') });
|
|
14
|
+
const url = options.url ?? process.env.TRUESIGHT_SYNC_URL;
|
|
15
|
+
const secret = options.secret ?? process.env.TRUESIGHT_SYNC_SECRET;
|
|
16
|
+
if (!url || !secret) {
|
|
17
|
+
console.error('Sync requires TRUESIGHT_SYNC_URL and TRUESIGHT_SYNC_SECRET (or --url / --secret flags)');
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
const absolutePath = (0, node_path_1.resolve)(cwd, options.path);
|
|
21
|
+
const rawBody = (0, node_fs_1.readFileSync)(absolutePath);
|
|
22
|
+
let parsed;
|
|
23
|
+
try {
|
|
24
|
+
parsed = JSON.parse(rawBody.toString('utf8'));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
console.error(`Failed to read manifest at ${options.path}: ${message}`);
|
|
29
|
+
return 1;
|
|
30
|
+
}
|
|
31
|
+
const validation = (0, model_schema_1.validateManifest)(parsed);
|
|
32
|
+
if (!validation.ok) {
|
|
33
|
+
(0, print_errors_js_1.printValidationErrors)(validation.errors);
|
|
34
|
+
return 1;
|
|
35
|
+
}
|
|
36
|
+
const signatureHeader = (0, sign_body_js_1.signManifestBody)(rawBody, secret);
|
|
37
|
+
try {
|
|
38
|
+
const response = await (0, post_manifest_js_1.postManifest)(url, rawBody, signatureHeader);
|
|
39
|
+
if (response.status < 200 || response.status >= 300) {
|
|
40
|
+
console.error(`Sync failed (${response.status}): ${response.body}`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
console.log(`Sync succeeded (${response.status})`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
48
|
+
console.error(`Sync request failed: ${message}`);
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runValidate = runValidate;
|
|
4
|
+
const node_fs_1 = require("node:fs");
|
|
5
|
+
const node_path_1 = require("node:path");
|
|
6
|
+
const model_schema_1 = require("@true-sight/model-schema");
|
|
7
|
+
const print_errors_js_1 = require("../util/print-errors.js");
|
|
8
|
+
async function runValidate(options) {
|
|
9
|
+
const cwd = options.cwd ?? process.cwd();
|
|
10
|
+
const absolutePath = (0, node_path_1.resolve)(cwd, options.path);
|
|
11
|
+
let parsed;
|
|
12
|
+
try {
|
|
13
|
+
parsed = JSON.parse((0, node_fs_1.readFileSync)(absolutePath, 'utf8'));
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
console.error(`Failed to read manifest at ${options.path}: ${message}`);
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
const validation = (0, model_schema_1.validateManifest)(parsed);
|
|
21
|
+
if (!validation.ok) {
|
|
22
|
+
(0, print_errors_js_1.printValidationErrors)(validation.errors);
|
|
23
|
+
return 1;
|
|
24
|
+
}
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.postManifest = postManifest;
|
|
4
|
+
async function postManifest(url, rawBody, signatureHeader) {
|
|
5
|
+
const response = await fetch(url, {
|
|
6
|
+
method: 'POST',
|
|
7
|
+
headers: {
|
|
8
|
+
'Content-Type': 'application/json',
|
|
9
|
+
'X-True-Sight-Signature-256': signatureHeader,
|
|
10
|
+
},
|
|
11
|
+
body: new Uint8Array(rawBody),
|
|
12
|
+
});
|
|
13
|
+
const body = await response.text();
|
|
14
|
+
return { status: response.status, body };
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function signManifestBody(rawBody: Buffer, secret: string): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.signManifestBody = signManifestBody;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
function signManifestBody(rawBody, secret) {
|
|
6
|
+
const digest = (0, node_crypto_1.createHmac)('sha256', secret).update(rawBody).digest('hex');
|
|
7
|
+
return `sha256=${digest}`;
|
|
8
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.printValidationErrors = printValidationErrors;
|
|
4
|
+
function printValidationErrors(errors) {
|
|
5
|
+
for (const error of errors) {
|
|
6
|
+
const prefix = error.path ? `${error.path}: ` : '';
|
|
7
|
+
console.error(`${prefix}${error.message}`);
|
|
8
|
+
}
|
|
9
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@true-sight/model-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"bin": {
|
|
5
|
+
"truesight-model": "./dist/cli.js"
|
|
6
|
+
},
|
|
7
|
+
"main": "./dist/cli.js",
|
|
8
|
+
"types": "./dist/cli.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"pretest": "npm run build -w @true-sight/model-schema && npm run build",
|
|
18
|
+
"test": "jest"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@true-sight/model-schema": "^1.0.0",
|
|
22
|
+
"commander": "^13.1.0",
|
|
23
|
+
"dotenv": "^16.6.1"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/jest": "^30.0.0",
|
|
27
|
+
"jest": "^30.0.0",
|
|
28
|
+
"ts-jest": "^29.2.5",
|
|
29
|
+
"typescript": "^5.7.3"
|
|
30
|
+
},
|
|
31
|
+
"jest": {
|
|
32
|
+
"moduleFileExtensions": [
|
|
33
|
+
"js",
|
|
34
|
+
"json",
|
|
35
|
+
"ts"
|
|
36
|
+
],
|
|
37
|
+
"rootDir": ".",
|
|
38
|
+
"testMatch": [
|
|
39
|
+
"**/test/**/*.spec.ts"
|
|
40
|
+
],
|
|
41
|
+
"transform": {
|
|
42
|
+
"^.+\\.(t|j)s$": "ts-jest"
|
|
43
|
+
},
|
|
44
|
+
"moduleNameMapper": {
|
|
45
|
+
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
46
|
+
},
|
|
47
|
+
"testEnvironment": "node"
|
|
48
|
+
}
|
|
49
|
+
}
|