@rex0220/kintone-sql-tools 1.12.1 → 1.13.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/README.md +46 -12
- package/dist-cli/ksql.js +764 -429
- package/dist-mcp/ksql-mcp.js +614 -236
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +4 -2
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -37666,195 +37666,169 @@ function buildBatchEnvelope(batch, options = {}) {
|
|
|
37666
37666
|
};
|
|
37667
37667
|
}
|
|
37668
37668
|
|
|
37669
|
-
// src/node/
|
|
37670
|
-
function
|
|
37671
|
-
|
|
37672
|
-
|
|
37673
|
-
|
|
37674
|
-
|
|
37675
|
-
|
|
37676
|
-
|
|
37677
|
-
|
|
37678
|
-
|
|
37679
|
-
if (!value) throw new Error(`ArgumentError: token is empty for ${key}.`);
|
|
37680
|
-
out[key] = value;
|
|
37669
|
+
// src/node/sqlDiagnostics.ts
|
|
37670
|
+
function restoreSqlDiagnosticValue(value, bindings) {
|
|
37671
|
+
if (typeof value === "string") {
|
|
37672
|
+
let restored = value;
|
|
37673
|
+
for (const binding of bindings.values()) {
|
|
37674
|
+
const internal = `APP${binding.mappedAppId}`;
|
|
37675
|
+
const display = binding.source === "logical" ? `LAPP_${binding.logicalName}@${binding.profile}` : `APP${binding.appId}@${binding.profile}`;
|
|
37676
|
+
restored = restored.split(`${internal} (${binding.mappedAppId})`).join(display).split(internal).join(display);
|
|
37677
|
+
}
|
|
37678
|
+
return restored;
|
|
37681
37679
|
}
|
|
37682
|
-
|
|
37683
|
-
|
|
37684
|
-
function normalizeAppKey(v) {
|
|
37685
|
-
const m1 = v.match(/^APP(\d+)$/i);
|
|
37686
|
-
if (m1) return `APP${m1[1]}`;
|
|
37687
|
-
const m2 = v.match(/^(\d+)$/);
|
|
37688
|
-
if (m2) return `APP${m2[1]}`;
|
|
37689
|
-
throw new Error(`ArgumentError: invalid app key "${v}"`);
|
|
37690
|
-
}
|
|
37691
|
-
function extractAppIds(sql) {
|
|
37692
|
-
const out = /* @__PURE__ */ new Set();
|
|
37693
|
-
for (const t of collectAppProfileTokens(sql)) out.add(t.appId);
|
|
37694
|
-
return [...out];
|
|
37695
|
-
}
|
|
37696
|
-
function isSqlIdentContinue(ch) {
|
|
37697
|
-
if (!ch) return false;
|
|
37698
|
-
const cp = ch.codePointAt(0);
|
|
37699
|
-
return cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp >= 48 && cp <= 57 || cp === 95 || cp === 36 || cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65281 && cp <= 65376;
|
|
37700
|
-
}
|
|
37701
|
-
function isProfileNameChar(ch) {
|
|
37702
|
-
if (!ch) return false;
|
|
37703
|
-
const cp = ch.codePointAt(0);
|
|
37704
|
-
return cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp >= 48 && cp <= 57 || ch === "_" || ch === "-" || ch === "." || ch === "$";
|
|
37705
|
-
}
|
|
37706
|
-
function tryParseAppProfileToken(sql, start) {
|
|
37707
|
-
const head = sql.slice(start, start + 3);
|
|
37708
|
-
if (head.toUpperCase() !== "APP") return null;
|
|
37709
|
-
const prev = start > 0 ? sql[start - 1] : "";
|
|
37710
|
-
if (isSqlIdentContinue(prev)) return null;
|
|
37711
|
-
let i = start + 3;
|
|
37712
|
-
const digitStart = i;
|
|
37713
|
-
while (i < sql.length && /[0-9]/.test(sql[i])) i++;
|
|
37714
|
-
const digitEnd = i;
|
|
37715
|
-
if (digitEnd === digitStart) return null;
|
|
37716
|
-
if (sql[i] === "$") {
|
|
37717
|
-
i++;
|
|
37718
|
-
const subStart = i;
|
|
37719
|
-
while (i < sql.length && isSqlIdentContinue(sql[i])) i++;
|
|
37720
|
-
if (i === subStart) return null;
|
|
37680
|
+
if (Array.isArray(value)) {
|
|
37681
|
+
return value.map((item) => restoreSqlDiagnosticValue(item, bindings));
|
|
37721
37682
|
}
|
|
37722
|
-
|
|
37723
|
-
|
|
37724
|
-
|
|
37725
|
-
|
|
37726
|
-
const pStart = i;
|
|
37727
|
-
while (i < sql.length && isProfileNameChar(sql[i])) i++;
|
|
37728
|
-
if (i === pStart) return null;
|
|
37729
|
-
profile2 = sql.slice(pStart, i);
|
|
37683
|
+
if (value !== null && typeof value === "object") {
|
|
37684
|
+
return Object.fromEntries(
|
|
37685
|
+
Object.entries(value).map(([key, item]) => [key, restoreSqlDiagnosticValue(item, bindings)])
|
|
37686
|
+
);
|
|
37730
37687
|
}
|
|
37731
|
-
|
|
37732
|
-
if (isSqlIdentContinue(next)) return null;
|
|
37733
|
-
return {
|
|
37734
|
-
appId: Number(sql.slice(digitStart, digitEnd)),
|
|
37735
|
-
profile: profile2,
|
|
37736
|
-
start,
|
|
37737
|
-
digitStart,
|
|
37738
|
-
digitEnd,
|
|
37739
|
-
appEnd,
|
|
37740
|
-
fullEnd: i
|
|
37741
|
-
};
|
|
37688
|
+
return value;
|
|
37742
37689
|
}
|
|
37743
|
-
function
|
|
37744
|
-
|
|
37745
|
-
let
|
|
37746
|
-
|
|
37747
|
-
|
|
37748
|
-
|
|
37749
|
-
|
|
37750
|
-
|
|
37751
|
-
|
|
37752
|
-
|
|
37753
|
-
|
|
37754
|
-
|
|
37755
|
-
|
|
37756
|
-
|
|
37757
|
-
|
|
37758
|
-
|
|
37759
|
-
|
|
37690
|
+
function restoreSqlContextError(err, sourceSql, context) {
|
|
37691
|
+
if (!(err instanceof Error)) return err;
|
|
37692
|
+
let message = err.message;
|
|
37693
|
+
for (const binding of context.bindings.values()) {
|
|
37694
|
+
if (binding.source === "logical") {
|
|
37695
|
+
message = message.split(`APP${binding.mappedAppId}`).join(`LAPP_${binding.logicalName}@${binding.profile}`);
|
|
37696
|
+
}
|
|
37697
|
+
}
|
|
37698
|
+
const token = err.token;
|
|
37699
|
+
if (typeof token?.pos === "number") {
|
|
37700
|
+
const segment = context.rewriteSegments.find(
|
|
37701
|
+
(candidate) => token.pos >= candidate.normalizedStart && token.pos < candidate.normalizedEnd
|
|
37702
|
+
);
|
|
37703
|
+
if (segment) {
|
|
37704
|
+
const sourcePos = segment.sourceStart + Math.min(
|
|
37705
|
+
token.pos - segment.normalizedStart,
|
|
37706
|
+
Math.max(0, segment.sourceEnd - segment.sourceStart - 1)
|
|
37707
|
+
);
|
|
37708
|
+
message = message.replace(/(位置 \d+、トークン:/, `\uFF08\u4F4D\u7F6E ${sourcePos}\u3001\u30C8\u30FC\u30AF\u30F3:`);
|
|
37709
|
+
const originalRef = sourceSql.slice(segment.sourceStart, segment.sourceEnd);
|
|
37710
|
+
if (segment.bindingMappedAppId !== void 0 && originalRef) {
|
|
37711
|
+
message = message.replace(/(トークン: 「)[^」]*(」)/, `$1${originalRef}$2`);
|
|
37760
37712
|
}
|
|
37761
|
-
continue;
|
|
37762
37713
|
}
|
|
37763
|
-
|
|
37764
|
-
|
|
37765
|
-
|
|
37766
|
-
|
|
37767
|
-
|
|
37714
|
+
}
|
|
37715
|
+
err.message = message;
|
|
37716
|
+
return err;
|
|
37717
|
+
}
|
|
37718
|
+
|
|
37719
|
+
// src/node/config.ts
|
|
37720
|
+
var import_fs = require("fs");
|
|
37721
|
+
var LOGICAL_APP_NAME_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
|
|
37722
|
+
var PHYSICAL_APP_KEY_RE = /^APP\d+$/i;
|
|
37723
|
+
var NUMERIC_APP_KEY_RE = /^\d+$/;
|
|
37724
|
+
var LOGICAL_SQL_KEY_RE = /^LAPP_/i;
|
|
37725
|
+
function argumentError(message) {
|
|
37726
|
+
return new Error(`ArgumentError: ${message}`);
|
|
37727
|
+
}
|
|
37728
|
+
function normalizeLogicalApps(profileName, value) {
|
|
37729
|
+
if (value === void 0) return void 0;
|
|
37730
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
37731
|
+
throw argumentError(`logicalApps for profile "${profileName}" must be an object.`);
|
|
37732
|
+
}
|
|
37733
|
+
const normalized = {};
|
|
37734
|
+
const physicalIdOwners = /* @__PURE__ */ new Map();
|
|
37735
|
+
for (const [rawName, rawAppId] of Object.entries(value)) {
|
|
37736
|
+
if (PHYSICAL_APP_KEY_RE.test(rawName) || NUMERIC_APP_KEY_RE.test(rawName) || LOGICAL_SQL_KEY_RE.test(rawName)) {
|
|
37737
|
+
throw argumentError(
|
|
37738
|
+
`logical app key "${rawName}" in profile "${profileName}" must be a logical name without APP, numeric, or LAPP_ syntax.`
|
|
37739
|
+
);
|
|
37768
37740
|
}
|
|
37769
|
-
if (
|
|
37770
|
-
|
|
37771
|
-
|
|
37772
|
-
|
|
37741
|
+
if (!LOGICAL_APP_NAME_RE.test(rawName)) {
|
|
37742
|
+
throw argumentError(
|
|
37743
|
+
`logical app key "${rawName}" in profile "${profileName}" must match [A-Z][A-Z0-9_]{0,63}.`
|
|
37744
|
+
);
|
|
37773
37745
|
}
|
|
37774
|
-
|
|
37775
|
-
|
|
37776
|
-
|
|
37777
|
-
|
|
37778
|
-
|
|
37779
|
-
break;
|
|
37780
|
-
}
|
|
37781
|
-
i++;
|
|
37782
|
-
}
|
|
37783
|
-
continue;
|
|
37746
|
+
const logicalName = rawName.toUpperCase();
|
|
37747
|
+
if (Object.prototype.hasOwnProperty.call(normalized, logicalName)) {
|
|
37748
|
+
throw argumentError(
|
|
37749
|
+
`logical app name "${logicalName}" is duplicated after case normalization in profile "${profileName}".`
|
|
37750
|
+
);
|
|
37784
37751
|
}
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
|
|
37788
|
-
|
|
37752
|
+
if (typeof rawAppId !== "number" || !Number.isSafeInteger(rawAppId) || rawAppId <= 0) {
|
|
37753
|
+
throw argumentError(
|
|
37754
|
+
`physical app ID for logical app "${logicalName}" in profile "${profileName}" must be a positive safe integer.`
|
|
37755
|
+
);
|
|
37789
37756
|
}
|
|
37790
|
-
|
|
37791
|
-
|
|
37757
|
+
const existingName = physicalIdOwners.get(rawAppId);
|
|
37758
|
+
if (existingName !== void 0) {
|
|
37759
|
+
throw argumentError(
|
|
37760
|
+
`logical apps "${existingName}" and "${logicalName}" in profile "${profileName}" map to the same physical app ID ${rawAppId}; physical app aliases are not supported yet.`
|
|
37761
|
+
);
|
|
37762
|
+
}
|
|
37763
|
+
physicalIdOwners.set(rawAppId, logicalName);
|
|
37764
|
+
normalized[logicalName] = rawAppId;
|
|
37792
37765
|
}
|
|
37793
|
-
return
|
|
37766
|
+
return normalized;
|
|
37794
37767
|
}
|
|
37795
|
-
function
|
|
37796
|
-
|
|
37797
|
-
|
|
37798
|
-
used.add(id);
|
|
37799
|
-
return id;
|
|
37800
|
-
}
|
|
37801
|
-
function normalizeSqlAppProfiles(sql, defaultProfile = "dev") {
|
|
37802
|
-
const tokens = collectAppProfileTokens(sql);
|
|
37803
|
-
const hasProfileSyntax = tokens.some((t) => t.profile !== null);
|
|
37804
|
-
const profilesByApp = /* @__PURE__ */ new Map();
|
|
37805
|
-
const normalizedProfile = (profile2) => profile2 ?? defaultProfile;
|
|
37806
|
-
for (const t of tokens) {
|
|
37807
|
-
const p = normalizedProfile(t.profile);
|
|
37808
|
-
let set2 = profilesByApp.get(t.appId);
|
|
37809
|
-
if (!set2) {
|
|
37810
|
-
set2 = /* @__PURE__ */ new Set();
|
|
37811
|
-
profilesByApp.set(t.appId, set2);
|
|
37812
|
-
}
|
|
37813
|
-
set2.add(p.toLowerCase());
|
|
37768
|
+
function validateKsqlConfig(config2) {
|
|
37769
|
+
if (config2 === null || typeof config2 !== "object" || Array.isArray(config2)) {
|
|
37770
|
+
throw argumentError("config must be an object.");
|
|
37814
37771
|
}
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
if (
|
|
37821
|
-
|
|
37822
|
-
const mapped = nextVirtualAppId(usedAppIds);
|
|
37823
|
-
pairToMapped.set(`${appId}@${pLower}`, mapped);
|
|
37824
|
-
appBindingByMappedApp.set(mapped, { appId, profile: pLower });
|
|
37772
|
+
if (config2.profiles === void 0) return config2;
|
|
37773
|
+
if (config2.profiles === null || typeof config2.profiles !== "object" || Array.isArray(config2.profiles)) {
|
|
37774
|
+
throw argumentError("profiles must be an object.");
|
|
37775
|
+
}
|
|
37776
|
+
for (const [profileName, profile2] of Object.entries(config2.profiles)) {
|
|
37777
|
+
if (profile2 === null || typeof profile2 !== "object" || Array.isArray(profile2)) {
|
|
37778
|
+
throw argumentError(`profile "${profileName}" must be an object.`);
|
|
37825
37779
|
}
|
|
37780
|
+
if (profile2.allowPhysicalAppRefs !== void 0 && typeof profile2.allowPhysicalAppRefs !== "boolean") {
|
|
37781
|
+
throw argumentError(`allowPhysicalAppRefs for profile "${profileName}" must be boolean.`);
|
|
37782
|
+
}
|
|
37783
|
+
const logicalApps = normalizeLogicalApps(profileName, profile2.logicalApps);
|
|
37784
|
+
if (logicalApps !== void 0) profile2.logicalApps = logicalApps;
|
|
37826
37785
|
}
|
|
37827
|
-
|
|
37828
|
-
|
|
37829
|
-
|
|
37830
|
-
|
|
37831
|
-
|
|
37832
|
-
|
|
37833
|
-
|
|
37834
|
-
|
|
37835
|
-
|
|
37836
|
-
|
|
37837
|
-
|
|
37838
|
-
|
|
37786
|
+
return config2;
|
|
37787
|
+
}
|
|
37788
|
+
function createAppResolutionContext(config2, defaultProfile) {
|
|
37789
|
+
const profiles = Object.fromEntries(
|
|
37790
|
+
Object.entries(config2.profiles ?? {}).map(([name, profile2]) => [
|
|
37791
|
+
name,
|
|
37792
|
+
{
|
|
37793
|
+
logicalApps: profile2.logicalApps === void 0 ? void 0 : { ...profile2.logicalApps },
|
|
37794
|
+
allowPhysicalAppRefs: profile2.allowPhysicalAppRefs
|
|
37795
|
+
}
|
|
37796
|
+
])
|
|
37797
|
+
);
|
|
37798
|
+
const implicitDefaultProfile = {};
|
|
37799
|
+
function requireProfile(profileName) {
|
|
37800
|
+
const profile2 = profiles[profileName];
|
|
37801
|
+
if (!profile2 && profileName === defaultProfile) return implicitDefaultProfile;
|
|
37802
|
+
if (!profile2) throw argumentError(`profile "${profileName}" is not defined.`);
|
|
37803
|
+
return profile2;
|
|
37839
37804
|
}
|
|
37840
|
-
out.push(sql.slice(cursor));
|
|
37841
37805
|
return {
|
|
37842
|
-
|
|
37843
|
-
|
|
37844
|
-
|
|
37806
|
+
resolveLogicalApp(name, profile2) {
|
|
37807
|
+
if (!LOGICAL_APP_NAME_RE.test(name)) {
|
|
37808
|
+
throw argumentError(`logical app name "${name}" must match [A-Z][A-Z0-9_]{0,63}.`);
|
|
37809
|
+
}
|
|
37810
|
+
const profileName = profile2 || defaultProfile;
|
|
37811
|
+
const logicalName = name.toUpperCase();
|
|
37812
|
+
const appId = requireProfile(profileName).logicalApps?.[logicalName];
|
|
37813
|
+
if (appId === void 0) {
|
|
37814
|
+
throw argumentError(`logical app LAPP_${logicalName}@${profileName} is not defined.`);
|
|
37815
|
+
}
|
|
37816
|
+
return appId;
|
|
37817
|
+
},
|
|
37818
|
+
assertPhysicalAppAllowed(profile2) {
|
|
37819
|
+
const profileName = profile2 || defaultProfile;
|
|
37820
|
+
if (!profiles[profileName]) return;
|
|
37821
|
+
if (requireProfile(profileName).allowPhysicalAppRefs === false) {
|
|
37822
|
+
throw argumentError(
|
|
37823
|
+
`physical app references are not allowed for profile "${profileName}"; use LAPP_<NAME>.`
|
|
37824
|
+
);
|
|
37825
|
+
}
|
|
37826
|
+
}
|
|
37845
37827
|
};
|
|
37846
37828
|
}
|
|
37847
|
-
function buildCacheContext(defaultProfile, appBindingByMappedApp) {
|
|
37848
|
-
if (appBindingByMappedApp.size === 0) return `default:${defaultProfile.toLowerCase()}`;
|
|
37849
|
-
const pairs = [...appBindingByMappedApp.entries()].sort((a, b) => a[0] - b[0]).map(([mappedAppId, b]) => `M${mappedAppId}=APP${b.appId}@${b.profile}`);
|
|
37850
|
-
return `apps:${pairs.join(",")}`;
|
|
37851
|
-
}
|
|
37852
|
-
|
|
37853
|
-
// src/node/config.ts
|
|
37854
|
-
var import_fs = require("fs");
|
|
37855
37829
|
function loadKsqlConfig(configPath) {
|
|
37856
37830
|
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
37857
|
-
return JSON.parse(raw);
|
|
37831
|
+
return validateKsqlConfig(JSON.parse(raw));
|
|
37858
37832
|
}
|
|
37859
37833
|
function loadOptionalKsqlConfig(configPath) {
|
|
37860
37834
|
if (!(0, import_fs.existsSync)(configPath)) return {};
|
|
@@ -38051,11 +38025,19 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
38051
38025
|
);
|
|
38052
38026
|
}
|
|
38053
38027
|
}
|
|
38054
|
-
const
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38028
|
+
const controller = new AbortController();
|
|
38029
|
+
const timeout2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
38030
|
+
timeout2.unref?.();
|
|
38031
|
+
let res;
|
|
38032
|
+
try {
|
|
38033
|
+
res = await fetch(url2, {
|
|
38034
|
+
...init,
|
|
38035
|
+
headers,
|
|
38036
|
+
signal: controller.signal
|
|
38037
|
+
});
|
|
38038
|
+
} finally {
|
|
38039
|
+
clearTimeout(timeout2);
|
|
38040
|
+
}
|
|
38059
38041
|
if (!res.ok) {
|
|
38060
38042
|
const bodyText = await res.text();
|
|
38061
38043
|
if (tokenResolver.debug) {
|
|
@@ -38223,17 +38205,376 @@ function detectSortKind(fieldType, calcFormat) {
|
|
|
38223
38205
|
return void 0;
|
|
38224
38206
|
}
|
|
38225
38207
|
|
|
38208
|
+
// src/node/appProfiles.ts
|
|
38209
|
+
function parseTokenMap(raw) {
|
|
38210
|
+
const out = {};
|
|
38211
|
+
if (!raw.trim()) return out;
|
|
38212
|
+
const pairs = raw.split(",");
|
|
38213
|
+
for (const pair of pairs) {
|
|
38214
|
+
const idx = pair.indexOf("=");
|
|
38215
|
+
if (idx <= 0) throw new Error("ArgumentError: --token-map must be APPxxx=token pairs.");
|
|
38216
|
+
const key = normalizeAppKey(pair.slice(0, idx).trim());
|
|
38217
|
+
const value = pair.slice(idx + 1).trim();
|
|
38218
|
+
if (!value) throw new Error(`ArgumentError: token is empty for ${key}.`);
|
|
38219
|
+
out[key] = value;
|
|
38220
|
+
}
|
|
38221
|
+
return out;
|
|
38222
|
+
}
|
|
38223
|
+
function normalizeAppKey(v) {
|
|
38224
|
+
const m1 = v.match(/^APP(\d+)$/i);
|
|
38225
|
+
if (m1) return `APP${m1[1]}`;
|
|
38226
|
+
const m2 = v.match(/^(\d+)$/);
|
|
38227
|
+
if (m2) return `APP${m2[1]}`;
|
|
38228
|
+
throw new Error(`ArgumentError: invalid app key "${v}"`);
|
|
38229
|
+
}
|
|
38230
|
+
function extractAppIds(sql) {
|
|
38231
|
+
const out = /* @__PURE__ */ new Set();
|
|
38232
|
+
for (const t of collectAppProfileTokens(sql)) {
|
|
38233
|
+
if (t.source === "physical") out.add(t.appId);
|
|
38234
|
+
}
|
|
38235
|
+
return [...out];
|
|
38236
|
+
}
|
|
38237
|
+
function isSqlIdentContinue(ch) {
|
|
38238
|
+
if (!ch) return false;
|
|
38239
|
+
const cp = ch.codePointAt(0);
|
|
38240
|
+
return cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp >= 48 && cp <= 57 || cp === 95 || cp === 36 || cp >= 12352 && cp <= 12543 || cp >= 13312 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65281 && cp <= 65376;
|
|
38241
|
+
}
|
|
38242
|
+
function isProfileNameChar(ch) {
|
|
38243
|
+
if (!ch) return false;
|
|
38244
|
+
const cp = ch.codePointAt(0);
|
|
38245
|
+
return cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp >= 48 && cp <= 57 || ch === "_" || ch === "-" || ch === "." || ch === "$";
|
|
38246
|
+
}
|
|
38247
|
+
function isAsciiLogicalNameStart(ch) {
|
|
38248
|
+
return /^[A-Za-z]$/.test(ch);
|
|
38249
|
+
}
|
|
38250
|
+
function isAsciiLogicalNameContinue(ch) {
|
|
38251
|
+
return /^[A-Za-z0-9_]$/.test(ch);
|
|
38252
|
+
}
|
|
38253
|
+
function tryParseAppProfileToken(sql, start) {
|
|
38254
|
+
const prev = start > 0 ? sql[start - 1] : "";
|
|
38255
|
+
if (isSqlIdentContinue(prev)) return null;
|
|
38256
|
+
let source;
|
|
38257
|
+
let appId;
|
|
38258
|
+
let logicalName;
|
|
38259
|
+
let referenceValueStart;
|
|
38260
|
+
let referenceValueEnd;
|
|
38261
|
+
let i;
|
|
38262
|
+
if (sql.slice(start, start + 5).toUpperCase() === "LAPP_") {
|
|
38263
|
+
source = "logical";
|
|
38264
|
+
i = start + 5;
|
|
38265
|
+
referenceValueStart = i;
|
|
38266
|
+
if (!isAsciiLogicalNameStart(sql[i] ?? "")) return null;
|
|
38267
|
+
i++;
|
|
38268
|
+
while (i < sql.length && isAsciiLogicalNameContinue(sql[i])) i++;
|
|
38269
|
+
referenceValueEnd = i;
|
|
38270
|
+
if (referenceValueEnd - referenceValueStart > 64) return null;
|
|
38271
|
+
logicalName = sql.slice(referenceValueStart, referenceValueEnd).toUpperCase();
|
|
38272
|
+
} else if (sql.slice(start, start + 3).toUpperCase() === "APP") {
|
|
38273
|
+
source = "physical";
|
|
38274
|
+
i = start + 3;
|
|
38275
|
+
referenceValueStart = i;
|
|
38276
|
+
while (i < sql.length && /[0-9]/.test(sql[i])) i++;
|
|
38277
|
+
referenceValueEnd = i;
|
|
38278
|
+
if (referenceValueEnd === referenceValueStart) return null;
|
|
38279
|
+
appId = Number(sql.slice(referenceValueStart, referenceValueEnd));
|
|
38280
|
+
} else {
|
|
38281
|
+
return null;
|
|
38282
|
+
}
|
|
38283
|
+
if (sql[i] === "$") {
|
|
38284
|
+
i++;
|
|
38285
|
+
const subStart = i;
|
|
38286
|
+
while (i < sql.length && isSqlIdentContinue(sql[i])) i++;
|
|
38287
|
+
if (i === subStart) return null;
|
|
38288
|
+
}
|
|
38289
|
+
const appEnd = i;
|
|
38290
|
+
let profile2 = null;
|
|
38291
|
+
if (sql[i] === "@") {
|
|
38292
|
+
i++;
|
|
38293
|
+
const pStart = i;
|
|
38294
|
+
while (i < sql.length && isProfileNameChar(sql[i])) i++;
|
|
38295
|
+
if (i === pStart) return null;
|
|
38296
|
+
profile2 = sql.slice(pStart, i);
|
|
38297
|
+
}
|
|
38298
|
+
const next = i < sql.length ? sql[i] : "";
|
|
38299
|
+
if (isSqlIdentContinue(next)) return null;
|
|
38300
|
+
const common = {
|
|
38301
|
+
profile: profile2,
|
|
38302
|
+
start,
|
|
38303
|
+
referenceValueStart,
|
|
38304
|
+
referenceValueEnd,
|
|
38305
|
+
appEnd,
|
|
38306
|
+
fullEnd: i
|
|
38307
|
+
};
|
|
38308
|
+
return source === "physical" ? { ...common, source, appId } : { ...common, source, logicalName };
|
|
38309
|
+
}
|
|
38310
|
+
function collectAppProfileTokens(sql) {
|
|
38311
|
+
const tokens = [];
|
|
38312
|
+
let i = 0;
|
|
38313
|
+
while (i < sql.length) {
|
|
38314
|
+
const ch = sql[i];
|
|
38315
|
+
if (ch === "'") {
|
|
38316
|
+
i++;
|
|
38317
|
+
while (i < sql.length) {
|
|
38318
|
+
if (sql[i] === "'") {
|
|
38319
|
+
i++;
|
|
38320
|
+
if (i < sql.length && sql[i] === "'") {
|
|
38321
|
+
i++;
|
|
38322
|
+
continue;
|
|
38323
|
+
}
|
|
38324
|
+
break;
|
|
38325
|
+
}
|
|
38326
|
+
i++;
|
|
38327
|
+
}
|
|
38328
|
+
continue;
|
|
38329
|
+
}
|
|
38330
|
+
if (ch === "`") {
|
|
38331
|
+
i++;
|
|
38332
|
+
while (i < sql.length && sql[i] !== "`") i++;
|
|
38333
|
+
if (i < sql.length) i++;
|
|
38334
|
+
continue;
|
|
38335
|
+
}
|
|
38336
|
+
if (ch === "-" && sql[i + 1] === "-") {
|
|
38337
|
+
i += 2;
|
|
38338
|
+
while (i < sql.length && sql[i] !== "\n") i++;
|
|
38339
|
+
continue;
|
|
38340
|
+
}
|
|
38341
|
+
if (ch === "/" && sql[i + 1] === "*") {
|
|
38342
|
+
i += 2;
|
|
38343
|
+
while (i < sql.length) {
|
|
38344
|
+
if (sql[i] === "*" && sql[i + 1] === "/") {
|
|
38345
|
+
i += 2;
|
|
38346
|
+
break;
|
|
38347
|
+
}
|
|
38348
|
+
i++;
|
|
38349
|
+
}
|
|
38350
|
+
continue;
|
|
38351
|
+
}
|
|
38352
|
+
const parsed = tryParseAppProfileToken(sql, i);
|
|
38353
|
+
if (!parsed) {
|
|
38354
|
+
i++;
|
|
38355
|
+
continue;
|
|
38356
|
+
}
|
|
38357
|
+
tokens.push(parsed);
|
|
38358
|
+
i = parsed.fullEnd;
|
|
38359
|
+
}
|
|
38360
|
+
return tokens;
|
|
38361
|
+
}
|
|
38362
|
+
function nextVirtualAppId(used) {
|
|
38363
|
+
let id = 9e8;
|
|
38364
|
+
while (used.has(id)) id++;
|
|
38365
|
+
used.add(id);
|
|
38366
|
+
return id;
|
|
38367
|
+
}
|
|
38368
|
+
function normalizeSqlAppProfiles(sql, defaultProfile = "dev", resolutionContext) {
|
|
38369
|
+
const tokens = collectAppProfileTokens(sql);
|
|
38370
|
+
const hasProfileSyntax = tokens.some((t) => t.profile !== null);
|
|
38371
|
+
const profilesByApp = /* @__PURE__ */ new Map();
|
|
38372
|
+
const normalizedProfile = (profile2) => profile2 ?? defaultProfile;
|
|
38373
|
+
for (const t of tokens) {
|
|
38374
|
+
if (t.source !== "physical") continue;
|
|
38375
|
+
const p = normalizedProfile(t.profile);
|
|
38376
|
+
let set2 = profilesByApp.get(t.appId);
|
|
38377
|
+
if (!set2) {
|
|
38378
|
+
set2 = /* @__PURE__ */ new Set();
|
|
38379
|
+
profilesByApp.set(t.appId, set2);
|
|
38380
|
+
}
|
|
38381
|
+
set2.add(p.toLowerCase());
|
|
38382
|
+
}
|
|
38383
|
+
const usedAppIds = new Set(
|
|
38384
|
+
tokens.filter((t) => t.source === "physical").map((t) => t.appId)
|
|
38385
|
+
);
|
|
38386
|
+
const resolvedLogicalApps = /* @__PURE__ */ new Map();
|
|
38387
|
+
for (const t of tokens) {
|
|
38388
|
+
if (t.source !== "logical") continue;
|
|
38389
|
+
const pLower = normalizedProfile(t.profile).toLowerCase();
|
|
38390
|
+
const logicalKey = `logical:${t.logicalName}@${pLower}`;
|
|
38391
|
+
if (resolvedLogicalApps.has(logicalKey)) continue;
|
|
38392
|
+
if (!resolutionContext) {
|
|
38393
|
+
throw new Error(
|
|
38394
|
+
`ArgumentError: logical app LAPP_${t.logicalName}@${pLower} requires logicalApps configuration.`
|
|
38395
|
+
);
|
|
38396
|
+
}
|
|
38397
|
+
const resolvedAppId = resolutionContext.resolveLogicalApp(t.logicalName, pLower);
|
|
38398
|
+
resolvedLogicalApps.set(logicalKey, resolvedAppId);
|
|
38399
|
+
usedAppIds.add(resolvedAppId);
|
|
38400
|
+
}
|
|
38401
|
+
const pairToMapped = /* @__PURE__ */ new Map();
|
|
38402
|
+
const appBindingByMappedApp = /* @__PURE__ */ new Map();
|
|
38403
|
+
for (const [appId, pSet] of profilesByApp.entries()) {
|
|
38404
|
+
const profiles = [...pSet].sort();
|
|
38405
|
+
if (profiles.length <= 1) continue;
|
|
38406
|
+
for (const pLower of profiles) {
|
|
38407
|
+
const mapped = nextVirtualAppId(usedAppIds);
|
|
38408
|
+
pairToMapped.set(`physical:${appId}@${pLower}`, mapped);
|
|
38409
|
+
appBindingByMappedApp.set(mapped, {
|
|
38410
|
+
source: "physical",
|
|
38411
|
+
mappedAppId: mapped,
|
|
38412
|
+
appId,
|
|
38413
|
+
profile: pLower
|
|
38414
|
+
});
|
|
38415
|
+
}
|
|
38416
|
+
}
|
|
38417
|
+
const out = [];
|
|
38418
|
+
const rewriteSegments = [];
|
|
38419
|
+
let normalizedLength = 0;
|
|
38420
|
+
let cursor = 0;
|
|
38421
|
+
const appendSegment = (text, sourceStart, sourceEnd, bindingMappedAppId) => {
|
|
38422
|
+
if (!text && sourceStart === sourceEnd) return;
|
|
38423
|
+
const normalizedStart = normalizedLength;
|
|
38424
|
+
out.push(text);
|
|
38425
|
+
normalizedLength += text.length;
|
|
38426
|
+
rewriteSegments.push({
|
|
38427
|
+
normalizedStart,
|
|
38428
|
+
normalizedEnd: normalizedLength,
|
|
38429
|
+
sourceStart,
|
|
38430
|
+
sourceEnd,
|
|
38431
|
+
...bindingMappedAppId === void 0 ? {} : { bindingMappedAppId }
|
|
38432
|
+
});
|
|
38433
|
+
};
|
|
38434
|
+
for (const t of tokens) {
|
|
38435
|
+
const p = normalizedProfile(t.profile);
|
|
38436
|
+
const pLower = p.toLowerCase();
|
|
38437
|
+
let binding;
|
|
38438
|
+
if (t.source === "physical") {
|
|
38439
|
+
const mapped = pairToMapped.get(`physical:${t.appId}@${pLower}`) ?? t.appId;
|
|
38440
|
+
binding = {
|
|
38441
|
+
source: "physical",
|
|
38442
|
+
mappedAppId: mapped,
|
|
38443
|
+
appId: t.appId,
|
|
38444
|
+
profile: pLower
|
|
38445
|
+
};
|
|
38446
|
+
} else {
|
|
38447
|
+
const logicalKey = `logical:${t.logicalName}@${pLower}`;
|
|
38448
|
+
let mapped = pairToMapped.get(logicalKey);
|
|
38449
|
+
if (mapped === void 0) {
|
|
38450
|
+
mapped = nextVirtualAppId(usedAppIds);
|
|
38451
|
+
pairToMapped.set(logicalKey, mapped);
|
|
38452
|
+
}
|
|
38453
|
+
binding = {
|
|
38454
|
+
source: "logical",
|
|
38455
|
+
logicalName: t.logicalName,
|
|
38456
|
+
mappedAppId: mapped,
|
|
38457
|
+
appId: resolvedLogicalApps.get(logicalKey),
|
|
38458
|
+
profile: pLower
|
|
38459
|
+
};
|
|
38460
|
+
}
|
|
38461
|
+
appBindingByMappedApp.set(binding.mappedAppId, binding);
|
|
38462
|
+
appendSegment(sql.slice(cursor, t.start), cursor, t.start);
|
|
38463
|
+
const subtableSuffix = sql.slice(t.referenceValueEnd, t.appEnd);
|
|
38464
|
+
const normalizedReference = t.source === "physical" ? `${sql.slice(t.start, t.referenceValueStart)}${binding.mappedAppId}${subtableSuffix}` : `APP${binding.mappedAppId}${subtableSuffix}`;
|
|
38465
|
+
appendSegment(
|
|
38466
|
+
normalizedReference,
|
|
38467
|
+
t.start,
|
|
38468
|
+
t.fullEnd,
|
|
38469
|
+
binding.mappedAppId
|
|
38470
|
+
);
|
|
38471
|
+
cursor = t.fullEnd;
|
|
38472
|
+
}
|
|
38473
|
+
appendSegment(sql.slice(cursor), cursor, sql.length);
|
|
38474
|
+
return {
|
|
38475
|
+
normalizedSql: out.join(""),
|
|
38476
|
+
hasProfileSyntax,
|
|
38477
|
+
appBindingByMappedApp,
|
|
38478
|
+
rewriteSegments
|
|
38479
|
+
};
|
|
38480
|
+
}
|
|
38481
|
+
function buildCacheContext(defaultProfile, appBindingByMappedApp) {
|
|
38482
|
+
if (appBindingByMappedApp.size === 0) return `default:${defaultProfile.toLowerCase()}`;
|
|
38483
|
+
const pairs = [...appBindingByMappedApp.entries()].sort((a, b) => a[0] - b[0]).map(([mappedAppId, b]) => b.source === "logical" ? `M${mappedAppId}=logical:${b.logicalName}:APP${b.appId}@${b.profile}` : `M${mappedAppId}=physical:APP${b.appId}@${b.profile}`);
|
|
38484
|
+
return `apps:${pairs.join(",")}`;
|
|
38485
|
+
}
|
|
38486
|
+
|
|
38226
38487
|
// src/node/runtime.ts
|
|
38488
|
+
var privateConfigSnapshots = /* @__PURE__ */ new WeakMap();
|
|
38489
|
+
function cloneConfigSnapshot(config2) {
|
|
38490
|
+
return JSON.parse(JSON.stringify(config2));
|
|
38491
|
+
}
|
|
38492
|
+
function toConfigView(config2) {
|
|
38493
|
+
const profiles = Object.fromEntries(Object.entries(config2.profiles ?? {}).map(([name, p]) => [name, {
|
|
38494
|
+
baseUrl: p.baseUrl,
|
|
38495
|
+
logicalApps: p.logicalApps === void 0 ? void 0 : Object.freeze({ ...p.logicalApps }),
|
|
38496
|
+
allowPhysicalAppRefs: p.allowPhysicalAppRefs,
|
|
38497
|
+
passwordEnv: p.passwordEnv,
|
|
38498
|
+
tokenMapSources: p.tokenMap === void 0 ? void 0 : Object.freeze(Object.fromEntries(
|
|
38499
|
+
Object.entries(p.tokenMap).map(([key, value]) => [key, String(value).startsWith("env:") ? String(value).slice(4) : "inline"])
|
|
38500
|
+
))
|
|
38501
|
+
}]));
|
|
38502
|
+
return Object.freeze({ defaultProfile: config2.defaultProfile, profiles: Object.freeze(profiles) });
|
|
38503
|
+
}
|
|
38504
|
+
function resolveSqlContext(serverOptions, sql, inputProfile) {
|
|
38505
|
+
const configPath = serverOptions.configPath ?? envString("KSQL_CONFIG") ?? "./ksql.config.json";
|
|
38506
|
+
const config2 = cloneConfigSnapshot(loadOptionalKsqlConfig(configPath));
|
|
38507
|
+
const profileName = resolveDefaultProfile(config2, serverOptions, inputProfile);
|
|
38508
|
+
const resolutionContext = createAppResolutionContext(config2, profileName);
|
|
38509
|
+
const normalized = normalizeSqlAppProfiles(sql, profileName, resolutionContext);
|
|
38510
|
+
const bindings = normalized.appBindingByMappedApp;
|
|
38511
|
+
for (const binding of bindings.values()) {
|
|
38512
|
+
if (binding.source === "physical") resolutionContext.assertPhysicalAppAllowed(binding.profile);
|
|
38513
|
+
}
|
|
38514
|
+
const context = {
|
|
38515
|
+
normalizedSql: normalized.normalizedSql,
|
|
38516
|
+
bindings,
|
|
38517
|
+
cacheContext: buildCacheContext(profileName, bindings),
|
|
38518
|
+
profileName,
|
|
38519
|
+
rewriteSegments: Object.freeze(normalized.rewriteSegments.map((segment) => Object.freeze({ ...segment }))),
|
|
38520
|
+
hasProfileSyntax: normalized.hasProfileSyntax,
|
|
38521
|
+
configSnapshot: toConfigView(config2),
|
|
38522
|
+
logicalBindingLabels: new Map(
|
|
38523
|
+
[...bindings.values()].filter((b) => b.source === "logical").map((b) => [b.mappedAppId, `LAPP_${b.logicalName}@${b.profile}`])
|
|
38524
|
+
)
|
|
38525
|
+
};
|
|
38526
|
+
Object.freeze(context);
|
|
38527
|
+
privateConfigSnapshots.set(context, config2);
|
|
38528
|
+
return context;
|
|
38529
|
+
}
|
|
38530
|
+
function resolveTokenByMappedApp(args) {
|
|
38531
|
+
const tokenByMappedApp = /* @__PURE__ */ new Map();
|
|
38532
|
+
const tokenByPhysicalApp = /* @__PURE__ */ new Map();
|
|
38533
|
+
const missing = [];
|
|
38534
|
+
for (const mappedAppId of args.mappedAppIds) {
|
|
38535
|
+
const binding = args.bindings.get(mappedAppId);
|
|
38536
|
+
if (!binding && args.logicalBindingLabels.has(mappedAppId)) {
|
|
38537
|
+
throw new Error(`InternalError: binding is missing for logical app ${args.logicalBindingLabels.get(mappedAppId)}.`);
|
|
38538
|
+
}
|
|
38539
|
+
const appId = binding?.appId ?? mappedAppId;
|
|
38540
|
+
const profile2 = binding?.profile ?? args.profileName;
|
|
38541
|
+
const fromMap = args.effectiveTokenMap[`APP${appId}`];
|
|
38542
|
+
if (fromMap) {
|
|
38543
|
+
const token = resolveTokenValue(fromMap);
|
|
38544
|
+
tokenByMappedApp.set(mappedAppId, token);
|
|
38545
|
+
tokenByPhysicalApp.set(appId, token);
|
|
38546
|
+
continue;
|
|
38547
|
+
}
|
|
38548
|
+
if (binding?.source !== "logical" && args.mappedAppIds.length === 1 && args.singleToken) {
|
|
38549
|
+
tokenByMappedApp.set(mappedAppId, args.singleToken);
|
|
38550
|
+
tokenByPhysicalApp.set(appId, args.singleToken);
|
|
38551
|
+
continue;
|
|
38552
|
+
}
|
|
38553
|
+
missing.push(binding?.source === "logical" ? `LAPP_${binding.logicalName} (APP${appId})@${profile2}` : `APP${appId}@${profile2}`);
|
|
38554
|
+
}
|
|
38555
|
+
return { tokenByMappedApp, tokenByPhysicalApp, missing };
|
|
38556
|
+
}
|
|
38557
|
+
function resolveRuntimeBinding(context, mappedAppId) {
|
|
38558
|
+
const binding = context.bindings.get(mappedAppId);
|
|
38559
|
+
if (binding) return binding;
|
|
38560
|
+
const logicalLabel = context.logicalBindingLabels.get(mappedAppId);
|
|
38561
|
+
if (logicalLabel) {
|
|
38562
|
+
throw new Error(`InternalError: binding is missing for logical app ${logicalLabel}.`);
|
|
38563
|
+
}
|
|
38564
|
+
return { appId: mappedAppId, profile: context.profileName.toLowerCase() };
|
|
38565
|
+
}
|
|
38227
38566
|
function resolveDefaultProfile(config2, serverOptions, inputProfile) {
|
|
38228
38567
|
return inputProfile ?? serverOptions.profile ?? envString("KSQL_PROFILE") ?? config2.defaultProfile ?? "dev";
|
|
38229
38568
|
}
|
|
38230
38569
|
async function createKsqlRuntime(serverOptions, input) {
|
|
38231
|
-
const
|
|
38232
|
-
const config2 =
|
|
38233
|
-
|
|
38570
|
+
const sqlContext = input.sqlContext ?? resolveSqlContext(serverOptions, input.sql, input.profile);
|
|
38571
|
+
const config2 = privateConfigSnapshots.get(sqlContext);
|
|
38572
|
+
if (!config2) {
|
|
38573
|
+
throw new Error("InternalError: private config snapshot is missing for resolved SQL context.");
|
|
38574
|
+
}
|
|
38575
|
+
const profileName = sqlContext.profileName;
|
|
38234
38576
|
const profile2 = config2.profiles?.[profileName] ?? {};
|
|
38235
|
-
const
|
|
38236
|
-
const sql = normalized.normalizedSql;
|
|
38577
|
+
const sql = sqlContext.normalizedSql;
|
|
38237
38578
|
const maxRecords2 = input.maxRecords ?? envInt("KSQL_MAX_RECORDS") ?? profile2.query?.maxRecords ?? 500;
|
|
38238
38579
|
const fetchParallel2 = input.fetchParallel ?? envInt("KSQL_FETCH_PARALLEL") ?? profile2.query?.fetchParallel ?? 3;
|
|
38239
38580
|
if (!Number.isInteger(fetchParallel2) || fetchParallel2 < 1 || fetchParallel2 > 10) {
|
|
@@ -38249,11 +38590,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38249
38590
|
for (const appId of appIds) {
|
|
38250
38591
|
appProfileByApp.set(
|
|
38251
38592
|
appId,
|
|
38252
|
-
|
|
38593
|
+
sqlContext.bindings.get(appId)?.profile ?? profileName.toLowerCase()
|
|
38253
38594
|
);
|
|
38254
38595
|
}
|
|
38255
38596
|
const usedProfiles = /* @__PURE__ */ new Set([...appProfileByApp.values(), profileName]);
|
|
38256
38597
|
const profileClientMap = /* @__PURE__ */ new Map();
|
|
38598
|
+
const allTokenByMappedApp = /* @__PURE__ */ new Map();
|
|
38257
38599
|
const missingAppProfiles = [];
|
|
38258
38600
|
const tokenMapEnv = envString("KSQL_TOKEN_MAP");
|
|
38259
38601
|
const mapFromEnv = tokenMapEnv ? parseTokenMap(tokenMapEnv) : {};
|
|
@@ -38291,21 +38633,19 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38291
38633
|
);
|
|
38292
38634
|
const effectiveTokenMap = { ...mapFromConfig, ...mapFromEnv };
|
|
38293
38635
|
const assignedAppIds = appIds.filter((appId) => appProfileByApp.get(appId) === pName);
|
|
38294
|
-
const
|
|
38295
|
-
|
|
38296
|
-
|
|
38297
|
-
|
|
38298
|
-
|
|
38299
|
-
|
|
38300
|
-
|
|
38301
|
-
|
|
38302
|
-
|
|
38303
|
-
|
|
38304
|
-
|
|
38305
|
-
continue;
|
|
38306
|
-
}
|
|
38307
|
-
missingAppProfiles.push(`APP${realAppId}@${pName}`);
|
|
38636
|
+
const resolvedTokens = resolveTokenByMappedApp({
|
|
38637
|
+
mappedAppIds: assignedAppIds,
|
|
38638
|
+
profileName: pName,
|
|
38639
|
+
bindings: sqlContext.bindings,
|
|
38640
|
+
logicalBindingLabels: sqlContext.logicalBindingLabels,
|
|
38641
|
+
effectiveTokenMap,
|
|
38642
|
+
singleToken
|
|
38643
|
+
});
|
|
38644
|
+
const tokenByApp = resolvedTokens.tokenByPhysicalApp;
|
|
38645
|
+
for (const [mappedAppId, token] of resolvedTokens.tokenByMappedApp) {
|
|
38646
|
+
allTokenByMappedApp.set(mappedAppId, token);
|
|
38308
38647
|
}
|
|
38648
|
+
missingAppProfiles.push(...resolvedTokens.missing);
|
|
38309
38649
|
if (assignedAppIds.length === 0 && singleToken) {
|
|
38310
38650
|
tokenByApp.set(0, singleToken);
|
|
38311
38651
|
}
|
|
@@ -38328,38 +38668,43 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38328
38668
|
if (missingAppProfiles.length > 0) {
|
|
38329
38669
|
throw new Error(`AuthError: token is missing for ${missingAppProfiles.join(", ")}.`);
|
|
38330
38670
|
}
|
|
38331
|
-
const
|
|
38671
|
+
const runtimeContext = {
|
|
38672
|
+
sqlContext,
|
|
38673
|
+
tokenByMappedApp: allTokenByMappedApp,
|
|
38674
|
+
clientsByProfile: profileClientMap
|
|
38675
|
+
};
|
|
38676
|
+
const defaultClient = runtimeContext.clientsByProfile.get(profileName);
|
|
38332
38677
|
if (!defaultClient) {
|
|
38333
38678
|
throw new Error(`AuthError: profile client is not resolved for "${profileName}".`);
|
|
38334
38679
|
}
|
|
38335
38680
|
const routedClient = {
|
|
38336
38681
|
getRecords: (params) => {
|
|
38337
|
-
const binding =
|
|
38338
|
-
const routed =
|
|
38682
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38683
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38339
38684
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38340
38685
|
return routed.getRecords({ ...params, app: binding.appId });
|
|
38341
38686
|
},
|
|
38342
38687
|
postRecords: (params) => {
|
|
38343
|
-
const binding =
|
|
38344
|
-
const routed =
|
|
38688
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38689
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38345
38690
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38346
38691
|
return routed.postRecords({ ...params, app: binding.appId });
|
|
38347
38692
|
},
|
|
38348
38693
|
putRecords: (params) => {
|
|
38349
|
-
const binding =
|
|
38350
|
-
const routed =
|
|
38694
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38695
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38351
38696
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38352
38697
|
return routed.putRecords({ ...params, app: binding.appId });
|
|
38353
38698
|
},
|
|
38354
38699
|
deleteRecords: (params) => {
|
|
38355
|
-
const binding =
|
|
38356
|
-
const routed =
|
|
38700
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38701
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38357
38702
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38358
38703
|
return routed.deleteRecords({ ...params, app: binding.appId });
|
|
38359
38704
|
},
|
|
38360
38705
|
getFields: (appId) => {
|
|
38361
|
-
const binding =
|
|
38362
|
-
const routed =
|
|
38706
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
|
|
38707
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38363
38708
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
38364
38709
|
return routed.getFields(binding.appId);
|
|
38365
38710
|
},
|
|
@@ -38378,7 +38723,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38378
38723
|
sql,
|
|
38379
38724
|
profileName,
|
|
38380
38725
|
client: gatedClient,
|
|
38381
|
-
cacheContext:
|
|
38726
|
+
cacheContext: sqlContext.cacheContext,
|
|
38382
38727
|
maxRecords: maxRecords2,
|
|
38383
38728
|
fetchParallel: fetchParallel2,
|
|
38384
38729
|
onLimit: onLimit2,
|
|
@@ -38590,11 +38935,6 @@ function noOpClient() {
|
|
|
38590
38935
|
getFields: fail
|
|
38591
38936
|
};
|
|
38592
38937
|
}
|
|
38593
|
-
function getToolProfile(serverOptions, inputProfile) {
|
|
38594
|
-
const configPath = getServerConfigPath(serverOptions);
|
|
38595
|
-
const config2 = loadOptionalKsqlConfig(configPath);
|
|
38596
|
-
return resolveDefaultProfile(config2, serverOptions, inputProfile);
|
|
38597
|
-
}
|
|
38598
38938
|
function getServerConfigPath(serverOptions) {
|
|
38599
38939
|
return serverOptions.configPath ?? envString("KSQL_CONFIG") ?? "./ksql.config.json";
|
|
38600
38940
|
}
|
|
@@ -38607,16 +38947,34 @@ function getSavedQueryCatalogPath(serverOptions) {
|
|
|
38607
38947
|
});
|
|
38608
38948
|
}
|
|
38609
38949
|
function normalizeSqlForTool(serverOptions, sql, inputProfile) {
|
|
38610
|
-
const
|
|
38611
|
-
const normalized = normalizeSqlAppProfiles(sql, profileName);
|
|
38950
|
+
const sqlContext = resolveSqlContext(serverOptions, sql, inputProfile);
|
|
38612
38951
|
return {
|
|
38613
|
-
profileName,
|
|
38614
|
-
normalizedSql:
|
|
38615
|
-
hasProfileSyntax:
|
|
38616
|
-
appBindingByMappedApp:
|
|
38617
|
-
cacheContext:
|
|
38952
|
+
profileName: sqlContext.profileName,
|
|
38953
|
+
normalizedSql: sqlContext.normalizedSql,
|
|
38954
|
+
hasProfileSyntax: sqlContext.hasProfileSyntax,
|
|
38955
|
+
appBindingByMappedApp: sqlContext.bindings,
|
|
38956
|
+
cacheContext: sqlContext.cacheContext,
|
|
38957
|
+
sqlContext,
|
|
38958
|
+
sourceSql: sql
|
|
38959
|
+
};
|
|
38960
|
+
}
|
|
38961
|
+
function toValidationBinding(mappedAppId, binding) {
|
|
38962
|
+
return binding.source === "logical" ? {
|
|
38963
|
+
source: binding.source,
|
|
38964
|
+
logicalName: binding.logicalName,
|
|
38965
|
+
mappedAppId,
|
|
38966
|
+
appId: binding.appId,
|
|
38967
|
+
profile: binding.profile
|
|
38968
|
+
} : {
|
|
38969
|
+
source: binding.source,
|
|
38970
|
+
mappedAppId,
|
|
38971
|
+
appId: binding.appId,
|
|
38972
|
+
profile: binding.profile
|
|
38618
38973
|
};
|
|
38619
38974
|
}
|
|
38975
|
+
function toExplainBindings(bindings) {
|
|
38976
|
+
return [...bindings.values()].map((binding) => binding.source === "logical" ? { source: binding.source, logicalName: binding.logicalName, appId: binding.appId, profile: binding.profile } : { source: binding.source, appId: binding.appId, profile: binding.profile });
|
|
38977
|
+
}
|
|
38620
38978
|
function explainSql(sql) {
|
|
38621
38979
|
return /^\s*EXPLAIN\b/i.test(sql) ? sql : `EXPLAIN ${sql}`;
|
|
38622
38980
|
}
|
|
@@ -38740,15 +39098,17 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38740
39098
|
const createRuntime = deps.createRuntime ?? createKsqlRuntime;
|
|
38741
39099
|
const executeSql = deps.executeSql ?? execute;
|
|
38742
39100
|
const executeBatchSql = deps.executeBatchSql ?? executeBatch;
|
|
39101
|
+
const validationContexts = /* @__PURE__ */ new WeakMap();
|
|
38743
39102
|
async function validate(input) {
|
|
38744
39103
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
38745
|
-
|
|
38746
|
-
|
|
38747
|
-
|
|
38748
|
-
|
|
38749
|
-
|
|
38750
|
-
|
|
38751
|
-
}
|
|
39104
|
+
let analysis;
|
|
39105
|
+
try {
|
|
39106
|
+
const statements = parseSqlStatements(normalized.normalizedSql);
|
|
39107
|
+
analysis = analyzeBatch(statements);
|
|
39108
|
+
} catch (err) {
|
|
39109
|
+
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
39110
|
+
}
|
|
39111
|
+
const appBindings = [...normalized.appBindingByMappedApp.entries()].map(([mappedAppId, binding]) => toValidationBinding(mappedAppId, binding));
|
|
38752
39112
|
const statementValidations = analysis.statements.map((s2) => ({
|
|
38753
39113
|
index: s2.index,
|
|
38754
39114
|
statementType: s2.statementType,
|
|
@@ -38778,10 +39138,12 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38778
39138
|
appBindings
|
|
38779
39139
|
};
|
|
38780
39140
|
if (analysis.statementCount > 1) {
|
|
38781
|
-
|
|
39141
|
+
const result2 = { ...common, batch: true };
|
|
39142
|
+
validationContexts.set(result2, normalized.sqlContext);
|
|
39143
|
+
return result2;
|
|
38782
39144
|
}
|
|
38783
39145
|
const s = statementValidations[0];
|
|
38784
|
-
|
|
39146
|
+
const result = {
|
|
38785
39147
|
...common,
|
|
38786
39148
|
batch: false,
|
|
38787
39149
|
statementType: s.statementType,
|
|
@@ -38791,17 +39153,26 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38791
39153
|
insertValuesCount: s.insertValuesCount,
|
|
38792
39154
|
appIds: s.appIds
|
|
38793
39155
|
};
|
|
39156
|
+
validationContexts.set(result, normalized.sqlContext);
|
|
39157
|
+
return result;
|
|
38794
39158
|
}
|
|
38795
39159
|
async function explain(input) {
|
|
38796
39160
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
38797
|
-
const
|
|
39161
|
+
const appBindings = toExplainBindings(normalized.appBindingByMappedApp);
|
|
39162
|
+
let statements;
|
|
39163
|
+
try {
|
|
39164
|
+
statements = parseSqlStatements(normalized.normalizedSql);
|
|
39165
|
+
} catch (err) {
|
|
39166
|
+
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
39167
|
+
}
|
|
38798
39168
|
if (statements.length > 1) {
|
|
38799
39169
|
const plans = buildBatchExplainPlans(normalized.normalizedSql);
|
|
38800
39170
|
return {
|
|
38801
39171
|
ok: true,
|
|
38802
39172
|
batch: true,
|
|
38803
39173
|
statementCount: plans.statementCount,
|
|
38804
|
-
statements: plans.statements
|
|
39174
|
+
statements: restoreSqlDiagnosticValue(plans.statements, normalized.appBindingByMappedApp),
|
|
39175
|
+
appBindings
|
|
38805
39176
|
};
|
|
38806
39177
|
}
|
|
38807
39178
|
const result = await executeSql(explainSql(normalized.normalizedSql), noOpClient(), {
|
|
@@ -38810,16 +39181,20 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38810
39181
|
if (result.type !== "SELECT") {
|
|
38811
39182
|
throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
|
|
38812
39183
|
}
|
|
38813
|
-
return
|
|
39184
|
+
return restoreSqlDiagnosticValue(
|
|
39185
|
+
{ ...toSelectPayload(result), appBindings },
|
|
39186
|
+
normalized.appBindingByMappedApp
|
|
39187
|
+
);
|
|
38814
39188
|
}
|
|
38815
|
-
async function query(input) {
|
|
38816
|
-
const validation = await validate(input);
|
|
39189
|
+
async function query(input, validated) {
|
|
39190
|
+
const validation = validated ?? await validate(input);
|
|
38817
39191
|
if (validation.batch) {
|
|
38818
39192
|
if (validation.containsDml) {
|
|
38819
39193
|
throw new Error("ArgumentError: batch contains DML statements. Use ksql_mutate.");
|
|
38820
39194
|
}
|
|
38821
39195
|
const runtime2 = await createRuntime(serverOptions, {
|
|
38822
39196
|
sql: input.sql,
|
|
39197
|
+
sqlContext: validationContexts.get(validation),
|
|
38823
39198
|
profile: input.profile,
|
|
38824
39199
|
maxRecords: input.maxRecords,
|
|
38825
39200
|
fetchParallel: input.fetchParallel,
|
|
@@ -38862,6 +39237,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38862
39237
|
}
|
|
38863
39238
|
const runtime = await createRuntime(serverOptions, {
|
|
38864
39239
|
sql: input.sql,
|
|
39240
|
+
sqlContext: validationContexts.get(validation),
|
|
38865
39241
|
profile: input.profile,
|
|
38866
39242
|
maxRecords: input.maxRecords,
|
|
38867
39243
|
fetchParallel: input.fetchParallel,
|
|
@@ -38907,6 +39283,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38907
39283
|
const selectBasedDml = containsSelectBasedDml(validation.statements);
|
|
38908
39284
|
const runtime = await createRuntime(serverOptions, {
|
|
38909
39285
|
sql: input.sql,
|
|
39286
|
+
sqlContext: validationContexts.get(validation),
|
|
38910
39287
|
profile: input.profile,
|
|
38911
39288
|
// SELECT-based DML を含む場合は dmlMaxRows で読み取りを絞らない(案A。
|
|
38912
39289
|
// resolveMutateRuntimeMaxRecords の doc コメント参照)
|
|
@@ -38951,9 +39328,9 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38951
39328
|
}
|
|
38952
39329
|
return { ...payload };
|
|
38953
39330
|
}
|
|
38954
|
-
async function mutate(input) {
|
|
39331
|
+
async function mutate(input, validated) {
|
|
38955
39332
|
const dmlMaxRows = requireDmlApproval(input, "ksql_mutate");
|
|
38956
|
-
const validation = await validate(input);
|
|
39333
|
+
const validation = validated ?? await validate(input);
|
|
38957
39334
|
if (validation.batch) {
|
|
38958
39335
|
return mutateBatch(input, validation, dmlMaxRows);
|
|
38959
39336
|
}
|
|
@@ -38969,6 +39346,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38969
39346
|
const selectBasedDml = containsSelectBasedDml(validation.statements);
|
|
38970
39347
|
const runtime = await createRuntime(serverOptions, {
|
|
38971
39348
|
sql: input.sql,
|
|
39349
|
+
sqlContext: validationContexts.get(validation),
|
|
38972
39350
|
profile: input.profile,
|
|
38973
39351
|
// SELECT-based DML は dmlMaxRows で読み取りを絞らない(案A。
|
|
38974
39352
|
// resolveMutateRuntimeMaxRecords の doc コメント参照)
|
|
@@ -39089,7 +39467,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
39089
39467
|
fetchParallel: input.fetchParallel,
|
|
39090
39468
|
onLimit: input.onLimit,
|
|
39091
39469
|
timeout: input.timeout
|
|
39092
|
-
});
|
|
39470
|
+
}, validation);
|
|
39093
39471
|
return {
|
|
39094
39472
|
ok: true,
|
|
39095
39473
|
name: saved.name,
|
|
@@ -39105,7 +39483,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
39105
39483
|
dmlMaxRows,
|
|
39106
39484
|
fetchParallel: input.fetchParallel,
|
|
39107
39485
|
timeout: input.timeout
|
|
39108
|
-
});
|
|
39486
|
+
}, validation);
|
|
39109
39487
|
return {
|
|
39110
39488
|
ok: true,
|
|
39111
39489
|
name: saved.name,
|
|
@@ -39275,7 +39653,7 @@ Options:
|
|
|
39275
39653
|
-h, --help Show help
|
|
39276
39654
|
`);
|
|
39277
39655
|
}
|
|
39278
|
-
var SERVER_VERSION = true ? "1.
|
|
39656
|
+
var SERVER_VERSION = true ? "1.13.1" : "0.0.0-dev";
|
|
39279
39657
|
function createServer(args) {
|
|
39280
39658
|
const server = new McpServer({
|
|
39281
39659
|
name: "ksql-mcp",
|