@mcpmake/core 0.2.4 → 0.3.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/analyzer/dom-parser.d.ts +35 -0
- package/dist/analyzer/dom-parser.d.ts.map +1 -1
- package/dist/analyzer/dom-parser.js +107 -6
- package/dist/analyzer/dom-parser.js.map +1 -1
- package/dist/analyzer/goal-crawler.d.ts +2 -1
- package/dist/analyzer/goal-crawler.d.ts.map +1 -1
- package/dist/analyzer/goal-crawler.js +66 -17
- package/dist/analyzer/goal-crawler.js.map +1 -1
- package/dist/analyzer/semantic-analyzer.d.ts +1 -1
- package/dist/analyzer/semantic-analyzer.d.ts.map +1 -1
- package/dist/analyzer/semantic-analyzer.js +15 -16
- package/dist/analyzer/semantic-analyzer.js.map +1 -1
- package/dist/analyzer/site-crawler.d.ts.map +1 -1
- package/dist/analyzer/site-crawler.js +122 -16
- package/dist/analyzer/site-crawler.js.map +1 -1
- package/dist/config/mcpmake-config.d.ts.map +1 -1
- package/dist/config/mcpmake-config.js +5 -0
- package/dist/config/mcpmake-config.js.map +1 -1
- package/dist/emitter/code-writer.d.ts +1 -0
- package/dist/emitter/code-writer.d.ts.map +1 -1
- package/dist/emitter/code-writer.js +79 -12
- package/dist/emitter/code-writer.js.map +1 -1
- package/dist/emitter/index.d.ts +8 -0
- package/dist/emitter/index.d.ts.map +1 -1
- package/dist/emitter/index.js +113 -6
- package/dist/emitter/index.js.map +1 -1
- package/dist/emitter/project-scaffolder.d.ts +13 -0
- package/dist/emitter/project-scaffolder.d.ts.map +1 -1
- package/dist/emitter/project-scaffolder.js +29 -0
- package/dist/emitter/project-scaffolder.js.map +1 -1
- package/dist/emitter/python-template-loader.d.ts.map +1 -1
- package/dist/emitter/python-template-loader.js +10 -0
- package/dist/emitter/python-template-loader.js.map +1 -1
- package/dist/emitter/python-templates/dockerfile.hbs +4 -1
- package/dist/emitter/python-templates/server.py.hbs +82 -8
- package/dist/emitter/site-scaffolder.d.ts.map +1 -1
- package/dist/emitter/site-scaffolder.js +28 -1
- package/dist/emitter/site-scaffolder.js.map +1 -1
- package/dist/emitter/site-templates/browser-manager.ts.hbs +104 -34
- package/dist/emitter/site-templates/dockerfile.hbs +13 -4
- package/dist/emitter/site-templates/env.example.hbs +8 -0
- package/dist/emitter/site-templates/server-main-http.ts.hbs +77 -6
- package/dist/emitter/site-templates/telemetry.ts.hbs +117 -0
- package/dist/emitter/site-templates/tool-handler-form.ts.hbs +10 -8
- package/dist/emitter/template-loader.d.ts.map +1 -1
- package/dist/emitter/template-loader.js +9 -0
- package/dist/emitter/template-loader.js.map +1 -1
- package/dist/emitter/templates/auth-provider.ts.hbs +86 -21
- package/dist/emitter/templates/config.ts.hbs +29 -0
- package/dist/emitter/templates/dockerfile.hbs +12 -4
- package/dist/emitter/templates/env.example.hbs +6 -0
- package/dist/emitter/templates/http-executor.ts.hbs +150 -7
- package/dist/emitter/templates/oauth.ts.hbs +19 -65
- package/dist/emitter/templates/server-main-http.ts.hbs +93 -12
- package/dist/emitter/templates/task-handlers.ts.hbs +40 -1
- package/dist/emitter/templates/tool-handler.ts.hbs +37 -2
- package/dist/emitter/templates/tool-test.ts.hbs +9 -1
- package/dist/emitter/worker-templates/config.ts.hbs +7 -0
- package/dist/emitter/worker-templates/tool-handler.ts.hbs +37 -2
- package/dist/emitter/worker-templates/worker.ts.hbs +119 -25
- package/dist/generator/spec-generator.d.ts.map +1 -1
- package/dist/generator/spec-generator.js +9 -54
- package/dist/generator/spec-generator.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/anthropic-provider.d.ts +14 -0
- package/dist/llm/anthropic-provider.d.ts.map +1 -0
- package/dist/llm/anthropic-provider.js +50 -0
- package/dist/llm/anthropic-provider.js.map +1 -0
- package/dist/llm/index.d.ts +19 -0
- package/dist/llm/index.d.ts.map +1 -0
- package/dist/llm/index.js +73 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +46 -0
- package/dist/llm/openai-provider.d.ts.map +1 -0
- package/dist/llm/openai-provider.js +221 -0
- package/dist/llm/openai-provider.js.map +1 -0
- package/dist/llm/types.d.ts +61 -0
- package/dist/llm/types.d.ts.map +1 -0
- package/dist/llm/types.js +16 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/parser/har-filter.d.ts +7 -0
- package/dist/parser/har-filter.d.ts.map +1 -1
- package/dist/parser/har-filter.js +107 -1
- package/dist/parser/har-filter.js.map +1 -1
- package/dist/parser/index.d.ts +1 -1
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +1 -1
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/openapi-loader.d.ts.map +1 -1
- package/dist/parser/openapi-loader.js +36 -2
- package/dist/parser/openapi-loader.js.map +1 -1
- package/dist/parser/operation-extractor.d.ts.map +1 -1
- package/dist/parser/operation-extractor.js +12 -1
- package/dist/parser/operation-extractor.js.map +1 -1
- package/dist/parser/overlay-loader.d.ts.map +1 -1
- package/dist/parser/overlay-loader.js +11 -2
- package/dist/parser/overlay-loader.js.map +1 -1
- package/dist/parser/postman-loader.d.ts.map +1 -1
- package/dist/parser/postman-loader.js +6 -1
- package/dist/parser/postman-loader.js.map +1 -1
- package/dist/parser/schema-converter.d.ts +13 -2
- package/dist/parser/schema-converter.d.ts.map +1 -1
- package/dist/parser/schema-converter.js +64 -42
- package/dist/parser/schema-converter.js.map +1 -1
- package/dist/plugins/loader.d.ts +5 -1
- package/dist/plugins/loader.d.ts.map +1 -1
- package/dist/plugins/loader.js +39 -10
- package/dist/plugins/loader.js.map +1 -1
- package/dist/pricing.d.ts +5 -1
- package/dist/pricing.d.ts.map +1 -1
- package/dist/pricing.js +7 -3
- package/dist/pricing.js.map +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +6 -21
- package/dist/providers/index.js.map +1 -1
- package/dist/recorder/browser-recorder.d.ts.map +1 -1
- package/dist/recorder/browser-recorder.js +89 -12
- package/dist/recorder/browser-recorder.js.map +1 -1
- package/dist/rescan/rescan-scheduler.d.ts.map +1 -1
- package/dist/rescan/rescan-scheduler.js +22 -7
- package/dist/rescan/rescan-scheduler.js.map +1 -1
- package/dist/site-transformer/selector-healer.d.ts +1 -1
- package/dist/site-transformer/selector-healer.d.ts.map +1 -1
- package/dist/site-transformer/selector-healer.js +17 -18
- package/dist/site-transformer/selector-healer.js.map +1 -1
- package/dist/site-transformer/tool-generator.d.ts.map +1 -1
- package/dist/site-transformer/tool-generator.js +90 -22
- package/dist/site-transformer/tool-generator.js.map +1 -1
- package/dist/transformer/auth-detector.d.ts.map +1 -1
- package/dist/transformer/auth-detector.js +24 -5
- package/dist/transformer/auth-detector.js.map +1 -1
- package/dist/transformer/har-schema-inferrer.d.ts.map +1 -1
- package/dist/transformer/har-schema-inferrer.js +2 -0
- package/dist/transformer/har-schema-inferrer.js.map +1 -1
- package/dist/transformer/har-to-operations.d.ts +1 -0
- package/dist/transformer/har-to-operations.d.ts.map +1 -1
- package/dist/transformer/har-to-operations.js +42 -10
- package/dist/transformer/har-to-operations.js.map +1 -1
- package/dist/transformer/llm-namer.d.ts.map +1 -1
- package/dist/transformer/llm-namer.js +10 -13
- package/dist/transformer/llm-namer.js.map +1 -1
- package/dist/transformer/naming.d.ts.map +1 -1
- package/dist/transformer/naming.js +16 -8
- package/dist/transformer/naming.js.map +1 -1
- package/dist/transformer/resource-builder.d.ts.map +1 -1
- package/dist/transformer/resource-builder.js +13 -6
- package/dist/transformer/resource-builder.js.map +1 -1
- package/dist/transformer/stainless-translator.d.ts +6 -0
- package/dist/transformer/stainless-translator.d.ts.map +1 -1
- package/dist/transformer/stainless-translator.js +18 -1
- package/dist/transformer/stainless-translator.js.map +1 -1
- package/dist/transformer/tool-builder.d.ts.map +1 -1
- package/dist/transformer/tool-builder.js +141 -14
- package/dist/transformer/tool-builder.js.map +1 -1
- package/dist/types/index.d.ts +79 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/site.d.ts +19 -1
- package/dist/types/site.d.ts.map +1 -1
- package/dist/utils/fail.d.ts.map +1 -1
- package/dist/utils/fail.js +22 -4
- package/dist/utils/fail.js.map +1 -1
- package/dist/utils/json-extract.d.ts +21 -0
- package/dist/utils/json-extract.d.ts.map +1 -0
- package/dist/utils/json-extract.js +67 -0
- package/dist/utils/json-extract.js.map +1 -0
- package/dist/utils/model-resolver.d.ts.map +1 -1
- package/dist/utils/model-resolver.js +6 -0
- package/dist/utils/model-resolver.js.map +1 -1
- package/dist/utils/sanitize.d.ts +63 -1
- package/dist/utils/sanitize.d.ts.map +1 -1
- package/dist/utils/sanitize.js +147 -2
- package/dist/utils/sanitize.js.map +1 -1
- package/dist/utils/ssrf-guard.d.ts +10 -0
- package/dist/utils/ssrf-guard.d.ts.map +1 -0
- package/dist/utils/ssrf-guard.js +130 -0
- package/dist/utils/ssrf-guard.js.map +1 -0
- package/dist/utils/watcher.d.ts +17 -1
- package/dist/utils/watcher.d.ts.map +1 -1
- package/dist/utils/watcher.js +53 -21
- package/dist/utils/watcher.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-extract.js","sourceRoot":"","sources":["../../src/utils/json-extract.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;GAIG;AACH,SAAS,eAAe,CAAC,IAAY,EAAE,IAAY,EAAE,KAAa;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,KAAK,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,OAAO;gBAAE,OAAO,GAAG,KAAK,CAAC;iBACxB,IAAI,EAAE,KAAK,IAAI;gBAAE,OAAO,GAAG,IAAI,CAAC;iBAChC,IAAI,EAAE,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAC;QACxC,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;YACvB,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;YACxB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAEnC,IAAI,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,KAAK,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpD,kEAAkE;IAClE,MAAM,QAAQ,GAAG,QAAQ,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAE7E,OAAO,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACtF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/model-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAG/C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAqB5C;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/model-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAG/C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;AAqB5C;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,EACf,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CA4CjB"}
|
|
@@ -56,8 +56,14 @@ export async function resolveModel(client, tier, override) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
catch (err) {
|
|
59
|
+
// Transient Models API failure: return the fallback for this call WITHOUT
|
|
60
|
+
// caching it, so a later call retries once the API recovers (a poisoned
|
|
61
|
+
// cache would pin the whole process to the fallback alias).
|
|
59
62
|
logger.warn(`Could not list models (${err instanceof Error ? err.message : err}); using "${preferred}"`);
|
|
63
|
+
return preferred;
|
|
60
64
|
}
|
|
65
|
+
// Only successful resolutions are cached — the served-model list rarely
|
|
66
|
+
// changes mid-run, so one API round-trip per tier is enough.
|
|
61
67
|
cache.set(tier, choice);
|
|
62
68
|
return choice;
|
|
63
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/utils/model-resolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC;;;;GAIG;AACH,MAAM,SAAS,GAA8B;IAC3C,QAAQ,EAAE,mBAAmB;IAC7B,IAAI,EAAE,kBAAkB;CACzB,CAAC;AAEF,MAAM,YAAY,GAA8B;IAC9C,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,2EAA2E;AAC3E,wEAAwE;AACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAiB,EACjB,IAAe,EACf,QAAiB;IAEjB,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,SAAS,CAAC;IAEvB,IAAI,CAAC;QACH,MAAM,MAAM,GAA+D,EAAE,CAAC;QAC9E,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM;iBAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBAClE,yEAAyE;iBACxE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,oBAAoB,SAAS,yBAAyB,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;gBAChF,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CACT,oBAAoB,SAAS,wBAAwB,IAAI,gCAAgC,CAC1F,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CACT,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,SAAS,GAAG,CAC5F,CAAC;
|
|
1
|
+
{"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/utils/model-resolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AASrC;;;;GAIG;AACH,MAAM,SAAS,GAA8B;IAC3C,QAAQ,EAAE,mBAAmB;IAC7B,IAAI,EAAE,kBAAkB;CACzB,CAAC;AAEF,MAAM,YAAY,GAA8B;IAC9C,QAAQ,EAAE,SAAS;IACnB,IAAI,EAAE,QAAQ;CACf,CAAC;AAEF,2EAA2E;AAC3E,wEAAwE;AACxE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAqB,CAAC;AAE3C;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAiB,EACjB,IAAe,EACf,QAAiB;IAEjB,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,SAAS,CAAC;IAEvB,IAAI,CAAC;QACH,MAAM,MAAM,GAA+D,EAAE,CAAC;QAC9E,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,MAAM;iBAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBAClE,yEAAyE;iBACxE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,oBAAoB,SAAS,yBAAyB,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;gBAChF,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,CACT,oBAAoB,SAAS,wBAAwB,IAAI,gCAAgC,CAC1F,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0EAA0E;QAC1E,wEAAwE;QACxE,4DAA4D;QAC5D,MAAM,CAAC,IAAI,CACT,0BAA0B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,aAAa,SAAS,GAAG,CAC5F,CAAC;QACF,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,wEAAwE;IACxE,6DAA6D;IAC7D,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/utils/sanitize.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sanitize a string for safe embedding in a JavaScript/TypeScript single-quoted string literal.
|
|
3
|
-
* Escapes backslashes, single quotes, and
|
|
3
|
+
* Escapes backslashes, single quotes, and CR/LF.
|
|
4
4
|
*/
|
|
5
5
|
export declare function escapeStringLiteral(str: string): string;
|
|
6
6
|
/**
|
|
@@ -13,6 +13,68 @@ export declare function escapeTemplateLiteral(str: string): string;
|
|
|
13
13
|
* Strips anything that isn't alphanumeric, underscore, or hyphen.
|
|
14
14
|
*/
|
|
15
15
|
export declare function sanitizeIdentifier(str: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Sanitize an HTTP header name (e.g. an apiKey scheme `name`) for safe embedding
|
|
18
|
+
* in a string literal. Real header names are RFC 7230 tokens; in practice API
|
|
19
|
+
* key headers are `[A-Za-z0-9-]` (plus `_`). Stripping everything else removes
|
|
20
|
+
* quotes/backticks/newlines that could break out of the generated literal.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sanitizeHeaderName(str: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Sanitize an environment-variable name. It is emitted both as a quoted string
|
|
25
|
+
* and as a bare member access (`process.env.<NAME>` / `env.<NAME>`), so it must
|
|
26
|
+
* be a valid JS/POSIX identifier. Strips invalid chars and prefixes `_` when the
|
|
27
|
+
* result would start with a digit or be empty.
|
|
28
|
+
*/
|
|
29
|
+
export declare function sanitizeEnvVarName(str: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* Resolve OpenAPI server-variable placeholders (`{var}`) in a server URL from
|
|
32
|
+
* their declared defaults, then validate the result is a real http(s) URL.
|
|
33
|
+
*
|
|
34
|
+
* OpenAPI server URLs may carry variables — `https://{region}.api.test/{version}`
|
|
35
|
+
* — with a `variables` map giving each a `default`. Substituting them here keeps
|
|
36
|
+
* the URL semantically intact instead of stripping the braces (which would corrupt
|
|
37
|
+
* the path, e.g. `{version}` → empty). Variables without a known default are left
|
|
38
|
+
* as-is; the subsequent per-sink escaper neutralizes any residual unsafe chars.
|
|
39
|
+
*/
|
|
40
|
+
export declare function resolveServerUrl(url: string, variables?: Record<string, {
|
|
41
|
+
default?: string;
|
|
42
|
+
} | undefined>): string;
|
|
43
|
+
/**
|
|
44
|
+
* Escape a base URL for safe embedding in a string literal across multiple
|
|
45
|
+
* target languages without mutating its semantics. Unlike a strip-based
|
|
46
|
+
* approach, this preserves every character that is legal in a URL (including
|
|
47
|
+
* `$`, `{`, `}`, `~`, etc. that appear in real paths such as `/v1/$metadata`)
|
|
48
|
+
* and only neutralizes the characters that could break out of, or inject into,
|
|
49
|
+
* the literal it is embedded in:
|
|
50
|
+
* - backslash, single/double quote, backtick → backslash-escaped
|
|
51
|
+
* - `${` (TS template-literal interpolation) → broken with a backslash
|
|
52
|
+
* - CR/LF (could inject extra dotenv/TOML lines) → backslash-escaped
|
|
53
|
+
* The same escaped form is safe in a TS single/double-quote string, a TS
|
|
54
|
+
* backtick literal, a Python double-quote string, a TOML basic string, and a
|
|
55
|
+
* single-line dotenv value. Validation/variable-resolution happens upstream in
|
|
56
|
+
* the emitter via {@link resolveServerUrl}.
|
|
57
|
+
*/
|
|
58
|
+
export declare function sanitizeUrlLiteral(str: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Validate a request-body media type against the RFC media-type grammar
|
|
61
|
+
* (`type/subtype`, optional parameters). The OpenAPI `content` map key is
|
|
62
|
+
* attacker-influenced and is interpolated into a string literal, so a value
|
|
63
|
+
* that is not a well-formed media type is replaced with `application/json`
|
|
64
|
+
* (the universal safe default) rather than trusted. The returned value is
|
|
65
|
+
* still escaped at the literal sink by {@link escapeStringLiteral}.
|
|
66
|
+
*/
|
|
67
|
+
export declare function sanitizeMediaType(str: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Escape a string for safe embedding in a double-quoted Python string literal.
|
|
70
|
+
* Escapes backslashes, double quotes, and newlines.
|
|
71
|
+
*/
|
|
72
|
+
export declare function escapePyString(str: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Convert an arbitrary parameter name into a valid, non-keyword Python
|
|
75
|
+
* identifier for use as a function argument or local variable name.
|
|
76
|
+
*/
|
|
77
|
+
export declare function sanitizePyIdentifier(str: string): string;
|
|
16
78
|
/**
|
|
17
79
|
* Validate that a URL path template contains only safe characters.
|
|
18
80
|
* Allows: alphanumeric, /, {, }, -, _, .
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,GAC3D,MAAM,CAUR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAStD;AAMD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlD;AA0CD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAExD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKpD;AAID;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
package/dist/utils/sanitize.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Sanitize a string for safe embedding in a JavaScript/TypeScript single-quoted string literal.
|
|
3
|
-
* Escapes backslashes, single quotes, and
|
|
3
|
+
* Escapes backslashes, single quotes, and CR/LF.
|
|
4
4
|
*/
|
|
5
5
|
export function escapeStringLiteral(str) {
|
|
6
|
-
return str
|
|
6
|
+
return str
|
|
7
|
+
.replace(/\\/g, '\\\\')
|
|
8
|
+
.replace(/'/g, "\\'")
|
|
9
|
+
.replace(/\n/g, '\\n')
|
|
10
|
+
.replace(/\r/g, '\\r');
|
|
7
11
|
}
|
|
8
12
|
/**
|
|
9
13
|
* Sanitize a string for safe embedding in a JavaScript/TypeScript template literal.
|
|
@@ -19,6 +23,147 @@ export function escapeTemplateLiteral(str) {
|
|
|
19
23
|
export function sanitizeIdentifier(str) {
|
|
20
24
|
return str.replace(/[^a-zA-Z0-9_\-]/g, '');
|
|
21
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Sanitize an HTTP header name (e.g. an apiKey scheme `name`) for safe embedding
|
|
28
|
+
* in a string literal. Real header names are RFC 7230 tokens; in practice API
|
|
29
|
+
* key headers are `[A-Za-z0-9-]` (plus `_`). Stripping everything else removes
|
|
30
|
+
* quotes/backticks/newlines that could break out of the generated literal.
|
|
31
|
+
*/
|
|
32
|
+
export function sanitizeHeaderName(str) {
|
|
33
|
+
return str.replace(/[^A-Za-z0-9_\-]/g, '');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Sanitize an environment-variable name. It is emitted both as a quoted string
|
|
37
|
+
* and as a bare member access (`process.env.<NAME>` / `env.<NAME>`), so it must
|
|
38
|
+
* be a valid JS/POSIX identifier. Strips invalid chars and prefixes `_` when the
|
|
39
|
+
* result would start with a digit or be empty.
|
|
40
|
+
*/
|
|
41
|
+
export function sanitizeEnvVarName(str) {
|
|
42
|
+
const cleaned = str.replace(/[^A-Za-z0-9_]/g, '');
|
|
43
|
+
return /^[A-Za-z_]/.test(cleaned) ? cleaned : `_${cleaned}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolve OpenAPI server-variable placeholders (`{var}`) in a server URL from
|
|
47
|
+
* their declared defaults, then validate the result is a real http(s) URL.
|
|
48
|
+
*
|
|
49
|
+
* OpenAPI server URLs may carry variables — `https://{region}.api.test/{version}`
|
|
50
|
+
* — with a `variables` map giving each a `default`. Substituting them here keeps
|
|
51
|
+
* the URL semantically intact instead of stripping the braces (which would corrupt
|
|
52
|
+
* the path, e.g. `{version}` → empty). Variables without a known default are left
|
|
53
|
+
* as-is; the subsequent per-sink escaper neutralizes any residual unsafe chars.
|
|
54
|
+
*/
|
|
55
|
+
export function resolveServerUrl(url, variables) {
|
|
56
|
+
if (!url)
|
|
57
|
+
return url;
|
|
58
|
+
let resolved = url;
|
|
59
|
+
if (variables) {
|
|
60
|
+
resolved = resolved.replace(/\{([^{}]+)\}/g, (match, name) => {
|
|
61
|
+
const def = variables[name]?.default;
|
|
62
|
+
return typeof def === 'string' ? def : match;
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return resolved;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Escape a base URL for safe embedding in a string literal across multiple
|
|
69
|
+
* target languages without mutating its semantics. Unlike a strip-based
|
|
70
|
+
* approach, this preserves every character that is legal in a URL (including
|
|
71
|
+
* `$`, `{`, `}`, `~`, etc. that appear in real paths such as `/v1/$metadata`)
|
|
72
|
+
* and only neutralizes the characters that could break out of, or inject into,
|
|
73
|
+
* the literal it is embedded in:
|
|
74
|
+
* - backslash, single/double quote, backtick → backslash-escaped
|
|
75
|
+
* - `${` (TS template-literal interpolation) → broken with a backslash
|
|
76
|
+
* - CR/LF (could inject extra dotenv/TOML lines) → backslash-escaped
|
|
77
|
+
* The same escaped form is safe in a TS single/double-quote string, a TS
|
|
78
|
+
* backtick literal, a Python double-quote string, a TOML basic string, and a
|
|
79
|
+
* single-line dotenv value. Validation/variable-resolution happens upstream in
|
|
80
|
+
* the emitter via {@link resolveServerUrl}.
|
|
81
|
+
*/
|
|
82
|
+
export function sanitizeUrlLiteral(str) {
|
|
83
|
+
return str
|
|
84
|
+
.replace(/\\/g, '\\\\')
|
|
85
|
+
.replace(/`/g, '\\`')
|
|
86
|
+
.replace(/'/g, "\\'")
|
|
87
|
+
.replace(/"/g, '\\"')
|
|
88
|
+
.replace(/\$\{/g, '\\${')
|
|
89
|
+
.replace(/\r/g, '\\r')
|
|
90
|
+
.replace(/\n/g, '\\n');
|
|
91
|
+
}
|
|
92
|
+
/** RFC 6838 / RFC 7231 media-type token: `type/subtype` with optional params. */
|
|
93
|
+
const MEDIA_TYPE_RE = /^[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*\/[A-Za-z0-9][A-Za-z0-9!#$&^_.+-]*(\s*;\s*[^\s;]+)*$/;
|
|
94
|
+
/**
|
|
95
|
+
* Validate a request-body media type against the RFC media-type grammar
|
|
96
|
+
* (`type/subtype`, optional parameters). The OpenAPI `content` map key is
|
|
97
|
+
* attacker-influenced and is interpolated into a string literal, so a value
|
|
98
|
+
* that is not a well-formed media type is replaced with `application/json`
|
|
99
|
+
* (the universal safe default) rather than trusted. The returned value is
|
|
100
|
+
* still escaped at the literal sink by {@link escapeStringLiteral}.
|
|
101
|
+
*/
|
|
102
|
+
export function sanitizeMediaType(str) {
|
|
103
|
+
return MEDIA_TYPE_RE.test(str.trim()) ? str.trim() : 'application/json';
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Escape a string for safe embedding in a double-quoted Python string literal.
|
|
107
|
+
* Escapes backslashes, double quotes, and newlines.
|
|
108
|
+
*/
|
|
109
|
+
export function escapePyString(str) {
|
|
110
|
+
return str
|
|
111
|
+
.replace(/\\/g, '\\\\')
|
|
112
|
+
.replace(/"/g, '\\"')
|
|
113
|
+
.replace(/\n/g, '\\n')
|
|
114
|
+
.replace(/\r/g, '\\r');
|
|
115
|
+
}
|
|
116
|
+
const PY_KEYWORDS = new Set([
|
|
117
|
+
'False',
|
|
118
|
+
'None',
|
|
119
|
+
'True',
|
|
120
|
+
'and',
|
|
121
|
+
'as',
|
|
122
|
+
'assert',
|
|
123
|
+
'async',
|
|
124
|
+
'await',
|
|
125
|
+
'break',
|
|
126
|
+
'class',
|
|
127
|
+
'continue',
|
|
128
|
+
'def',
|
|
129
|
+
'del',
|
|
130
|
+
'elif',
|
|
131
|
+
'else',
|
|
132
|
+
'except',
|
|
133
|
+
'finally',
|
|
134
|
+
'for',
|
|
135
|
+
'from',
|
|
136
|
+
'global',
|
|
137
|
+
'if',
|
|
138
|
+
'import',
|
|
139
|
+
'in',
|
|
140
|
+
'is',
|
|
141
|
+
'lambda',
|
|
142
|
+
'nonlocal',
|
|
143
|
+
'not',
|
|
144
|
+
'or',
|
|
145
|
+
'pass',
|
|
146
|
+
'raise',
|
|
147
|
+
'return',
|
|
148
|
+
'try',
|
|
149
|
+
'while',
|
|
150
|
+
'with',
|
|
151
|
+
'yield',
|
|
152
|
+
'match',
|
|
153
|
+
'case',
|
|
154
|
+
]);
|
|
155
|
+
/**
|
|
156
|
+
* Convert an arbitrary parameter name into a valid, non-keyword Python
|
|
157
|
+
* identifier for use as a function argument or local variable name.
|
|
158
|
+
*/
|
|
159
|
+
export function sanitizePyIdentifier(str) {
|
|
160
|
+
let id = str.replace(/[^A-Za-z0-9_]/g, '_');
|
|
161
|
+
if (!/^[A-Za-z_]/.test(id))
|
|
162
|
+
id = `_${id}`;
|
|
163
|
+
if (PY_KEYWORDS.has(id))
|
|
164
|
+
id = `${id}_`;
|
|
165
|
+
return id || '_param';
|
|
166
|
+
}
|
|
22
167
|
/**
|
|
23
168
|
* Validate that a URL path template contains only safe characters.
|
|
24
169
|
* Allows: alphanumeric, /, {, }, -, _, .
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/utils/sanitize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function privateHostsAllowed(): boolean;
|
|
2
|
+
/** Whether `ip` (a literal IPv4 or IPv6 address) is private, loopback, or reserved. */
|
|
3
|
+
export declare function isPrivateOrReservedIp(ip: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Throw if `urlString` is not a public http(s) URL. Resolves the host via DNS and
|
|
6
|
+
* rejects when any resolved address is private/loopback/link-local/reserved.
|
|
7
|
+
* Honors the `MCPMAKE_ALLOW_PRIVATE_HOSTS` escape hatch.
|
|
8
|
+
*/
|
|
9
|
+
export declare function assertPublicUrl(urlString: string): Promise<void>;
|
|
10
|
+
//# sourceMappingURL=ssrf-guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-guard.d.ts","sourceRoot":"","sources":["../../src/utils/ssrf-guard.ts"],"names":[],"mappings":"AAyBA,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AA0CD,uFAAuF;AACvF,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAKzD;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA0CtE"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { isIP } from 'node:net';
|
|
2
|
+
import { lookup } from 'node:dns/promises';
|
|
3
|
+
/**
|
|
4
|
+
* SSRF guard for outbound requests driven by untrusted input — crawled links,
|
|
5
|
+
* recorded navigations, and remote OpenAPI spec/`$ref` URLs.
|
|
6
|
+
*
|
|
7
|
+
* The browser crawler/recorder and the spec loader all fetch URLs that originate
|
|
8
|
+
* from user input or from an LLM/page following links. Without a host check they
|
|
9
|
+
* can be steered at `localhost`, RFC1918 intranets, or the cloud metadata
|
|
10
|
+
* endpoint (`169.254.169.254`). This module resolves a URL's host and rejects
|
|
11
|
+
* any that points at a private, loopback, link-local, or otherwise reserved
|
|
12
|
+
* address.
|
|
13
|
+
*
|
|
14
|
+
* Residual limitation (documented, not closed here): this checks at request time
|
|
15
|
+
* but does not pin DNS at the socket, so a TOCTOU/DNS-rebinding attacker who
|
|
16
|
+
* flips a record between this lookup and the browser's own connect can still slip
|
|
17
|
+
* through. Full DNS-pinning would require intercepting at the socket layer.
|
|
18
|
+
*
|
|
19
|
+
* Escape hatch: set `MCPMAKE_ALLOW_PRIVATE_HOSTS=1` to allow private/loopback
|
|
20
|
+
* targets (local development against `localhost` test servers).
|
|
21
|
+
*/
|
|
22
|
+
const ALLOW_ENV = 'MCPMAKE_ALLOW_PRIVATE_HOSTS';
|
|
23
|
+
export function privateHostsAllowed() {
|
|
24
|
+
return process.env[ALLOW_ENV] === '1' || process.env[ALLOW_ENV] === 'true';
|
|
25
|
+
}
|
|
26
|
+
/** Parse a dotted-quad IPv4 string into its four octets, or null if malformed. */
|
|
27
|
+
function ipv4Octets(ip) {
|
|
28
|
+
const parts = ip.split('.');
|
|
29
|
+
if (parts.length !== 4)
|
|
30
|
+
return null;
|
|
31
|
+
const nums = parts.map((p) => Number(p));
|
|
32
|
+
if (nums.some((n) => !Number.isInteger(n) || n < 0 || n > 255))
|
|
33
|
+
return null;
|
|
34
|
+
return nums;
|
|
35
|
+
}
|
|
36
|
+
function isPrivateIpv4(ip) {
|
|
37
|
+
const o = ipv4Octets(ip);
|
|
38
|
+
if (!o)
|
|
39
|
+
return false;
|
|
40
|
+
const [a, b] = o;
|
|
41
|
+
if (a === 0)
|
|
42
|
+
return true; // 0.0.0.0/8 "this network"
|
|
43
|
+
if (a === 10)
|
|
44
|
+
return true; // 10.0.0.0/8 private
|
|
45
|
+
if (a === 127)
|
|
46
|
+
return true; // 127.0.0.0/8 loopback
|
|
47
|
+
if (a === 169 && b === 254)
|
|
48
|
+
return true; // 169.254.0.0/16 link-local (cloud metadata)
|
|
49
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
50
|
+
return true; // 172.16.0.0/12 private
|
|
51
|
+
if (a === 192 && b === 168)
|
|
52
|
+
return true; // 192.168.0.0/16 private
|
|
53
|
+
if (a === 100 && b >= 64 && b <= 127)
|
|
54
|
+
return true; // 100.64.0.0/10 CGNAT
|
|
55
|
+
if (a === 192 && b === 0 && o[2] === 0)
|
|
56
|
+
return true; // 192.0.0.0/24 IETF protocol
|
|
57
|
+
if (a >= 224)
|
|
58
|
+
return true; // 224.0.0.0/4 multicast + 240.0.0.0/4 reserved + 255.* broadcast
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
function isPrivateIpv6(raw) {
|
|
62
|
+
const ip = raw.toLowerCase();
|
|
63
|
+
if (ip === '::1' || ip === '::')
|
|
64
|
+
return true; // loopback / unspecified
|
|
65
|
+
// IPv4-mapped (::ffff:a.b.c.d) and IPv4-compatible / NAT64 — re-check embedded v4.
|
|
66
|
+
const mapped = ip.match(/(?:::ffff:|::ffff:0:|64:ff9b::)(\d+\.\d+\.\d+\.\d+)$/);
|
|
67
|
+
if (mapped)
|
|
68
|
+
return isPrivateIpv4(mapped[1]);
|
|
69
|
+
if (ip.startsWith('fe8') || ip.startsWith('fe9') || ip.startsWith('fea') || ip.startsWith('feb'))
|
|
70
|
+
return true; // fe80::/10 link-local
|
|
71
|
+
if (ip.startsWith('fc') || ip.startsWith('fd'))
|
|
72
|
+
return true; // fc00::/7 unique-local
|
|
73
|
+
if (ip.startsWith('fec') || ip.startsWith('fed') || ip.startsWith('fee') || ip.startsWith('fef'))
|
|
74
|
+
return true; // fec0::/10 deprecated site-local
|
|
75
|
+
if (ip.startsWith('ff'))
|
|
76
|
+
return true; // ff00::/8 multicast
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
/** Whether `ip` (a literal IPv4 or IPv6 address) is private, loopback, or reserved. */
|
|
80
|
+
export function isPrivateOrReservedIp(ip) {
|
|
81
|
+
const kind = isIP(ip);
|
|
82
|
+
if (kind === 4)
|
|
83
|
+
return isPrivateIpv4(ip);
|
|
84
|
+
if (kind === 6)
|
|
85
|
+
return isPrivateIpv6(ip);
|
|
86
|
+
return false; // not an IP literal
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Throw if `urlString` is not a public http(s) URL. Resolves the host via DNS and
|
|
90
|
+
* rejects when any resolved address is private/loopback/link-local/reserved.
|
|
91
|
+
* Honors the `MCPMAKE_ALLOW_PRIVATE_HOSTS` escape hatch.
|
|
92
|
+
*/
|
|
93
|
+
export async function assertPublicUrl(urlString) {
|
|
94
|
+
let url;
|
|
95
|
+
try {
|
|
96
|
+
url = new URL(urlString);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw new Error(`Invalid URL: ${urlString}`);
|
|
100
|
+
}
|
|
101
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
102
|
+
throw new Error(`Refusing non-http(s) URL: ${urlString}`);
|
|
103
|
+
}
|
|
104
|
+
if (privateHostsAllowed())
|
|
105
|
+
return;
|
|
106
|
+
// Strip IPv6 brackets from the hostname for literal checks.
|
|
107
|
+
const host = url.hostname.replace(/^\[/, '').replace(/\]$/, '');
|
|
108
|
+
// Literal IP host — check directly, no DNS needed.
|
|
109
|
+
if (isIP(host)) {
|
|
110
|
+
if (isPrivateOrReservedIp(host)) {
|
|
111
|
+
throw new Error(`Refusing to access private/reserved address ${host} (set ${ALLOW_ENV}=1 to allow).`);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
// Hostname — resolve every address it maps to and reject if ANY is private.
|
|
116
|
+
let addresses;
|
|
117
|
+
try {
|
|
118
|
+
addresses = await lookup(host, { all: true });
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
throw new Error(`Cannot resolve host "${host}" to verify it is public; refusing request.`);
|
|
122
|
+
}
|
|
123
|
+
for (const { address } of addresses) {
|
|
124
|
+
if (isPrivateOrReservedIp(address)) {
|
|
125
|
+
throw new Error(`Refusing request: host "${host}" resolves to private/reserved address ${address} ` +
|
|
126
|
+
`(set ${ALLOW_ENV}=1 to allow).`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=ssrf-guard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-guard.js","sourceRoot":"","sources":["../../src/utils/ssrf-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/watcher.d.ts
CHANGED
|
@@ -4,9 +4,25 @@ export interface WatchOptions {
|
|
|
4
4
|
onChange: () => Promise<void>;
|
|
5
5
|
debounceMs?: number;
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Debounce + coalesce change notifications into regeneration runs.
|
|
9
|
+
*
|
|
10
|
+
* - Rapid bursts before a run are debounced into one run.
|
|
11
|
+
* - A change that arrives *while* a run is in flight sets a single `pending`
|
|
12
|
+
* flag, so exactly one trailing run fires afterwards. The flag (not a queue)
|
|
13
|
+
* caps the backlog at one regardless of how many events land mid-run, which
|
|
14
|
+
* avoids an unbounded backlog / memory growth.
|
|
15
|
+
*
|
|
16
|
+
* Exposed (and exported) separately from the fs binding so the coalescing logic
|
|
17
|
+
* is testable without relying on platform fs.watch event timing.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createChangeHandler(onChange: () => Promise<void>, debounceMs: number): {
|
|
20
|
+
notify: () => void;
|
|
21
|
+
};
|
|
7
22
|
/**
|
|
8
23
|
* Watch a file for changes and invoke a callback.
|
|
9
|
-
* Debounces rapid successive changes (e.g., editor save + format)
|
|
24
|
+
* Debounces rapid successive changes (e.g., editor save + format) and coalesces
|
|
25
|
+
* changes that arrive during a regeneration into a single trailing run.
|
|
10
26
|
*/
|
|
11
27
|
export declare function watchFile(options: WatchOptions): FSWatcher;
|
|
12
28
|
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/utils/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAGhD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../../src/utils/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAGhD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAC7B,UAAU,EAAE,MAAM,GACjB;IAAE,MAAM,EAAE,MAAM,IAAI,CAAA;CAAE,CAmCxB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,YAAY,GAAG,SAAS,CAa1D"}
|
package/dist/utils/watcher.js
CHANGED
|
@@ -1,34 +1,66 @@
|
|
|
1
1
|
import { watch } from 'node:fs';
|
|
2
2
|
import { logger } from './logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Debounce + coalesce change notifications into regeneration runs.
|
|
5
|
+
*
|
|
6
|
+
* - Rapid bursts before a run are debounced into one run.
|
|
7
|
+
* - A change that arrives *while* a run is in flight sets a single `pending`
|
|
8
|
+
* flag, so exactly one trailing run fires afterwards. The flag (not a queue)
|
|
9
|
+
* caps the backlog at one regardless of how many events land mid-run, which
|
|
10
|
+
* avoids an unbounded backlog / memory growth.
|
|
11
|
+
*
|
|
12
|
+
* Exposed (and exported) separately from the fs binding so the coalescing logic
|
|
13
|
+
* is testable without relying on platform fs.watch event timing.
|
|
14
|
+
*/
|
|
15
|
+
export function createChangeHandler(onChange, debounceMs) {
|
|
16
|
+
let timer;
|
|
17
|
+
let running = false;
|
|
18
|
+
let pending = false;
|
|
19
|
+
async function regenerate() {
|
|
20
|
+
running = true;
|
|
21
|
+
try {
|
|
22
|
+
do {
|
|
23
|
+
pending = false;
|
|
24
|
+
logger.info('Spec file changed, regenerating...');
|
|
25
|
+
try {
|
|
26
|
+
await onChange();
|
|
27
|
+
logger.success('Regeneration complete');
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
logger.error(`Regeneration failed: ${err instanceof Error ? err.message : err}`);
|
|
31
|
+
}
|
|
32
|
+
} while (pending);
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
running = false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
notify() {
|
|
40
|
+
if (running) {
|
|
41
|
+
pending = true;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (timer)
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
timer = setTimeout(() => {
|
|
47
|
+
void regenerate();
|
|
48
|
+
}, debounceMs);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
3
52
|
/**
|
|
4
53
|
* Watch a file for changes and invoke a callback.
|
|
5
|
-
* Debounces rapid successive changes (e.g., editor save + format)
|
|
54
|
+
* Debounces rapid successive changes (e.g., editor save + format) and coalesces
|
|
55
|
+
* changes that arrive during a regeneration into a single trailing run.
|
|
6
56
|
*/
|
|
7
57
|
export function watchFile(options) {
|
|
8
58
|
const debounceMs = options.debounceMs ?? 500;
|
|
9
|
-
|
|
10
|
-
let running = false;
|
|
59
|
+
const handler = createChangeHandler(options.onChange, debounceMs);
|
|
11
60
|
const watcher = watch(options.filePath, (eventType) => {
|
|
12
61
|
if (eventType !== 'change')
|
|
13
62
|
return;
|
|
14
|
-
|
|
15
|
-
return;
|
|
16
|
-
if (timer)
|
|
17
|
-
clearTimeout(timer);
|
|
18
|
-
timer = setTimeout(async () => {
|
|
19
|
-
running = true;
|
|
20
|
-
logger.info('Spec file changed, regenerating...');
|
|
21
|
-
try {
|
|
22
|
-
await options.onChange();
|
|
23
|
-
logger.success('Regeneration complete');
|
|
24
|
-
}
|
|
25
|
-
catch (err) {
|
|
26
|
-
logger.error(`Regeneration failed: ${err instanceof Error ? err.message : err}`);
|
|
27
|
-
}
|
|
28
|
-
finally {
|
|
29
|
-
running = false;
|
|
30
|
-
}
|
|
31
|
-
}, debounceMs);
|
|
63
|
+
handler.notify();
|
|
32
64
|
});
|
|
33
65
|
logger.info(`Watching for changes: ${options.filePath}`);
|
|
34
66
|
logger.info('Press Ctrl+C to stop');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/utils/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/utils/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAkB,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAQrC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAA6B,EAC7B,UAAkB;IAElB,IAAI,KAAgD,CAAC;IACrD,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,UAAU,UAAU;QACvB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACH,GAAG,CAAC;gBACF,OAAO,GAAG,KAAK,CAAC;gBAChB,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;gBAClD,IAAI,CAAC;oBACH,MAAM,QAAQ,EAAE,CAAC;oBACjB,MAAM,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;gBAC1C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;gBACnF,CAAC;YACH,CAAC,QAAQ,OAAO,EAAE;QACpB,CAAC;gBAAS,CAAC;YACT,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM;YACJ,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,GAAG,IAAI,CAAC;gBACf,OAAO;YACT,CAAC;YACD,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,KAAK,UAAU,EAAE,CAAC;YACpB,CAAC,EAAE,UAAU,CAAC,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,OAAqB;IAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,GAAG,CAAC;IAC7C,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,EAAE;QACpD,IAAI,SAAS,KAAK,QAAQ;YAAE,OAAO;QACnC,OAAO,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,IAAI,CAAC,yBAAyB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACzD,MAAM,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAEpC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpmake/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Shared generation library for mcpmake — parse APIs (OpenAPI/HAR/Postman/websites) and emit MCP servers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"handlebars": "^4.7.8",
|
|
36
36
|
"json-schema-to-zod": "^2.4.1",
|
|
37
37
|
"marked": "^12.0.2",
|
|
38
|
+
"openai": "^6.44.0",
|
|
38
39
|
"openapi-types": "^12.1.3",
|
|
39
40
|
"playwright": "^1.59.1",
|
|
40
41
|
"yaml": "^2.7.0"
|