apcore-toolkit 0.4.1 → 0.5.1
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/CHANGELOG.md +68 -0
- package/LICENSE +185 -0
- package/README.md +91 -39
- package/dist/ai-enhancer.d.ts +18 -1
- package/dist/ai-enhancer.d.ts.map +1 -1
- package/dist/ai-enhancer.js +100 -23
- package/dist/ai-enhancer.js.map +1 -1
- package/dist/binding-loader.d.ts +55 -0
- package/dist/binding-loader.d.ts.map +1 -0
- package/dist/binding-loader.js +175 -0
- package/dist/binding-loader.js.map +1 -0
- package/dist/binding-parser.d.ts +80 -0
- package/dist/binding-parser.d.ts.map +1 -0
- package/dist/binding-parser.js +257 -0
- package/dist/binding-parser.js.map +1 -0
- package/dist/browser/index.d.ts +17 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +46 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/{display-resolver.d.ts → display/resolver.d.ts} +14 -2
- package/dist/display/resolver.d.ts.map +1 -0
- package/dist/{display-resolver.js → display/resolver.js} +79 -25
- package/dist/display/resolver.js.map +1 -0
- package/dist/formatting/markdown.d.ts.map +1 -1
- package/dist/formatting/markdown.js +25 -22
- package/dist/formatting/markdown.js.map +1 -1
- package/dist/http-verb-map.d.ts +79 -0
- package/dist/http-verb-map.d.ts.map +1 -0
- package/dist/http-verb-map.js +179 -0
- package/dist/http-verb-map.js.map +1 -0
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -4
- package/dist/index.js.map +1 -1
- package/dist/openapi.d.ts.map +1 -1
- package/dist/openapi.js +37 -10
- package/dist/openapi.js.map +1 -1
- package/dist/output/base-writer.d.ts +17 -0
- package/dist/output/base-writer.d.ts.map +1 -0
- package/dist/output/base-writer.js +34 -0
- package/dist/output/base-writer.js.map +1 -0
- package/dist/output/errors.d.ts +7 -2
- package/dist/output/errors.d.ts.map +1 -1
- package/dist/output/errors.js +8 -3
- package/dist/output/errors.js.map +1 -1
- package/dist/output/factory.d.ts +13 -1
- package/dist/output/factory.d.ts.map +1 -1
- package/dist/output/factory.js +21 -2
- package/dist/output/factory.js.map +1 -1
- package/dist/output/http-proxy-writer.d.ts +82 -0
- package/dist/output/http-proxy-writer.d.ts.map +1 -0
- package/dist/output/http-proxy-writer.js +222 -0
- package/dist/output/http-proxy-writer.js.map +1 -0
- package/dist/output/index.d.ts +1 -1
- package/dist/output/index.d.ts.map +1 -1
- package/dist/output/index.js +1 -1
- package/dist/output/index.js.map +1 -1
- package/dist/output/registry-writer.d.ts +23 -5
- package/dist/output/registry-writer.d.ts.map +1 -1
- package/dist/output/registry-writer.js +52 -14
- package/dist/output/registry-writer.js.map +1 -1
- package/dist/output/types.d.ts +1 -0
- package/dist/output/types.d.ts.map +1 -1
- package/dist/output/types.js.map +1 -1
- package/dist/output/typescript-writer.d.ts +14 -6
- package/dist/output/typescript-writer.d.ts.map +1 -1
- package/dist/output/typescript-writer.js +100 -32
- package/dist/output/typescript-writer.js.map +1 -1
- package/dist/output/verifiers.d.ts +1 -9
- package/dist/output/verifiers.d.ts.map +1 -1
- package/dist/output/verifiers.js +92 -42
- package/dist/output/verifiers.js.map +1 -1
- package/dist/output/verify-core.d.ts +20 -0
- package/dist/output/verify-core.d.ts.map +1 -0
- package/dist/output/verify-core.js +59 -0
- package/dist/output/verify-core.js.map +1 -0
- package/dist/output/yaml-writer.d.ts +18 -6
- package/dist/output/yaml-writer.d.ts.map +1 -1
- package/dist/output/yaml-writer.js +99 -42
- package/dist/output/yaml-writer.js.map +1 -1
- package/dist/resolve-target.d.ts.map +1 -1
- package/dist/resolve-target.js +34 -5
- package/dist/resolve-target.js.map +1 -1
- package/dist/safe-keys.d.ts +2 -0
- package/dist/safe-keys.d.ts.map +1 -0
- package/dist/safe-keys.js +19 -0
- package/dist/safe-keys.js.map +1 -0
- package/dist/scanner.d.ts +22 -0
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +40 -16
- package/dist/scanner.js.map +1 -1
- package/dist/schema-utils.d.ts.map +1 -1
- package/dist/schema-utils.js +13 -2
- package/dist/schema-utils.js.map +1 -1
- package/dist/serializers.d.ts.map +1 -1
- package/dist/serializers.js +2 -0
- package/dist/serializers.js.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +9 -2
- package/dist/display-resolver.d.ts.map +0 -1
- package/dist/display-resolver.js.map +0 -1
- package/dist/flatten-params.d.ts +0 -16
- package/dist/flatten-params.d.ts.map +0 -1
- package/dist/flatten-params.js +0 -18
- package/dist/flatten-params.js.map +0 -1
|
@@ -1,38 +1,72 @@
|
|
|
1
1
|
import { FunctionModule, jsonSchemaToTypeBox } from 'apcore-js';
|
|
2
2
|
import { resolveTarget } from '../resolve-target.js';
|
|
3
3
|
import { createWriteResult } from './types.js';
|
|
4
|
-
import { RegistryVerifier
|
|
4
|
+
import { RegistryVerifier } from './verifiers.js';
|
|
5
|
+
import { WriteError } from './errors.js';
|
|
6
|
+
import { applyVerification } from './base-writer.js';
|
|
7
|
+
/**
|
|
8
|
+
* Write scanned modules to an apcore-js registry.
|
|
9
|
+
*
|
|
10
|
+
* Resolves each module's target function via `resolveTarget`, wraps it in a
|
|
11
|
+
* `FunctionModule`, and calls `registry.register()`. Supports dry-run and
|
|
12
|
+
* built-in / custom verification.
|
|
13
|
+
*/
|
|
5
14
|
export class RegistryWriter {
|
|
15
|
+
/**
|
|
16
|
+
* Register modules into the provided registry.
|
|
17
|
+
*
|
|
18
|
+
* @async This method is async in TypeScript due to dynamic module loading via
|
|
19
|
+
* `resolveTarget`. In Python and Rust the equivalent is synchronous.
|
|
20
|
+
* Always `await` this call: `await writer.write(modules, registry)`.
|
|
21
|
+
*
|
|
22
|
+
* @param modules - Scanned modules to register.
|
|
23
|
+
* @param registry - Target registry that implements `register()`.
|
|
24
|
+
* @param options - Optional write options: `dryRun`, `verify`, `verifiers`.
|
|
25
|
+
* @returns Array of WriteResult, one per module.
|
|
26
|
+
*/
|
|
6
27
|
async write(modules, registry, options) {
|
|
7
28
|
const shouldVerify = options?.verify ?? false;
|
|
8
29
|
const verifiers = options?.verifiers ?? [];
|
|
30
|
+
const allowedPrefixes = options?.allowedPrefixes;
|
|
31
|
+
const errorMode = options?.errorMode ?? 'throw';
|
|
9
32
|
const results = [];
|
|
10
33
|
for (const mod of modules) {
|
|
11
34
|
if (options?.dryRun) {
|
|
12
35
|
results.push(createWriteResult(mod.moduleId, null));
|
|
13
36
|
continue;
|
|
14
37
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
|
|
38
|
+
let fm;
|
|
39
|
+
try {
|
|
40
|
+
fm = await this._toFunctionModule(mod, allowedPrefixes);
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
if (errorMode === 'collect') {
|
|
44
|
+
results.push(createWriteResult(mod.moduleId, null, false, err instanceof Error ? err.message : String(err)));
|
|
45
|
+
continue;
|
|
22
46
|
}
|
|
47
|
+
throw new WriteError(mod.moduleId, err);
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
registry.register(mod.moduleId, fm);
|
|
23
51
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
52
|
+
catch (err) {
|
|
53
|
+
if (errorMode === 'collect') {
|
|
54
|
+
results.push(createWriteResult(mod.moduleId, null, false, err instanceof Error ? err.message : String(err)));
|
|
55
|
+
continue;
|
|
28
56
|
}
|
|
57
|
+
throw new WriteError(mod.moduleId, err);
|
|
29
58
|
}
|
|
59
|
+
const result = applyVerification(createWriteResult(mod.moduleId, null), new RegistryVerifier(registry), verifiers, '', mod.moduleId, shouldVerify);
|
|
30
60
|
results.push(result);
|
|
31
61
|
}
|
|
32
62
|
return results;
|
|
33
63
|
}
|
|
34
|
-
async _toFunctionModule(mod) {
|
|
35
|
-
const
|
|
64
|
+
async _toFunctionModule(mod, allowedPrefixes) {
|
|
65
|
+
const resolved = await resolveTarget(mod.target, allowedPrefixes);
|
|
66
|
+
if (typeof resolved !== 'function') {
|
|
67
|
+
throw new Error(`Target "${mod.target}" resolved to ${typeof resolved}, expected a function.`);
|
|
68
|
+
}
|
|
69
|
+
const targetFn = resolved;
|
|
36
70
|
return new FunctionModule({
|
|
37
71
|
execute: async (inputs, _context) => {
|
|
38
72
|
const result = await targetFn(inputs);
|
|
@@ -55,6 +89,10 @@ export class RegistryWriter {
|
|
|
55
89
|
annotations: mod.annotations,
|
|
56
90
|
metadata: Object.keys(mod.metadata).length > 0 ? { ...mod.metadata } : null,
|
|
57
91
|
examples: mod.examples.length > 0 ? [...mod.examples] : null,
|
|
92
|
+
// NOTE: ScannedModule carries a `display` field (populated by DisplayResolver).
|
|
93
|
+
// FunctionModule in apcore-js does not currently expose a display slot, so
|
|
94
|
+
// the display metadata is intentionally omitted here. In Rust, ModuleDescriptor
|
|
95
|
+
// includes a display field — once apcore-js exposes one, wire it here.
|
|
58
96
|
});
|
|
59
97
|
}
|
|
60
98
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-writer.js","sourceRoot":"","sources":["../../src/output/registry-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"registry-writer.js","sourceRoot":"","sources":["../../src/output/registry-writer.ts"],"names":[],"mappings":"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"}
|
package/dist/output/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/output/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/output/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC;CACtD;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,GAAE,MAAM,GAAG,IAAW,EAC1B,QAAQ,UAAO,EACf,iBAAiB,GAAE,MAAM,GAAG,IAAW,GACtC,WAAW,CAEb"}
|
package/dist/output/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/output/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/output/types.ts"],"names":[],"mappings":"AAiBA,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,OAAsB,IAAI,EAC1B,QAAQ,GAAG,IAAI,EACf,oBAAmC,IAAI;IAEvC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC;AACzD,CAAC"}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import type { ScannedModule } from '../types.js';
|
|
2
|
-
import type { WriteResult
|
|
2
|
+
import type { WriteResult } from './types.js';
|
|
3
|
+
import type { FileWriteOptions } from './base-writer.js';
|
|
4
|
+
/**
|
|
5
|
+
* Write scanned modules as TypeScript source files.
|
|
6
|
+
*
|
|
7
|
+
* Each module is emitted as a `<module_id>.ts` file that re-exports the
|
|
8
|
+
* target function with the apcore binding decorator applied.
|
|
9
|
+
*
|
|
10
|
+
* Language-parity note: this writer is TypeScript-only. Python uses
|
|
11
|
+
* `PythonWriter`; Rust does not have an equivalent code-generation writer.
|
|
12
|
+
* Output from this writer should not be compared to `YAMLWriter` output —
|
|
13
|
+
* they serve different purposes (runtime type-safety vs cross-SDK interchange).
|
|
14
|
+
*/
|
|
3
15
|
export declare class TypeScriptWriter {
|
|
4
|
-
write(modules: ScannedModule[], outputDir: string, options?:
|
|
5
|
-
dryRun?: boolean;
|
|
6
|
-
verify?: boolean;
|
|
7
|
-
verifiers?: Verifier[];
|
|
8
|
-
}): WriteResult[];
|
|
16
|
+
write(modules: ScannedModule[], outputDir: string, options?: FileWriteOptions): WriteResult[];
|
|
9
17
|
private _generateCode;
|
|
10
18
|
private _parseTarget;
|
|
11
19
|
private _sanitizeIdentifier;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript-writer.d.ts","sourceRoot":"","sources":["../../src/output/typescript-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"typescript-writer.d.ts","sourceRoot":"","sources":["../../src/output/typescript-writer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;;;;;;;GAUG;AACH,qBAAa,gBAAgB;IAC3B,KAAK,CACH,OAAO,EAAE,aAAa,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,WAAW,EAAE;IA8GhB,OAAO,CAAC,aAAa;IAiCrB,OAAO,CAAC,YAAY;IAoBpB,OAAO,CAAC,mBAAmB;CAU5B"}
|
|
@@ -1,53 +1,112 @@
|
|
|
1
|
-
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
-
import { resolve, join } from 'node:path';
|
|
1
|
+
import { writeFileSync, mkdirSync, realpathSync, lstatSync, renameSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import { resolve, join, sep, isAbsolute } from 'node:path';
|
|
3
3
|
import { createWriteResult } from './types.js';
|
|
4
4
|
import { WriteError } from './errors.js';
|
|
5
|
-
import { SyntaxVerifier
|
|
5
|
+
import { SyntaxVerifier } from './verifiers.js';
|
|
6
|
+
import { applyVerification } from './base-writer.js';
|
|
7
|
+
/**
|
|
8
|
+
* Write scanned modules as TypeScript source files.
|
|
9
|
+
*
|
|
10
|
+
* Each module is emitted as a `<module_id>.ts` file that re-exports the
|
|
11
|
+
* target function with the apcore binding decorator applied.
|
|
12
|
+
*
|
|
13
|
+
* Language-parity note: this writer is TypeScript-only. Python uses
|
|
14
|
+
* `PythonWriter`; Rust does not have an equivalent code-generation writer.
|
|
15
|
+
* Output from this writer should not be compared to `YAMLWriter` output —
|
|
16
|
+
* they serve different purposes (runtime type-safety vs cross-SDK interchange).
|
|
17
|
+
*/
|
|
6
18
|
export class TypeScriptWriter {
|
|
7
19
|
write(modules, outputDir, options) {
|
|
8
20
|
const dryRun = options?.dryRun ?? false;
|
|
9
21
|
const shouldVerify = options?.verify ?? false;
|
|
10
22
|
const verifiers = options?.verifiers ?? [];
|
|
23
|
+
const errorMode = options?.errorMode ?? 'throw';
|
|
11
24
|
const results = [];
|
|
12
25
|
const timestamp = new Date().toISOString();
|
|
26
|
+
const writtenIds = new Map(); // filename → moduleId that claimed it
|
|
13
27
|
const resolvedOut = dryRun ? '' : resolve(outputDir);
|
|
14
28
|
if (!dryRun) {
|
|
15
|
-
|
|
29
|
+
try {
|
|
30
|
+
mkdirSync(resolvedOut, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
throw new WriteError(resolvedOut, err);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
let realResolvedOut = resolvedOut;
|
|
37
|
+
if (!dryRun) {
|
|
38
|
+
try {
|
|
39
|
+
realResolvedOut = realpathSync(resolvedOut);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
throw new WriteError(resolvedOut, err);
|
|
43
|
+
}
|
|
16
44
|
}
|
|
17
45
|
for (const mod of modules) {
|
|
18
|
-
|
|
46
|
+
let code;
|
|
47
|
+
try {
|
|
48
|
+
code = this._generateCode(mod, timestamp);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (errorMode === 'collect') {
|
|
52
|
+
results.push(createWriteResult(mod.moduleId, null, false, err instanceof Error ? err.message : String(err)));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
throw new WriteError(mod.moduleId, err);
|
|
56
|
+
}
|
|
19
57
|
if (dryRun) {
|
|
20
58
|
results.push(createWriteResult(mod.moduleId, null));
|
|
21
59
|
continue;
|
|
22
60
|
}
|
|
23
|
-
// Path traversal protection: check raw moduleId before sanitization
|
|
24
|
-
const rawResolved = resolve(join(resolvedOut, mod.moduleId));
|
|
25
|
-
if (!rawResolved.startsWith(resolvedOut + '/') && rawResolved !== resolvedOut) {
|
|
26
|
-
console.warn('Skipping module with path traversal in id: %s', mod.moduleId);
|
|
27
|
-
continue;
|
|
28
|
-
}
|
|
29
61
|
const sanitized = this._sanitizeIdentifier(mod.moduleId);
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
62
|
+
const baseFilename = `${sanitized}.ts`;
|
|
63
|
+
let filename = baseFilename;
|
|
64
|
+
let collisionCounter = 0;
|
|
65
|
+
while (writtenIds.has(filename)) {
|
|
66
|
+
collisionCounter++;
|
|
67
|
+
filename = `${sanitized}_${collisionCounter}.ts`;
|
|
34
68
|
}
|
|
35
|
-
|
|
36
|
-
|
|
69
|
+
if (collisionCounter > 0) {
|
|
70
|
+
console.warn('TypeScriptWriter: safeId collision — "%s" and "%s" both map to %s; using %s', writtenIds.get(baseFilename), mod.moduleId, baseFilename, filename);
|
|
37
71
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
72
|
+
writtenIds.set(filename, mod.moduleId);
|
|
73
|
+
const filePath = resolve(join(realResolvedOut, filename));
|
|
74
|
+
// Block symlinks pre-created at the target path (TOCTOU mitigation).
|
|
75
|
+
// lstatSync does not follow symlinks, so it detects symlinks directly.
|
|
76
|
+
try {
|
|
77
|
+
if (lstatSync(filePath).isSymbolicLink()) {
|
|
78
|
+
console.warn('Skipping symlink escape at: %s', filePath);
|
|
79
|
+
results.push(createWriteResult(mod.moduleId, filePath, false, 'Security skip: symlink at target path'));
|
|
80
|
+
continue;
|
|
43
81
|
}
|
|
44
82
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
83
|
+
catch { /* file does not exist — safe to write */ }
|
|
84
|
+
// Atomic write: write to a tmp file then rename so readers never see a
|
|
85
|
+
// partially-written file and so the final rename is atomic on POSIX.
|
|
86
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
87
|
+
try {
|
|
88
|
+
writeFileSync(tmpPath, code, 'utf-8');
|
|
89
|
+
renameSync(tmpPath, filePath);
|
|
90
|
+
// Post-rename sanity check: verify the result is not a symlink (defence-in-depth).
|
|
91
|
+
try {
|
|
92
|
+
if (lstatSync(filePath).isSymbolicLink()) {
|
|
93
|
+
console.warn('TypeScriptWriter: post-rename symlink detected at %s — possible race', filePath);
|
|
94
|
+
}
|
|
49
95
|
}
|
|
96
|
+
catch { /* lstat failing here is non-critical */ }
|
|
50
97
|
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
try {
|
|
100
|
+
unlinkSync(tmpPath);
|
|
101
|
+
}
|
|
102
|
+
catch { /* best-effort cleanup */ }
|
|
103
|
+
if (errorMode === 'collect') {
|
|
104
|
+
results.push(createWriteResult(mod.moduleId, filePath, false, err instanceof Error ? err.message : String(err)));
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
throw new WriteError(filePath, err);
|
|
108
|
+
}
|
|
109
|
+
const result = applyVerification(createWriteResult(mod.moduleId, filePath), new SyntaxVerifier(), verifiers, filePath, mod.moduleId, shouldVerify);
|
|
51
110
|
results.push(result);
|
|
52
111
|
}
|
|
53
112
|
return results;
|
|
@@ -60,12 +119,13 @@ export class TypeScriptWriter {
|
|
|
60
119
|
lines.push('// Do not edit manually unless you intend to customize behavior.');
|
|
61
120
|
lines.push('');
|
|
62
121
|
lines.push("import { module } from 'apcore-js';");
|
|
122
|
+
lines.push("import { Type } from '@sinclair/typebox';");
|
|
63
123
|
lines.push('');
|
|
64
124
|
lines.push('export default module({');
|
|
65
125
|
lines.push(` id: ${JSON.stringify(mod.moduleId)},`);
|
|
66
126
|
lines.push(` description: ${JSON.stringify(mod.description)},`);
|
|
67
|
-
lines.push(` inputSchema: ${JSON.stringify(mod.inputSchema)},`);
|
|
68
|
-
lines.push(` outputSchema: ${JSON.stringify(mod.outputSchema)},`);
|
|
127
|
+
lines.push(` inputSchema: Type.Unsafe(${JSON.stringify(mod.inputSchema)}),`);
|
|
128
|
+
lines.push(` outputSchema: Type.Unsafe(${JSON.stringify(mod.outputSchema)}),`);
|
|
69
129
|
lines.push(` tags: ${JSON.stringify([...mod.tags])},`);
|
|
70
130
|
lines.push(` version: ${JSON.stringify(mod.version)},`);
|
|
71
131
|
if (mod.annotations !== null) {
|
|
@@ -88,16 +148,24 @@ export class TypeScriptWriter {
|
|
|
88
148
|
if (!/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(exportName)) {
|
|
89
149
|
throw new Error(`Invalid export name: ${exportName}`);
|
|
90
150
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
151
|
+
const modulePath = target.slice(0, lastColon);
|
|
152
|
+
if (isAbsolute(modulePath)) {
|
|
153
|
+
throw new Error(`TypeScriptWriter: absolute module path not allowed in target: ${modulePath}`);
|
|
154
|
+
}
|
|
155
|
+
const segments = modulePath.split('/');
|
|
156
|
+
if (segments.some((seg) => seg === '..')) {
|
|
157
|
+
throw new Error(`TypeScriptWriter: parent traversal in module path not allowed: ${modulePath}`);
|
|
158
|
+
}
|
|
159
|
+
return { modulePath, exportName };
|
|
95
160
|
}
|
|
96
161
|
_sanitizeIdentifier(name) {
|
|
97
162
|
let sanitized = name.replace(/[^a-zA-Z0-9_]/g, '_');
|
|
98
163
|
if (/^[0-9]/.test(sanitized)) {
|
|
99
164
|
sanitized = `_${sanitized}`;
|
|
100
165
|
}
|
|
166
|
+
if (sanitized.length === 0) {
|
|
167
|
+
sanitized = '_module';
|
|
168
|
+
}
|
|
101
169
|
return sanitized;
|
|
102
170
|
}
|
|
103
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript-writer.js","sourceRoot":"","sources":["../../src/output/typescript-writer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"typescript-writer.js","sourceRoot":"","sources":["../../src/output/typescript-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,26 +1,18 @@
|
|
|
1
1
|
import type { Verifier, VerifyResult } from './types.js';
|
|
2
|
+
export { RegistryVerifier, runVerifierChain } from './verify-core.js';
|
|
2
3
|
export declare class YAMLVerifier implements Verifier {
|
|
3
4
|
verify(path: string, _moduleId: string): VerifyResult;
|
|
4
5
|
}
|
|
5
6
|
export declare class SyntaxVerifier implements Verifier {
|
|
6
7
|
verify(path: string, _moduleId: string): VerifyResult;
|
|
7
8
|
}
|
|
8
|
-
export declare class RegistryVerifier implements Verifier {
|
|
9
|
-
private readonly registry;
|
|
10
|
-
constructor(registry: {
|
|
11
|
-
getModule?(id: string): unknown;
|
|
12
|
-
});
|
|
13
|
-
verify(_path: string, moduleId: string): VerifyResult;
|
|
14
|
-
}
|
|
15
9
|
export declare class MagicBytesVerifier implements Verifier {
|
|
16
10
|
private readonly expected;
|
|
17
11
|
constructor(expected: Buffer);
|
|
18
12
|
verify(path: string, _moduleId: string): VerifyResult;
|
|
19
13
|
}
|
|
20
14
|
export declare class JSONVerifier implements Verifier {
|
|
21
|
-
private readonly schema;
|
|
22
15
|
constructor(schema?: Record<string, unknown>);
|
|
23
16
|
verify(path: string, _moduleId: string): VerifyResult;
|
|
24
17
|
}
|
|
25
|
-
export declare function runVerifierChain(verifiers: Verifier[], path: string, moduleId: string): VerifyResult;
|
|
26
18
|
//# sourceMappingURL=verifiers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifiers.d.ts","sourceRoot":"","sources":["../../src/output/verifiers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verifiers.d.ts","sourceRoot":"","sources":["../../src/output/verifiers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAMzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAYtE,qBAAa,YAAa,YAAW,QAAQ;IAC3C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY;CA2BtD;AAkBD,qBAAa,cAAe,YAAW,QAAQ;IAC7C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY;CA+BtD;AAED,qBAAa,kBAAmB,YAAW,QAAQ;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,EAAE,MAAM;IAI5B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY;CAgBtD;AAED,qBAAa,YAAa,YAAW,QAAQ;gBAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAU5C,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY;CActD"}
|
package/dist/output/verifiers.js
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
1
|
+
import { readFileSync, openSync, readSync, closeSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
import yaml from 'js-yaml';
|
|
4
|
+
// Re-export runtime-neutral verifier primitives so downstream imports from
|
|
5
|
+
// this file (internal and the default package entry) continue to work while
|
|
6
|
+
// the browser subpath imports them directly from `verify-core.js` without
|
|
7
|
+
// dragging in the Node-only code below.
|
|
8
|
+
export { RegistryVerifier, runVerifierChain } from './verify-core.js';
|
|
9
|
+
const _require = createRequire(import.meta.url);
|
|
10
|
+
function loadTypeScript() {
|
|
11
|
+
try {
|
|
12
|
+
return _require('typescript');
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
3
18
|
export class YAMLVerifier {
|
|
4
19
|
verify(path, _moduleId) {
|
|
5
20
|
try {
|
|
@@ -11,46 +26,73 @@ export class YAMLVerifier {
|
|
|
11
26
|
if (!('bindings' in doc)) {
|
|
12
27
|
return { ok: false, error: 'Missing required "bindings" key' };
|
|
13
28
|
}
|
|
29
|
+
const bindings = doc.bindings;
|
|
30
|
+
if (!Array.isArray(bindings) || bindings.length === 0) {
|
|
31
|
+
return { ok: false, error: 'bindings array is empty' };
|
|
32
|
+
}
|
|
33
|
+
for (let i = 0; i < bindings.length; i++) {
|
|
34
|
+
const entry = bindings[i];
|
|
35
|
+
for (const field of ['module_id', 'target']) {
|
|
36
|
+
if (typeof entry[field] !== 'string' || entry[field] === '') {
|
|
37
|
+
return { ok: false, error: `Missing or empty required field '${field}' in binding[${i}]` };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
14
41
|
return { ok: true };
|
|
15
42
|
}
|
|
16
43
|
catch (err) {
|
|
17
|
-
return { ok: false, error: `YAML parse error: ${err.message}
|
|
44
|
+
return { ok: false, error: `YAML parse error: ${err.message}`, cause: err };
|
|
18
45
|
}
|
|
19
46
|
}
|
|
20
47
|
}
|
|
48
|
+
function _flattenDiagnosticMessage(msg, depth = 0) {
|
|
49
|
+
if (depth > 32)
|
|
50
|
+
return '[...]';
|
|
51
|
+
if (typeof msg === 'string')
|
|
52
|
+
return msg;
|
|
53
|
+
if (typeof msg === 'object' && msg !== null && 'messageText' in msg) {
|
|
54
|
+
const chain = msg;
|
|
55
|
+
const parts = [_flattenDiagnosticMessage(chain.messageText, depth + 1)];
|
|
56
|
+
if (Array.isArray(chain.next)) {
|
|
57
|
+
for (const sub of chain.next) {
|
|
58
|
+
parts.push(_flattenDiagnosticMessage(sub, depth + 1));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return parts.join(': ');
|
|
62
|
+
}
|
|
63
|
+
return String(msg);
|
|
64
|
+
}
|
|
21
65
|
export class SyntaxVerifier {
|
|
22
66
|
verify(path, _moduleId) {
|
|
23
67
|
try {
|
|
24
68
|
const content = readFileSync(path, 'utf-8');
|
|
25
|
-
// Basic syntax check: ensure file is non-empty and parseable
|
|
26
69
|
if (content.trim().length === 0) {
|
|
27
70
|
return { ok: false, error: 'File is empty' };
|
|
28
71
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
export class RegistryVerifier {
|
|
37
|
-
registry;
|
|
38
|
-
constructor(registry) {
|
|
39
|
-
this.registry = registry;
|
|
40
|
-
}
|
|
41
|
-
verify(_path, moduleId) {
|
|
42
|
-
try {
|
|
43
|
-
if (typeof this.registry.getModule !== 'function') {
|
|
44
|
-
return { ok: false, error: 'Registry does not have a getModule method' };
|
|
72
|
+
// Use the TypeScript compiler to parse and check for syntax errors.
|
|
73
|
+
const ts = loadTypeScript();
|
|
74
|
+
if (ts === null) {
|
|
75
|
+
return { ok: false, error: 'typescript package required for syntax verification' };
|
|
45
76
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
77
|
+
const program = ts.createProgram([path], {
|
|
78
|
+
noLib: true,
|
|
79
|
+
noResolve: true,
|
|
80
|
+
skipLibCheck: true,
|
|
81
|
+
strict: false,
|
|
82
|
+
});
|
|
83
|
+
const sourceFile = program.getSourceFile(path);
|
|
84
|
+
if (!sourceFile) {
|
|
85
|
+
return { ok: false, error: 'TypeScript compiler could not load file' };
|
|
86
|
+
}
|
|
87
|
+
const diagnostics = program.getSyntacticDiagnostics(sourceFile);
|
|
88
|
+
if (diagnostics.length > 0) {
|
|
89
|
+
const text = _flattenDiagnosticMessage(diagnostics[0].messageText);
|
|
90
|
+
return { ok: false, error: `Syntax error: ${text}` };
|
|
49
91
|
}
|
|
50
92
|
return { ok: true };
|
|
51
93
|
}
|
|
52
94
|
catch (err) {
|
|
53
|
-
return { ok: false, error: `
|
|
95
|
+
return { ok: false, error: `Read error: ${err.message}`, cause: err };
|
|
54
96
|
}
|
|
55
97
|
}
|
|
56
98
|
}
|
|
@@ -60,44 +102,52 @@ export class MagicBytesVerifier {
|
|
|
60
102
|
this.expected = expected;
|
|
61
103
|
}
|
|
62
104
|
verify(path, _moduleId) {
|
|
105
|
+
let fd;
|
|
63
106
|
try {
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
107
|
+
fd = openSync(path, 'r');
|
|
108
|
+
const buf = Buffer.alloc(this.expected.length);
|
|
109
|
+
const bytesRead = readSync(fd, buf, 0, this.expected.length, 0);
|
|
110
|
+
if (bytesRead < this.expected.length || !buf.equals(this.expected)) {
|
|
67
111
|
return { ok: false, error: 'File header does not match expected magic bytes' };
|
|
68
112
|
}
|
|
69
113
|
return { ok: true };
|
|
70
114
|
}
|
|
71
115
|
catch (err) {
|
|
72
|
-
return { ok: false, error: `Read error: ${err.message}
|
|
116
|
+
return { ok: false, error: `Read error: ${err.message}`, cause: err };
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
if (fd !== undefined) {
|
|
120
|
+
try {
|
|
121
|
+
closeSync(fd);
|
|
122
|
+
}
|
|
123
|
+
catch { /* ignore */ }
|
|
124
|
+
}
|
|
73
125
|
}
|
|
74
126
|
}
|
|
75
127
|
}
|
|
76
128
|
export class JSONVerifier {
|
|
77
|
-
schema;
|
|
78
129
|
constructor(schema) {
|
|
79
|
-
|
|
130
|
+
if (schema != null) {
|
|
131
|
+
throw new Error('JSONVerifier: schema validation is not yet implemented. ' +
|
|
132
|
+
'Install ajv and update JSONVerifier.verify() to enable schema validation, ' +
|
|
133
|
+
'or construct JSONVerifier without a schema argument for syntax-only checking.');
|
|
134
|
+
}
|
|
80
135
|
}
|
|
81
136
|
verify(path, _moduleId) {
|
|
137
|
+
let content;
|
|
138
|
+
try {
|
|
139
|
+
content = readFileSync(path, 'utf-8');
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
return { ok: false, error: `Read error: ${err.message}`, cause: err };
|
|
143
|
+
}
|
|
82
144
|
try {
|
|
83
|
-
const content = readFileSync(path, 'utf-8');
|
|
84
145
|
JSON.parse(content);
|
|
85
|
-
// Schema validation is accepted for API parity with Python but requires
|
|
86
|
-
// a JSON Schema validator (e.g., ajv) for actual validation.
|
|
87
146
|
return { ok: true };
|
|
88
147
|
}
|
|
89
148
|
catch (err) {
|
|
90
|
-
return { ok: false, error: `JSON parse error: ${err.message}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
export function runVerifierChain(verifiers, path, moduleId) {
|
|
95
|
-
for (const verifier of verifiers) {
|
|
96
|
-
const result = verifier.verify(path, moduleId);
|
|
97
|
-
if (!result.ok) {
|
|
98
|
-
return result;
|
|
149
|
+
return { ok: false, error: `JSON parse error: ${err.message}`, cause: err };
|
|
99
150
|
}
|
|
100
151
|
}
|
|
101
|
-
return { ok: true };
|
|
102
152
|
}
|
|
103
153
|
//# sourceMappingURL=verifiers.js.map
|