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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verifiers.js","sourceRoot":"","sources":["../../src/output/verifiers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"verifiers.js","sourceRoot":"","sources":["../../src/output/verifiers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Verifier, VerifyResult } from './types.js';
|
|
2
|
+
export declare class RegistryVerifier implements Verifier {
|
|
3
|
+
private readonly registry;
|
|
4
|
+
constructor(registry: {
|
|
5
|
+
getModule?(id: string): unknown;
|
|
6
|
+
});
|
|
7
|
+
verify(_path: string, moduleId: string): VerifyResult;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Run a chain of verifiers in order, returning the first failure.
|
|
11
|
+
* If a verifier throws an exception, it is caught and returned as a failure
|
|
12
|
+
* with the prefix "Verifier crashed:".
|
|
13
|
+
*
|
|
14
|
+
* @param verifiers - Ordered list of verifiers to run.
|
|
15
|
+
* @param path - File path to verify.
|
|
16
|
+
* @param moduleId - Module ID being verified.
|
|
17
|
+
* @returns The first failed VerifyResult, or { ok: true } if all pass.
|
|
18
|
+
*/
|
|
19
|
+
export declare function runVerifierChain(verifiers: Verifier[], path: string, moduleId: string): VerifyResult;
|
|
20
|
+
//# sourceMappingURL=verify-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-core.d.ts","sourceRoot":"","sources":["../../src/output/verify-core.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,qBAAa,gBAAiB,YAAW,QAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;gBAEnD,QAAQ,EAAE;QAAE,SAAS,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE;IAIzD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY;CActD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,QAAQ,EAAE,EACrB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,YAAY,CAYd"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Runtime-neutral verifier primitives.
|
|
2
|
+
//
|
|
3
|
+
// This module contains the `Verifier` implementations and combinators that
|
|
4
|
+
// do not touch the filesystem or any other Node-only API. They live here so
|
|
5
|
+
// the browser subpath entry (`apcore-toolkit/browser`) can expose them
|
|
6
|
+
// without transitively dragging in `node:fs` / `node:module` from the
|
|
7
|
+
// file-based verifiers (`YAMLVerifier`, `SyntaxVerifier`, `MagicBytesVerifier`,
|
|
8
|
+
// `JSONVerifier`) that share the original `verifiers.ts` file.
|
|
9
|
+
//
|
|
10
|
+
// `verifiers.ts` continues to re-export `RegistryVerifier` and
|
|
11
|
+
// `runVerifierChain` from here, so the default package entry point's public
|
|
12
|
+
// API is unchanged.
|
|
13
|
+
export class RegistryVerifier {
|
|
14
|
+
registry;
|
|
15
|
+
constructor(registry) {
|
|
16
|
+
this.registry = registry;
|
|
17
|
+
}
|
|
18
|
+
verify(_path, moduleId) {
|
|
19
|
+
try {
|
|
20
|
+
if (typeof this.registry.getModule !== 'function') {
|
|
21
|
+
return { ok: false, error: 'Registry does not have a getModule method' };
|
|
22
|
+
}
|
|
23
|
+
const mod = this.registry.getModule(moduleId);
|
|
24
|
+
if (mod == null) {
|
|
25
|
+
return { ok: false, error: `Module "${moduleId}" not found in registry` };
|
|
26
|
+
}
|
|
27
|
+
return { ok: true };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
return { ok: false, error: `Registry lookup error: ${err.message}`, cause: err };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Run a chain of verifiers in order, returning the first failure.
|
|
36
|
+
* If a verifier throws an exception, it is caught and returned as a failure
|
|
37
|
+
* with the prefix "Verifier crashed:".
|
|
38
|
+
*
|
|
39
|
+
* @param verifiers - Ordered list of verifiers to run.
|
|
40
|
+
* @param path - File path to verify.
|
|
41
|
+
* @param moduleId - Module ID being verified.
|
|
42
|
+
* @returns The first failed VerifyResult, or { ok: true } if all pass.
|
|
43
|
+
*/
|
|
44
|
+
export function runVerifierChain(verifiers, path, moduleId) {
|
|
45
|
+
for (const verifier of verifiers) {
|
|
46
|
+
try {
|
|
47
|
+
const result = verifier.verify(path, moduleId);
|
|
48
|
+
if (!result.ok)
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
const name = verifier.constructor?.name ?? 'UnknownVerifier';
|
|
53
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
54
|
+
return { ok: false, error: `${name} crashed: ${msg}`, cause: e };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { ok: true };
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=verify-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify-core.js","sourceRoot":"","sources":["../../src/output/verify-core.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,uEAAuE;AACvE,sEAAsE;AACtE,gFAAgF;AAChF,+DAA+D;AAC/D,EAAE;AACF,+DAA+D;AAC/D,4EAA4E;AAC5E,oBAAoB;AAIpB,MAAM,OAAO,gBAAgB;IACV,QAAQ,CAAsC;IAE/D,YAAY,QAA6C;QACvD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,KAAa,EAAE,QAAgB;QACpC,IAAI,CAAC;YACH,IAAI,OAAO,IAAI,CAAC,QAAQ,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBAClD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,2CAA2C,EAAE,CAAC;YAC3E,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;gBAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,QAAQ,yBAAyB,EAAE,CAAC;YAC5E,CAAC;YACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA2B,GAAa,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;QAC9F,CAAC;IACH,CAAC;CACF;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAqB,EACrB,IAAY,EACZ,QAAgB;IAEhB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC/C,IAAI,CAAC,MAAM,CAAC,EAAE;gBAAE,OAAO,MAAM,CAAC;QAChC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,iBAAiB,CAAC;YAC7D,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,aAAa,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACnE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC"}
|
|
@@ -1,11 +1,23 @@
|
|
|
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 YAML binding files.
|
|
6
|
+
*
|
|
7
|
+
* Each module is serialised to a `<module_id>.binding.yaml` file in the
|
|
8
|
+
* specified output directory. The YAML format conforms to the apcore binding
|
|
9
|
+
* spec (`spec_version: "1.0"`).
|
|
10
|
+
*/
|
|
3
11
|
export declare class YAMLWriter {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Serialise modules to YAML and write them to `outputDir`.
|
|
14
|
+
*
|
|
15
|
+
* @param modules - Scanned modules to write.
|
|
16
|
+
* @param outputDir - Directory to write binding files into (created if absent).
|
|
17
|
+
* @param options - Optional write options: `dryRun`, `verify`, `verifiers`.
|
|
18
|
+
* @returns Array of WriteResult, one per module.
|
|
19
|
+
*/
|
|
20
|
+
write(modules: ScannedModule[], outputDir: string, options?: FileWriteOptions): WriteResult[];
|
|
9
21
|
private _buildBinding;
|
|
10
22
|
}
|
|
11
23
|
//# sourceMappingURL=yaml-writer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-writer.d.ts","sourceRoot":"","sources":["../../src/output/yaml-writer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"yaml-writer.d.ts","sourceRoot":"","sources":["../../src/output/yaml-writer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAK9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD;;;;;;GAMG;AACH,qBAAa,UAAU;IACrB;;;;;;;OAOG;IACH,KAAK,CACH,OAAO,EAAE,aAAa,EAAE,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,gBAAgB,GACzB,WAAW,EAAE;IAqHhB,OAAO,CAAC,aAAa;CA2BtB"}
|
|
@@ -1,24 +1,56 @@
|
|
|
1
1
|
import yaml from 'js-yaml';
|
|
2
|
-
import { writeFileSync, mkdirSync,
|
|
3
|
-
import { resolve, join } from 'node:path';
|
|
2
|
+
import { writeFileSync, mkdirSync, realpathSync, lstatSync, renameSync, unlinkSync } from 'node:fs';
|
|
3
|
+
import { resolve, join, sep } from 'node:path';
|
|
4
4
|
import { annotationsToDict } from '../serializers.js';
|
|
5
5
|
import { createWriteResult } from './types.js';
|
|
6
6
|
import { WriteError } from './errors.js';
|
|
7
|
-
import { YAMLVerifier
|
|
7
|
+
import { YAMLVerifier } from './verifiers.js';
|
|
8
|
+
import { applyVerification } from './base-writer.js';
|
|
9
|
+
/**
|
|
10
|
+
* Write scanned modules as YAML binding files.
|
|
11
|
+
*
|
|
12
|
+
* Each module is serialised to a `<module_id>.binding.yaml` file in the
|
|
13
|
+
* specified output directory. The YAML format conforms to the apcore binding
|
|
14
|
+
* spec (`spec_version: "1.0"`).
|
|
15
|
+
*/
|
|
8
16
|
export class YAMLWriter {
|
|
17
|
+
/**
|
|
18
|
+
* Serialise modules to YAML and write them to `outputDir`.
|
|
19
|
+
*
|
|
20
|
+
* @param modules - Scanned modules to write.
|
|
21
|
+
* @param outputDir - Directory to write binding files into (created if absent).
|
|
22
|
+
* @param options - Optional write options: `dryRun`, `verify`, `verifiers`.
|
|
23
|
+
* @returns Array of WriteResult, one per module.
|
|
24
|
+
*/
|
|
9
25
|
write(modules, outputDir, options) {
|
|
10
26
|
const dryRun = options?.dryRun ?? false;
|
|
11
27
|
const shouldVerify = options?.verify ?? false;
|
|
12
28
|
const verifiers = options?.verifiers ?? [];
|
|
29
|
+
const errorMode = options?.errorMode ?? 'throw';
|
|
13
30
|
if (modules.length === 0) {
|
|
14
31
|
return [];
|
|
15
32
|
}
|
|
16
33
|
const outputPath = resolve(outputDir);
|
|
17
34
|
if (!dryRun) {
|
|
18
|
-
|
|
35
|
+
try {
|
|
36
|
+
mkdirSync(outputPath, { recursive: true });
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
throw new WriteError(outputPath, err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let realOutputPath = outputPath;
|
|
43
|
+
if (!dryRun) {
|
|
44
|
+
try {
|
|
45
|
+
realOutputPath = realpathSync(outputPath);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
throw new WriteError(outputPath, err);
|
|
49
|
+
}
|
|
19
50
|
}
|
|
20
51
|
const results = [];
|
|
21
52
|
const timestamp = new Date().toISOString();
|
|
53
|
+
const writtenIds = new Map(); // filename → moduleId that claimed it
|
|
22
54
|
for (const module of modules) {
|
|
23
55
|
const bindingData = this._buildBinding(module);
|
|
24
56
|
if (dryRun) {
|
|
@@ -27,16 +59,29 @@ export class YAMLWriter {
|
|
|
27
59
|
}
|
|
28
60
|
let safeId = module.moduleId.replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
29
61
|
safeId = safeId.replace(/\.{2,}/g, '_');
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
62
|
+
const baseFilename = `${safeId}.binding.yaml`;
|
|
63
|
+
let filename = baseFilename;
|
|
64
|
+
let collisionCounter = 0;
|
|
65
|
+
while (writtenIds.has(filename)) {
|
|
66
|
+
collisionCounter++;
|
|
67
|
+
filename = `${safeId}_${collisionCounter}.binding.yaml`;
|
|
36
68
|
}
|
|
37
|
-
if (
|
|
38
|
-
console.warn('
|
|
69
|
+
if (collisionCounter > 0) {
|
|
70
|
+
console.warn('YAMLWriter: safeId collision — "%s" and "%s" both map to %s; using %s', writtenIds.get(baseFilename), module.moduleId, baseFilename, filename);
|
|
39
71
|
}
|
|
72
|
+
writtenIds.set(filename, module.moduleId);
|
|
73
|
+
// Build filePath from the real (symlink-resolved) output dir so the
|
|
74
|
+
// prefix check below compares canonical paths on both sides.
|
|
75
|
+
const filePath = resolve(join(realOutputPath, filename));
|
|
76
|
+
// Block pre-existing symlinks at the target path (TOCTOU mitigation).
|
|
77
|
+
try {
|
|
78
|
+
if (lstatSync(filePath).isSymbolicLink()) {
|
|
79
|
+
console.warn('Skipping symlink escape at: %s', filePath);
|
|
80
|
+
results.push(createWriteResult(module.moduleId, filePath, false, 'Security skip: symlink at target path'));
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch { /* file does not exist — safe to write */ }
|
|
40
85
|
const header = `# Auto-generated by apcore-toolkit scanner\n` +
|
|
41
86
|
`# Generated: ${timestamp}\n` +
|
|
42
87
|
`# Do not edit manually unless you intend to customize schemas.\n\n`;
|
|
@@ -44,48 +89,60 @@ export class YAMLWriter {
|
|
|
44
89
|
flowLevel: -1,
|
|
45
90
|
sortKeys: false,
|
|
46
91
|
});
|
|
92
|
+
// Atomic write via tmp file + rename.
|
|
93
|
+
const tmpPath = `${filePath}.${process.pid}.tmp`;
|
|
47
94
|
try {
|
|
48
|
-
writeFileSync(
|
|
95
|
+
writeFileSync(tmpPath, header + yamlContent, 'utf-8');
|
|
96
|
+
renameSync(tmpPath, filePath);
|
|
97
|
+
// Post-rename sanity check: verify the result is not a symlink (defence-in-depth).
|
|
98
|
+
try {
|
|
99
|
+
if (lstatSync(filePath).isSymbolicLink()) {
|
|
100
|
+
console.warn('YAMLWriter: post-rename symlink detected at %s — possible race', filePath);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch { /* lstat failing here is non-critical */ }
|
|
49
104
|
}
|
|
50
105
|
catch (err) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
let result = createWriteResult(module.moduleId, filePath);
|
|
54
|
-
if (shouldVerify) {
|
|
55
|
-
const builtinResult = new YAMLVerifier().verify(filePath, module.moduleId);
|
|
56
|
-
if (!builtinResult.ok) {
|
|
57
|
-
result = createWriteResult(module.moduleId, filePath, false, builtinResult.error ?? null);
|
|
106
|
+
try {
|
|
107
|
+
unlinkSync(tmpPath);
|
|
58
108
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
result = createWriteResult(module.moduleId, filePath, false, vResult.error ?? null);
|
|
109
|
+
catch { /* best-effort cleanup */ }
|
|
110
|
+
if (errorMode === 'collect') {
|
|
111
|
+
results.push(createWriteResult(module.moduleId, filePath, false, err instanceof Error ? err.message : String(err)));
|
|
112
|
+
continue;
|
|
64
113
|
}
|
|
114
|
+
throw new WriteError(filePath, err);
|
|
65
115
|
}
|
|
116
|
+
const result = applyVerification(createWriteResult(module.moduleId, filePath), new YAMLVerifier(), verifiers, filePath, module.moduleId, shouldVerify);
|
|
66
117
|
results.push(result);
|
|
67
118
|
}
|
|
68
119
|
return results;
|
|
69
120
|
}
|
|
70
121
|
_buildBinding(module) {
|
|
122
|
+
const binding = {
|
|
123
|
+
module_id: module.moduleId,
|
|
124
|
+
target: module.target,
|
|
125
|
+
description: module.description,
|
|
126
|
+
documentation: module.documentation,
|
|
127
|
+
tags: [...module.tags],
|
|
128
|
+
version: module.version,
|
|
129
|
+
annotations: annotationsToDict(module.annotations),
|
|
130
|
+
examples: module.examples.length > 0
|
|
131
|
+
? module.examples.map((e) => structuredClone(e))
|
|
132
|
+
: [],
|
|
133
|
+
metadata: structuredClone(module.metadata),
|
|
134
|
+
input_schema: structuredClone(module.inputSchema),
|
|
135
|
+
output_schema: structuredClone(module.outputSchema),
|
|
136
|
+
};
|
|
137
|
+
if (module.suggestedAlias !== null) {
|
|
138
|
+
binding.suggested_alias = module.suggestedAlias;
|
|
139
|
+
}
|
|
140
|
+
if (module.display !== null) {
|
|
141
|
+
binding.display = structuredClone(module.display);
|
|
142
|
+
}
|
|
71
143
|
return {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
module_id: module.moduleId,
|
|
75
|
-
target: module.target,
|
|
76
|
-
description: module.description,
|
|
77
|
-
documentation: module.documentation,
|
|
78
|
-
tags: [...module.tags],
|
|
79
|
-
version: module.version,
|
|
80
|
-
annotations: annotationsToDict(module.annotations),
|
|
81
|
-
examples: module.examples.length > 0
|
|
82
|
-
? module.examples.map((e) => ({ ...e }))
|
|
83
|
-
: [],
|
|
84
|
-
metadata: structuredClone(module.metadata),
|
|
85
|
-
input_schema: structuredClone(module.inputSchema),
|
|
86
|
-
output_schema: structuredClone(module.outputSchema),
|
|
87
|
-
},
|
|
88
|
-
],
|
|
144
|
+
spec_version: "1.0",
|
|
145
|
+
bindings: [binding],
|
|
89
146
|
};
|
|
90
147
|
}
|
|
91
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-writer.js","sourceRoot":"","sources":["../../src/output/yaml-writer.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"yaml-writer.js","sourceRoot":"","sources":["../../src/output/yaml-writer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-target.d.ts","sourceRoot":"","sources":["../src/resolve-target.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve-target.d.ts","sourceRoot":"","sources":["../src/resolve-target.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,OAAO,CAAC,CAoElB"}
|
package/dist/resolve-target.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { resolve, isAbsolute } from 'node:path';
|
|
1
|
+
import { resolve, isAbsolute, sep } from 'node:path';
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
2
3
|
/**
|
|
3
4
|
* Dynamically imports a module and resolves a named export.
|
|
4
5
|
*
|
|
@@ -19,11 +20,39 @@ export async function resolveTarget(target, allowedPrefixes) {
|
|
|
19
20
|
}
|
|
20
21
|
const modulePath = target.slice(0, lastColon);
|
|
21
22
|
const exportName = target.slice(lastColon + 1);
|
|
22
|
-
|
|
23
|
+
if (typeof modulePath !== 'string' || modulePath.length === 0) {
|
|
24
|
+
throw new Error(`Invalid target format: "${target}". Module path must be a non-empty string.`);
|
|
25
|
+
}
|
|
26
|
+
// When allowedPrefixes are specified, restrict to file-path imports only.
|
|
27
|
+
// node: built-ins and bare package names are not under any file prefix.
|
|
28
|
+
const isNodeBuiltin = modulePath.startsWith('node:');
|
|
23
29
|
const isFilePath = modulePath.startsWith('.') || isAbsolute(modulePath);
|
|
30
|
+
const isBarePackage = !isFilePath && !isNodeBuiltin;
|
|
31
|
+
if (allowedPrefixes != null && allowedPrefixes.length > 0 && (isNodeBuiltin || isBarePackage)) {
|
|
32
|
+
throw new Error(`Import "${modulePath}" is not allowed: only file-path imports are permitted when allowedPrefixes is set.`);
|
|
33
|
+
}
|
|
24
34
|
if (isFilePath && allowedPrefixes != null && allowedPrefixes.length > 0) {
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
let resolved = resolve(modulePath);
|
|
36
|
+
try {
|
|
37
|
+
resolved = realpathSync(resolved);
|
|
38
|
+
}
|
|
39
|
+
catch (resolveErr) {
|
|
40
|
+
const code = resolveErr.code;
|
|
41
|
+
if (code !== 'ENOENT') {
|
|
42
|
+
// Non-ENOENT errors (ELOOP, EACCES, etc.) indicate a path that cannot
|
|
43
|
+
// be safely canonicalized — reject rather than fall back to lexical resolve.
|
|
44
|
+
throw new Error(`Import path "${modulePath}" could not be canonicalized: ${resolveErr.message}`, { cause: resolveErr });
|
|
45
|
+
}
|
|
46
|
+
// ENOENT: file will be created; use lexical resolved path for prefix check.
|
|
47
|
+
}
|
|
48
|
+
const allowed = allowedPrefixes.some((prefix) => {
|
|
49
|
+
let resolvedPrefix = resolve(prefix);
|
|
50
|
+
try {
|
|
51
|
+
resolvedPrefix = realpathSync(resolvedPrefix);
|
|
52
|
+
}
|
|
53
|
+
catch { /* keep logical resolve */ }
|
|
54
|
+
return resolved === resolvedPrefix || resolved.startsWith(resolvedPrefix + sep);
|
|
55
|
+
});
|
|
27
56
|
if (!allowed) {
|
|
28
57
|
throw new Error(`Import path "${modulePath}" is not under any allowed prefix: ${allowedPrefixes.join(', ')}`);
|
|
29
58
|
}
|
|
@@ -34,7 +63,7 @@ export async function resolveTarget(target, allowedPrefixes) {
|
|
|
34
63
|
}
|
|
35
64
|
catch (err) {
|
|
36
65
|
const message = err instanceof Error ? err.message : String(err);
|
|
37
|
-
throw new Error(`Failed to import module "${modulePath}": ${message}
|
|
66
|
+
throw new Error(`Failed to import module "${modulePath}": ${message}`, { cause: err });
|
|
38
67
|
}
|
|
39
68
|
if (mod[exportName] === undefined) {
|
|
40
69
|
throw new Error(`Export "${exportName}" not found in module "${modulePath}".`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-target.js","sourceRoot":"","sources":["../src/resolve-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-target.js","sourceRoot":"","sources":["../src/resolve-target.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-keys.d.ts","sourceRoot":"","sources":["../src/safe-keys.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,MAAM,CAIzC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// JavaScript-specific prototype-pollution guard.
|
|
2
|
+
//
|
|
3
|
+
// This file has no Python or Rust counterpart: the named keys
|
|
4
|
+
// (`__proto__`, `constructor`, `prototype`) are dangerous only under
|
|
5
|
+
// JavaScript's prototype-chain semantics. Python and Rust use attribute
|
|
6
|
+
// lookups / field accesses that are not affected by this vulnerability
|
|
7
|
+
// class, so their SDKs do not need an equivalent.
|
|
8
|
+
//
|
|
9
|
+
// Typed as `Set<string>` (not the literal union inferred by `as const`) so
|
|
10
|
+
// callers can pass arbitrary user-supplied keys to `.has()` without a cast.
|
|
11
|
+
// The runtime check is what matters; the compile-time narrowing from `as const`
|
|
12
|
+
// would force every caller to pre-narrow their key type, which is impractical
|
|
13
|
+
// for keys coming out of `Object.entries`, YAML parses, or OpenAPI schemas.
|
|
14
|
+
export const PROTO_DENY = new Set([
|
|
15
|
+
'__proto__',
|
|
16
|
+
'constructor',
|
|
17
|
+
'prototype',
|
|
18
|
+
]);
|
|
19
|
+
//# sourceMappingURL=safe-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safe-keys.js","sourceRoot":"","sources":["../src/safe-keys.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,8DAA8D;AAC9D,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,kDAAkD;AAClD,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,gFAAgF;AAChF,8EAA8E;AAC9E,4EAA4E;AAC5E,MAAM,CAAC,MAAM,UAAU,GAAwB,IAAI,GAAG,CAAC;IACrD,WAAW;IACX,aAAa;IACb,WAAW;CACZ,CAAC,CAAC"}
|
package/dist/scanner.d.ts
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { ModuleAnnotations } from 'apcore-js';
|
|
2
2
|
import type { ScannedModule } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for all apcore-toolkit scanners.
|
|
5
|
+
*
|
|
6
|
+
* Subclasses implement `scan()` to produce `ScannedModule[]` from a given
|
|
7
|
+
* source (OpenAPI spec, Express router, file system, etc.). The base class
|
|
8
|
+
* provides shared utilities: docstring extraction, module ID deduplication,
|
|
9
|
+
* and pattern-based include/exclude filtering.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* class MyScanner extends BaseScanner {
|
|
13
|
+
* scan(spec: OpenAPISpec): ScannedModule[] { ... }
|
|
14
|
+
* getSourceName(): string { return 'my-scanner'; }
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
3
17
|
export declare abstract class BaseScanner {
|
|
4
18
|
abstract scan(...args: unknown[]): ScannedModule[] | Promise<ScannedModule[]>;
|
|
5
19
|
abstract getSourceName(): string;
|
|
@@ -8,6 +22,14 @@ export declare abstract class BaseScanner {
|
|
|
8
22
|
documentation: string | null;
|
|
9
23
|
params: Record<string, string>;
|
|
10
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Apply include/exclude regex filters to a list of scanned modules.
|
|
27
|
+
*
|
|
28
|
+
* @param modules - Modules to filter.
|
|
29
|
+
* @param options - Optional `include` and/or `exclude` regex pattern strings.
|
|
30
|
+
* @returns Filtered array of modules.
|
|
31
|
+
* @throws {SyntaxError} When `include` or `exclude` contain an invalid regex pattern.
|
|
32
|
+
*/
|
|
11
33
|
filterModules(modules: ScannedModule[], options?: {
|
|
12
34
|
include?: string;
|
|
13
35
|
exclude?: string;
|
package/dist/scanner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD;;;;;;;;;;;;;GAaG;AACH,8BAAsB,WAAW;IAC/B,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAC7E,QAAQ,CAAC,aAAa,IAAI,MAAM;IAEhC,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG;QAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KAChC;IAwCD;;;;;;;OAOG;IACH,aAAa,CACX,OAAO,EAAE,aAAa,EAAE,EACxB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/C,aAAa,EAAE;IAgBlB,MAAM,CAAC,0BAA0B,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB;IAiBpE,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,aAAa,EAAE;CAoC1D"}
|
package/dist/scanner.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { DEFAULT_ANNOTATIONS } from 'apcore-js';
|
|
2
2
|
import { cloneModule } from './types.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Abstract base class for all apcore-toolkit scanners.
|
|
5
|
+
*
|
|
6
|
+
* Subclasses implement `scan()` to produce `ScannedModule[]` from a given
|
|
7
|
+
* source (OpenAPI spec, Express router, file system, etc.). The base class
|
|
8
|
+
* provides shared utilities: docstring extraction, module ID deduplication,
|
|
9
|
+
* and pattern-based include/exclude filtering.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* class MyScanner extends BaseScanner {
|
|
13
|
+
* scan(spec: OpenAPISpec): ScannedModule[] { ... }
|
|
14
|
+
* getSourceName(): string { return 'my-scanner'; }
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
12
17
|
export class BaseScanner {
|
|
13
18
|
extractDocstring(func) {
|
|
14
19
|
if (func == null || typeof func !== 'function') {
|
|
@@ -16,7 +21,7 @@ export class BaseScanner {
|
|
|
16
21
|
}
|
|
17
22
|
// Extract JSDoc-style documentation from function's toString representation
|
|
18
23
|
const source = func.toString();
|
|
19
|
-
const jsdocMatch = source.match(
|
|
24
|
+
const jsdocMatch = source.match(/^\/\*\*([\s\S]*?)\*\//);
|
|
20
25
|
if (!jsdocMatch) {
|
|
21
26
|
return { description: null, documentation: null, params: {} };
|
|
22
27
|
}
|
|
@@ -46,19 +51,29 @@ export class BaseScanner {
|
|
|
46
51
|
const documentation = descLines.length > 1 ? descLines.join('\n') : null;
|
|
47
52
|
return { description, documentation, params };
|
|
48
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Apply include/exclude regex filters to a list of scanned modules.
|
|
56
|
+
*
|
|
57
|
+
* @param modules - Modules to filter.
|
|
58
|
+
* @param options - Optional `include` and/or `exclude` regex pattern strings.
|
|
59
|
+
* @returns Filtered array of modules.
|
|
60
|
+
* @throws {SyntaxError} When `include` or `exclude` contain an invalid regex pattern.
|
|
61
|
+
*/
|
|
49
62
|
filterModules(modules, options) {
|
|
50
63
|
let result = modules;
|
|
51
64
|
if (options?.include != null) {
|
|
52
|
-
const re =
|
|
65
|
+
const re = new RegExp(options.include);
|
|
53
66
|
result = result.filter((m) => re.test(m.moduleId));
|
|
54
67
|
}
|
|
55
68
|
if (options?.exclude != null) {
|
|
56
|
-
const re =
|
|
69
|
+
const re = new RegExp(options.exclude);
|
|
57
70
|
result = result.filter((m) => !re.test(m.moduleId));
|
|
58
71
|
}
|
|
59
72
|
return result;
|
|
60
73
|
}
|
|
61
74
|
static inferAnnotationsFromMethod(method) {
|
|
75
|
+
if (typeof method !== 'string')
|
|
76
|
+
return { ...DEFAULT_ANNOTATIONS };
|
|
62
77
|
const upper = method.toUpperCase();
|
|
63
78
|
if (upper === 'GET') {
|
|
64
79
|
return { ...DEFAULT_ANNOTATIONS, readonly: true, cacheable: true };
|
|
@@ -72,14 +87,23 @@ export class BaseScanner {
|
|
|
72
87
|
return { ...DEFAULT_ANNOTATIONS };
|
|
73
88
|
}
|
|
74
89
|
deduplicateIds(modules) {
|
|
75
|
-
const
|
|
90
|
+
const seenCount = new Map();
|
|
91
|
+
// Pre-populate with all original IDs so generated suffixes never collide
|
|
92
|
+
// with an ID that already exists in the input list.
|
|
93
|
+
const usedIds = new Set(modules.map((m) => m.moduleId));
|
|
76
94
|
const result = [];
|
|
77
95
|
for (const module of modules) {
|
|
78
96
|
const mid = module.moduleId;
|
|
79
|
-
const count =
|
|
80
|
-
|
|
97
|
+
const count = seenCount.get(mid) ?? 0;
|
|
98
|
+
seenCount.set(mid, count + 1);
|
|
81
99
|
if (count > 0) {
|
|
82
|
-
|
|
100
|
+
let counter = count + 1;
|
|
101
|
+
let newId = `${mid}_${counter}`;
|
|
102
|
+
while (usedIds.has(newId)) {
|
|
103
|
+
counter++;
|
|
104
|
+
newId = `${mid}_${counter}`;
|
|
105
|
+
}
|
|
106
|
+
usedIds.add(newId);
|
|
83
107
|
result.push(cloneModule(module, {
|
|
84
108
|
moduleId: newId,
|
|
85
109
|
warnings: [
|