@rex0220/kintone-sql-tools 1.12.1 → 1.13.2
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 +780 -434
- package/dist-mcp/ksql-mcp.js +629 -243
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +4 -2
package/dist-mcp/ksql-mcp.js
CHANGED
|
@@ -37441,7 +37441,7 @@ function buildInsertPlan(stmt, label) {
|
|
|
37441
37441
|
const lines = [];
|
|
37442
37442
|
if (label) lines.push(label);
|
|
37443
37443
|
lines.push(` [INSERT]`);
|
|
37444
|
-
lines.push(`
|
|
37444
|
+
lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
|
|
37445
37445
|
lines.push(` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`);
|
|
37446
37446
|
lines.push(` api: POST /k/v1/records.json \xD7 ${batchCount}`);
|
|
37447
37447
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
@@ -37451,7 +37451,7 @@ function buildInsertSelectPlan(stmt, label) {
|
|
|
37451
37451
|
const lines = [];
|
|
37452
37452
|
if (label) lines.push(label);
|
|
37453
37453
|
lines.push(` [INSERT SELECT]`);
|
|
37454
|
-
lines.push(`
|
|
37454
|
+
lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
|
|
37455
37455
|
lines.push(` fields: ${stmt.fields.join(", ")}`);
|
|
37456
37456
|
lines.push(` api: POST /k/v1/records.json\uFF08\u4EF6\u6570\u306F SELECT \u7D50\u679C\u306B\u4F9D\u5B58\u3001100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`);
|
|
37457
37457
|
lines.push("");
|
|
@@ -37464,7 +37464,7 @@ function buildUpdatePlan(stmt, label) {
|
|
|
37464
37464
|
const lines = [];
|
|
37465
37465
|
if (label) lines.push(label);
|
|
37466
37466
|
lines.push(` [UPDATE]`);
|
|
37467
|
-
lines.push(`
|
|
37467
|
+
lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
|
|
37468
37468
|
lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
|
|
37469
37469
|
lines.push(` api: GET /k/v1/records.json \u2192 PUT /k/v1/records.json`);
|
|
37470
37470
|
const setTypes = [];
|
|
@@ -37494,7 +37494,7 @@ function buildDeletePlan(stmt, label) {
|
|
|
37494
37494
|
const lines = [];
|
|
37495
37495
|
if (label) lines.push(label);
|
|
37496
37496
|
lines.push(` [DELETE]`);
|
|
37497
|
-
lines.push(`
|
|
37497
|
+
lines.push(` target: APP${stmt.appId} (${stmt.appId})`);
|
|
37498
37498
|
lines.push(` kintone query: ${safeWhereToKintone(stmt.where)}`);
|
|
37499
37499
|
lines.push(` api: GET /k/v1/records.json \u2192 DELETE /k/v1/records.json`);
|
|
37500
37500
|
return lines;
|
|
@@ -37505,7 +37505,7 @@ function buildUpsertPlan(stmt, label) {
|
|
|
37505
37505
|
return [
|
|
37506
37506
|
...label ? [label] : [],
|
|
37507
37507
|
` [UPSERT]`,
|
|
37508
|
-
`
|
|
37508
|
+
` target: APP${stmt.appId} (${stmt.appId})`,
|
|
37509
37509
|
` records: ${totalRows} \u4EF6\uFF08\u30D0\u30C3\u30C1 ${batchCount} \u56DE \xD7 \u6700\u5927 100 \u4EF6\uFF09`,
|
|
37510
37510
|
` key fields: ${stmt.keyFields.join(", ")}`,
|
|
37511
37511
|
` fields: ${stmt.fields.join(", ")}`,
|
|
@@ -37516,7 +37516,7 @@ function buildUpsertSelectPlan(stmt, label) {
|
|
|
37516
37516
|
const lines = [
|
|
37517
37517
|
...label ? [label] : [],
|
|
37518
37518
|
` [UPSERT SELECT]`,
|
|
37519
|
-
`
|
|
37519
|
+
` target: APP${stmt.appId} (${stmt.appId})`,
|
|
37520
37520
|
` key fields: ${stmt.keyFields.join(", ")}`,
|
|
37521
37521
|
` fields: ${stmt.fields.join(", ")}`,
|
|
37522
37522
|
` api: GET /k/v1/records.json\uFF08\u91CD\u8907\u5224\u5B9A\uFF09\u2192 POST \u307E\u305F\u306F PUT /k/v1/records.json\uFF08100 \u4EF6\u3054\u3068\u306B\u30D0\u30C3\u30C1\uFF09`,
|
|
@@ -37532,7 +37532,7 @@ function buildReorderPlan(stmt, label) {
|
|
|
37532
37532
|
const lines = [
|
|
37533
37533
|
...label ? [label] : [],
|
|
37534
37534
|
` [REORDER]`,
|
|
37535
|
-
`
|
|
37535
|
+
` target: APP${stmt.appId} (${stmt.appId})`,
|
|
37536
37536
|
` table: ${target}`,
|
|
37537
37537
|
` scope: ${scope}`,
|
|
37538
37538
|
` by: ${byStr}`,
|
|
@@ -37666,195 +37666,177 @@ function buildBatchEnvelope(batch, options = {}) {
|
|
|
37666
37666
|
};
|
|
37667
37667
|
}
|
|
37668
37668
|
|
|
37669
|
-
// src/node/
|
|
37670
|
-
function
|
|
37671
|
-
|
|
37672
|
-
|
|
37673
|
-
|
|
37674
|
-
|
|
37675
|
-
|
|
37676
|
-
|
|
37677
|
-
|
|
37678
|
-
|
|
37679
|
-
|
|
37680
|
-
|
|
37669
|
+
// src/node/sqlDiagnostics.ts
|
|
37670
|
+
function restoreSqlDiagnosticValue(value, bindings) {
|
|
37671
|
+
if (typeof value === "string") {
|
|
37672
|
+
const dmlTarget = value.match(/^(\s*target:\s*)APP(\d+) \((\d+)\)\s*$/);
|
|
37673
|
+
if (dmlTarget && dmlTarget[2] === dmlTarget[3]) {
|
|
37674
|
+
const binding = bindings.get(Number(dmlTarget[2]));
|
|
37675
|
+
if (binding) {
|
|
37676
|
+
const target = binding.source === "logical" ? `LAPP_${binding.logicalName} -> APP${binding.appId}@${binding.profile}` : `APP${binding.appId}@${binding.profile}`;
|
|
37677
|
+
return `${dmlTarget[1]}${target}`;
|
|
37678
|
+
}
|
|
37679
|
+
}
|
|
37680
|
+
let restored = value;
|
|
37681
|
+
for (const binding of bindings.values()) {
|
|
37682
|
+
const internal = `APP${binding.mappedAppId}`;
|
|
37683
|
+
const display = binding.source === "logical" ? `LAPP_${binding.logicalName}@${binding.profile}` : `APP${binding.appId}@${binding.profile}`;
|
|
37684
|
+
restored = restored.split(`${internal} (${binding.mappedAppId})`).join(display).split(internal).join(display);
|
|
37685
|
+
}
|
|
37686
|
+
return restored;
|
|
37681
37687
|
}
|
|
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;
|
|
37688
|
+
if (Array.isArray(value)) {
|
|
37689
|
+
return value.map((item) => restoreSqlDiagnosticValue(item, bindings));
|
|
37721
37690
|
}
|
|
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);
|
|
37691
|
+
if (value !== null && typeof value === "object") {
|
|
37692
|
+
return Object.fromEntries(
|
|
37693
|
+
Object.entries(value).map(([key, item]) => [key, restoreSqlDiagnosticValue(item, bindings)])
|
|
37694
|
+
);
|
|
37730
37695
|
}
|
|
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
|
-
};
|
|
37696
|
+
return value;
|
|
37742
37697
|
}
|
|
37743
|
-
function
|
|
37744
|
-
|
|
37745
|
-
let
|
|
37746
|
-
|
|
37747
|
-
|
|
37748
|
-
|
|
37749
|
-
|
|
37750
|
-
|
|
37751
|
-
|
|
37752
|
-
|
|
37753
|
-
|
|
37754
|
-
|
|
37755
|
-
|
|
37756
|
-
|
|
37757
|
-
|
|
37758
|
-
|
|
37759
|
-
|
|
37698
|
+
function restoreSqlContextError(err, sourceSql, context) {
|
|
37699
|
+
if (!(err instanceof Error)) return err;
|
|
37700
|
+
let message = err.message;
|
|
37701
|
+
for (const binding of context.bindings.values()) {
|
|
37702
|
+
if (binding.source === "logical") {
|
|
37703
|
+
message = message.split(`APP${binding.mappedAppId}`).join(`LAPP_${binding.logicalName}@${binding.profile}`);
|
|
37704
|
+
}
|
|
37705
|
+
}
|
|
37706
|
+
const token = err.token;
|
|
37707
|
+
if (typeof token?.pos === "number") {
|
|
37708
|
+
const segment = context.rewriteSegments.find(
|
|
37709
|
+
(candidate) => token.pos >= candidate.normalizedStart && token.pos < candidate.normalizedEnd
|
|
37710
|
+
);
|
|
37711
|
+
if (segment) {
|
|
37712
|
+
const sourcePos = segment.sourceStart + Math.min(
|
|
37713
|
+
token.pos - segment.normalizedStart,
|
|
37714
|
+
Math.max(0, segment.sourceEnd - segment.sourceStart - 1)
|
|
37715
|
+
);
|
|
37716
|
+
message = message.replace(/(位置 \d+、トークン:/, `\uFF08\u4F4D\u7F6E ${sourcePos}\u3001\u30C8\u30FC\u30AF\u30F3:`);
|
|
37717
|
+
const originalRef = sourceSql.slice(segment.sourceStart, segment.sourceEnd);
|
|
37718
|
+
if (segment.bindingMappedAppId !== void 0 && originalRef) {
|
|
37719
|
+
message = message.replace(/(トークン: 「)[^」]*(」)/, `$1${originalRef}$2`);
|
|
37760
37720
|
}
|
|
37761
|
-
continue;
|
|
37762
37721
|
}
|
|
37763
|
-
|
|
37764
|
-
|
|
37765
|
-
|
|
37766
|
-
|
|
37767
|
-
|
|
37722
|
+
}
|
|
37723
|
+
err.message = message;
|
|
37724
|
+
return err;
|
|
37725
|
+
}
|
|
37726
|
+
|
|
37727
|
+
// src/node/config.ts
|
|
37728
|
+
var import_fs = require("fs");
|
|
37729
|
+
var LOGICAL_APP_NAME_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
|
|
37730
|
+
var PHYSICAL_APP_KEY_RE = /^APP\d+$/i;
|
|
37731
|
+
var NUMERIC_APP_KEY_RE = /^\d+$/;
|
|
37732
|
+
var LOGICAL_SQL_KEY_RE = /^LAPP_/i;
|
|
37733
|
+
function argumentError(message) {
|
|
37734
|
+
return new Error(`ArgumentError: ${message}`);
|
|
37735
|
+
}
|
|
37736
|
+
function normalizeLogicalApps(profileName, value) {
|
|
37737
|
+
if (value === void 0) return void 0;
|
|
37738
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
37739
|
+
throw argumentError(`logicalApps for profile "${profileName}" must be an object.`);
|
|
37740
|
+
}
|
|
37741
|
+
const normalized = {};
|
|
37742
|
+
const physicalIdOwners = /* @__PURE__ */ new Map();
|
|
37743
|
+
for (const [rawName, rawAppId] of Object.entries(value)) {
|
|
37744
|
+
if (PHYSICAL_APP_KEY_RE.test(rawName) || NUMERIC_APP_KEY_RE.test(rawName) || LOGICAL_SQL_KEY_RE.test(rawName)) {
|
|
37745
|
+
throw argumentError(
|
|
37746
|
+
`logical app key "${rawName}" in profile "${profileName}" must be a logical name without APP, numeric, or LAPP_ syntax.`
|
|
37747
|
+
);
|
|
37768
37748
|
}
|
|
37769
|
-
if (
|
|
37770
|
-
|
|
37771
|
-
|
|
37772
|
-
|
|
37749
|
+
if (!LOGICAL_APP_NAME_RE.test(rawName)) {
|
|
37750
|
+
throw argumentError(
|
|
37751
|
+
`logical app key "${rawName}" in profile "${profileName}" must match [A-Z][A-Z0-9_]{0,63}.`
|
|
37752
|
+
);
|
|
37773
37753
|
}
|
|
37774
|
-
|
|
37775
|
-
|
|
37776
|
-
|
|
37777
|
-
|
|
37778
|
-
|
|
37779
|
-
break;
|
|
37780
|
-
}
|
|
37781
|
-
i++;
|
|
37782
|
-
}
|
|
37783
|
-
continue;
|
|
37754
|
+
const logicalName = rawName.toUpperCase();
|
|
37755
|
+
if (Object.prototype.hasOwnProperty.call(normalized, logicalName)) {
|
|
37756
|
+
throw argumentError(
|
|
37757
|
+
`logical app name "${logicalName}" is duplicated after case normalization in profile "${profileName}".`
|
|
37758
|
+
);
|
|
37784
37759
|
}
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
|
|
37788
|
-
|
|
37760
|
+
if (typeof rawAppId !== "number" || !Number.isSafeInteger(rawAppId) || rawAppId <= 0) {
|
|
37761
|
+
throw argumentError(
|
|
37762
|
+
`physical app ID for logical app "${logicalName}" in profile "${profileName}" must be a positive safe integer.`
|
|
37763
|
+
);
|
|
37789
37764
|
}
|
|
37790
|
-
|
|
37791
|
-
|
|
37765
|
+
const existingName = physicalIdOwners.get(rawAppId);
|
|
37766
|
+
if (existingName !== void 0) {
|
|
37767
|
+
throw argumentError(
|
|
37768
|
+
`logical apps "${existingName}" and "${logicalName}" in profile "${profileName}" map to the same physical app ID ${rawAppId}; physical app aliases are not supported yet.`
|
|
37769
|
+
);
|
|
37770
|
+
}
|
|
37771
|
+
physicalIdOwners.set(rawAppId, logicalName);
|
|
37772
|
+
normalized[logicalName] = rawAppId;
|
|
37792
37773
|
}
|
|
37793
|
-
return
|
|
37774
|
+
return normalized;
|
|
37794
37775
|
}
|
|
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());
|
|
37776
|
+
function validateKsqlConfig(config2) {
|
|
37777
|
+
if (config2 === null || typeof config2 !== "object" || Array.isArray(config2)) {
|
|
37778
|
+
throw argumentError("config must be an object.");
|
|
37814
37779
|
}
|
|
37815
|
-
|
|
37816
|
-
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
if (
|
|
37821
|
-
|
|
37822
|
-
|
|
37823
|
-
|
|
37824
|
-
|
|
37780
|
+
if (config2.profiles === void 0) return config2;
|
|
37781
|
+
if (config2.profiles === null || typeof config2.profiles !== "object" || Array.isArray(config2.profiles)) {
|
|
37782
|
+
throw argumentError("profiles must be an object.");
|
|
37783
|
+
}
|
|
37784
|
+
for (const [profileName, profile2] of Object.entries(config2.profiles)) {
|
|
37785
|
+
if (profile2 === null || typeof profile2 !== "object" || Array.isArray(profile2)) {
|
|
37786
|
+
throw argumentError(`profile "${profileName}" must be an object.`);
|
|
37787
|
+
}
|
|
37788
|
+
if (profile2.allowPhysicalAppRefs !== void 0 && typeof profile2.allowPhysicalAppRefs !== "boolean") {
|
|
37789
|
+
throw argumentError(`allowPhysicalAppRefs for profile "${profileName}" must be boolean.`);
|
|
37825
37790
|
}
|
|
37791
|
+
const logicalApps = normalizeLogicalApps(profileName, profile2.logicalApps);
|
|
37792
|
+
if (logicalApps !== void 0) profile2.logicalApps = logicalApps;
|
|
37826
37793
|
}
|
|
37827
|
-
|
|
37828
|
-
|
|
37829
|
-
|
|
37830
|
-
|
|
37831
|
-
|
|
37832
|
-
|
|
37833
|
-
|
|
37834
|
-
|
|
37835
|
-
|
|
37836
|
-
|
|
37837
|
-
|
|
37838
|
-
|
|
37794
|
+
return config2;
|
|
37795
|
+
}
|
|
37796
|
+
function createAppResolutionContext(config2, defaultProfile) {
|
|
37797
|
+
const profiles = Object.fromEntries(
|
|
37798
|
+
Object.entries(config2.profiles ?? {}).map(([name, profile2]) => [
|
|
37799
|
+
name,
|
|
37800
|
+
{
|
|
37801
|
+
logicalApps: profile2.logicalApps === void 0 ? void 0 : { ...profile2.logicalApps },
|
|
37802
|
+
allowPhysicalAppRefs: profile2.allowPhysicalAppRefs
|
|
37803
|
+
}
|
|
37804
|
+
])
|
|
37805
|
+
);
|
|
37806
|
+
const implicitDefaultProfile = {};
|
|
37807
|
+
function requireProfile(profileName) {
|
|
37808
|
+
const profile2 = profiles[profileName];
|
|
37809
|
+
if (!profile2 && profileName === defaultProfile) return implicitDefaultProfile;
|
|
37810
|
+
if (!profile2) throw argumentError(`profile "${profileName}" is not defined.`);
|
|
37811
|
+
return profile2;
|
|
37839
37812
|
}
|
|
37840
|
-
out.push(sql.slice(cursor));
|
|
37841
37813
|
return {
|
|
37842
|
-
|
|
37843
|
-
|
|
37844
|
-
|
|
37814
|
+
resolveLogicalApp(name, profile2) {
|
|
37815
|
+
if (!LOGICAL_APP_NAME_RE.test(name)) {
|
|
37816
|
+
throw argumentError(`logical app name "${name}" must match [A-Z][A-Z0-9_]{0,63}.`);
|
|
37817
|
+
}
|
|
37818
|
+
const profileName = profile2 || defaultProfile;
|
|
37819
|
+
const logicalName = name.toUpperCase();
|
|
37820
|
+
const appId = requireProfile(profileName).logicalApps?.[logicalName];
|
|
37821
|
+
if (appId === void 0) {
|
|
37822
|
+
throw argumentError(`logical app LAPP_${logicalName}@${profileName} is not defined.`);
|
|
37823
|
+
}
|
|
37824
|
+
return appId;
|
|
37825
|
+
},
|
|
37826
|
+
assertPhysicalAppAllowed(profile2) {
|
|
37827
|
+
const profileName = profile2 || defaultProfile;
|
|
37828
|
+
if (!profiles[profileName]) return;
|
|
37829
|
+
if (requireProfile(profileName).allowPhysicalAppRefs === false) {
|
|
37830
|
+
throw argumentError(
|
|
37831
|
+
`physical app references are not allowed for profile "${profileName}"; use LAPP_<NAME>.`
|
|
37832
|
+
);
|
|
37833
|
+
}
|
|
37834
|
+
}
|
|
37845
37835
|
};
|
|
37846
37836
|
}
|
|
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
37837
|
function loadKsqlConfig(configPath) {
|
|
37856
37838
|
const raw = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
37857
|
-
return JSON.parse(raw);
|
|
37839
|
+
return validateKsqlConfig(JSON.parse(raw));
|
|
37858
37840
|
}
|
|
37859
37841
|
function loadOptionalKsqlConfig(configPath) {
|
|
37860
37842
|
if (!(0, import_fs.existsSync)(configPath)) return {};
|
|
@@ -38051,11 +38033,19 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
38051
38033
|
);
|
|
38052
38034
|
}
|
|
38053
38035
|
}
|
|
38054
|
-
const
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38036
|
+
const controller = new AbortController();
|
|
38037
|
+
const timeout2 = setTimeout(() => controller.abort(), timeoutMs);
|
|
38038
|
+
timeout2.unref?.();
|
|
38039
|
+
let res;
|
|
38040
|
+
try {
|
|
38041
|
+
res = await fetch(url2, {
|
|
38042
|
+
...init,
|
|
38043
|
+
headers,
|
|
38044
|
+
signal: controller.signal
|
|
38045
|
+
});
|
|
38046
|
+
} finally {
|
|
38047
|
+
clearTimeout(timeout2);
|
|
38048
|
+
}
|
|
38059
38049
|
if (!res.ok) {
|
|
38060
38050
|
const bodyText = await res.text();
|
|
38061
38051
|
if (tokenResolver.debug) {
|
|
@@ -38223,17 +38213,376 @@ function detectSortKind(fieldType, calcFormat) {
|
|
|
38223
38213
|
return void 0;
|
|
38224
38214
|
}
|
|
38225
38215
|
|
|
38216
|
+
// src/node/appProfiles.ts
|
|
38217
|
+
function parseTokenMap(raw) {
|
|
38218
|
+
const out = {};
|
|
38219
|
+
if (!raw.trim()) return out;
|
|
38220
|
+
const pairs = raw.split(",");
|
|
38221
|
+
for (const pair of pairs) {
|
|
38222
|
+
const idx = pair.indexOf("=");
|
|
38223
|
+
if (idx <= 0) throw new Error("ArgumentError: --token-map must be APPxxx=token pairs.");
|
|
38224
|
+
const key = normalizeAppKey(pair.slice(0, idx).trim());
|
|
38225
|
+
const value = pair.slice(idx + 1).trim();
|
|
38226
|
+
if (!value) throw new Error(`ArgumentError: token is empty for ${key}.`);
|
|
38227
|
+
out[key] = value;
|
|
38228
|
+
}
|
|
38229
|
+
return out;
|
|
38230
|
+
}
|
|
38231
|
+
function normalizeAppKey(v) {
|
|
38232
|
+
const m1 = v.match(/^APP(\d+)$/i);
|
|
38233
|
+
if (m1) return `APP${m1[1]}`;
|
|
38234
|
+
const m2 = v.match(/^(\d+)$/);
|
|
38235
|
+
if (m2) return `APP${m2[1]}`;
|
|
38236
|
+
throw new Error(`ArgumentError: invalid app key "${v}"`);
|
|
38237
|
+
}
|
|
38238
|
+
function extractAppIds(sql) {
|
|
38239
|
+
const out = /* @__PURE__ */ new Set();
|
|
38240
|
+
for (const t of collectAppProfileTokens(sql)) {
|
|
38241
|
+
if (t.source === "physical") out.add(t.appId);
|
|
38242
|
+
}
|
|
38243
|
+
return [...out];
|
|
38244
|
+
}
|
|
38245
|
+
function isSqlIdentContinue(ch) {
|
|
38246
|
+
if (!ch) return false;
|
|
38247
|
+
const cp = ch.codePointAt(0);
|
|
38248
|
+
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;
|
|
38249
|
+
}
|
|
38250
|
+
function isProfileNameChar(ch) {
|
|
38251
|
+
if (!ch) return false;
|
|
38252
|
+
const cp = ch.codePointAt(0);
|
|
38253
|
+
return cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp >= 48 && cp <= 57 || ch === "_" || ch === "-" || ch === "." || ch === "$";
|
|
38254
|
+
}
|
|
38255
|
+
function isAsciiLogicalNameStart(ch) {
|
|
38256
|
+
return /^[A-Za-z]$/.test(ch);
|
|
38257
|
+
}
|
|
38258
|
+
function isAsciiLogicalNameContinue(ch) {
|
|
38259
|
+
return /^[A-Za-z0-9_]$/.test(ch);
|
|
38260
|
+
}
|
|
38261
|
+
function tryParseAppProfileToken(sql, start) {
|
|
38262
|
+
const prev = start > 0 ? sql[start - 1] : "";
|
|
38263
|
+
if (isSqlIdentContinue(prev)) return null;
|
|
38264
|
+
let source;
|
|
38265
|
+
let appId;
|
|
38266
|
+
let logicalName;
|
|
38267
|
+
let referenceValueStart;
|
|
38268
|
+
let referenceValueEnd;
|
|
38269
|
+
let i;
|
|
38270
|
+
if (sql.slice(start, start + 5).toUpperCase() === "LAPP_") {
|
|
38271
|
+
source = "logical";
|
|
38272
|
+
i = start + 5;
|
|
38273
|
+
referenceValueStart = i;
|
|
38274
|
+
if (!isAsciiLogicalNameStart(sql[i] ?? "")) return null;
|
|
38275
|
+
i++;
|
|
38276
|
+
while (i < sql.length && isAsciiLogicalNameContinue(sql[i])) i++;
|
|
38277
|
+
referenceValueEnd = i;
|
|
38278
|
+
if (referenceValueEnd - referenceValueStart > 64) return null;
|
|
38279
|
+
logicalName = sql.slice(referenceValueStart, referenceValueEnd).toUpperCase();
|
|
38280
|
+
} else if (sql.slice(start, start + 3).toUpperCase() === "APP") {
|
|
38281
|
+
source = "physical";
|
|
38282
|
+
i = start + 3;
|
|
38283
|
+
referenceValueStart = i;
|
|
38284
|
+
while (i < sql.length && /[0-9]/.test(sql[i])) i++;
|
|
38285
|
+
referenceValueEnd = i;
|
|
38286
|
+
if (referenceValueEnd === referenceValueStart) return null;
|
|
38287
|
+
appId = Number(sql.slice(referenceValueStart, referenceValueEnd));
|
|
38288
|
+
} else {
|
|
38289
|
+
return null;
|
|
38290
|
+
}
|
|
38291
|
+
if (sql[i] === "$") {
|
|
38292
|
+
i++;
|
|
38293
|
+
const subStart = i;
|
|
38294
|
+
while (i < sql.length && isSqlIdentContinue(sql[i])) i++;
|
|
38295
|
+
if (i === subStart) return null;
|
|
38296
|
+
}
|
|
38297
|
+
const appEnd = i;
|
|
38298
|
+
let profile2 = null;
|
|
38299
|
+
if (sql[i] === "@") {
|
|
38300
|
+
i++;
|
|
38301
|
+
const pStart = i;
|
|
38302
|
+
while (i < sql.length && isProfileNameChar(sql[i])) i++;
|
|
38303
|
+
if (i === pStart) return null;
|
|
38304
|
+
profile2 = sql.slice(pStart, i);
|
|
38305
|
+
}
|
|
38306
|
+
const next = i < sql.length ? sql[i] : "";
|
|
38307
|
+
if (isSqlIdentContinue(next)) return null;
|
|
38308
|
+
const common = {
|
|
38309
|
+
profile: profile2,
|
|
38310
|
+
start,
|
|
38311
|
+
referenceValueStart,
|
|
38312
|
+
referenceValueEnd,
|
|
38313
|
+
appEnd,
|
|
38314
|
+
fullEnd: i
|
|
38315
|
+
};
|
|
38316
|
+
return source === "physical" ? { ...common, source, appId } : { ...common, source, logicalName };
|
|
38317
|
+
}
|
|
38318
|
+
function collectAppProfileTokens(sql) {
|
|
38319
|
+
const tokens = [];
|
|
38320
|
+
let i = 0;
|
|
38321
|
+
while (i < sql.length) {
|
|
38322
|
+
const ch = sql[i];
|
|
38323
|
+
if (ch === "'") {
|
|
38324
|
+
i++;
|
|
38325
|
+
while (i < sql.length) {
|
|
38326
|
+
if (sql[i] === "'") {
|
|
38327
|
+
i++;
|
|
38328
|
+
if (i < sql.length && sql[i] === "'") {
|
|
38329
|
+
i++;
|
|
38330
|
+
continue;
|
|
38331
|
+
}
|
|
38332
|
+
break;
|
|
38333
|
+
}
|
|
38334
|
+
i++;
|
|
38335
|
+
}
|
|
38336
|
+
continue;
|
|
38337
|
+
}
|
|
38338
|
+
if (ch === "`") {
|
|
38339
|
+
i++;
|
|
38340
|
+
while (i < sql.length && sql[i] !== "`") i++;
|
|
38341
|
+
if (i < sql.length) i++;
|
|
38342
|
+
continue;
|
|
38343
|
+
}
|
|
38344
|
+
if (ch === "-" && sql[i + 1] === "-") {
|
|
38345
|
+
i += 2;
|
|
38346
|
+
while (i < sql.length && sql[i] !== "\n") i++;
|
|
38347
|
+
continue;
|
|
38348
|
+
}
|
|
38349
|
+
if (ch === "/" && sql[i + 1] === "*") {
|
|
38350
|
+
i += 2;
|
|
38351
|
+
while (i < sql.length) {
|
|
38352
|
+
if (sql[i] === "*" && sql[i + 1] === "/") {
|
|
38353
|
+
i += 2;
|
|
38354
|
+
break;
|
|
38355
|
+
}
|
|
38356
|
+
i++;
|
|
38357
|
+
}
|
|
38358
|
+
continue;
|
|
38359
|
+
}
|
|
38360
|
+
const parsed = tryParseAppProfileToken(sql, i);
|
|
38361
|
+
if (!parsed) {
|
|
38362
|
+
i++;
|
|
38363
|
+
continue;
|
|
38364
|
+
}
|
|
38365
|
+
tokens.push(parsed);
|
|
38366
|
+
i = parsed.fullEnd;
|
|
38367
|
+
}
|
|
38368
|
+
return tokens;
|
|
38369
|
+
}
|
|
38370
|
+
function nextVirtualAppId(used) {
|
|
38371
|
+
let id = 9e8;
|
|
38372
|
+
while (used.has(id)) id++;
|
|
38373
|
+
used.add(id);
|
|
38374
|
+
return id;
|
|
38375
|
+
}
|
|
38376
|
+
function normalizeSqlAppProfiles(sql, defaultProfile = "dev", resolutionContext) {
|
|
38377
|
+
const tokens = collectAppProfileTokens(sql);
|
|
38378
|
+
const hasProfileSyntax = tokens.some((t) => t.profile !== null);
|
|
38379
|
+
const profilesByApp = /* @__PURE__ */ new Map();
|
|
38380
|
+
const normalizedProfile = (profile2) => profile2 ?? defaultProfile;
|
|
38381
|
+
for (const t of tokens) {
|
|
38382
|
+
if (t.source !== "physical") continue;
|
|
38383
|
+
const p = normalizedProfile(t.profile);
|
|
38384
|
+
let set2 = profilesByApp.get(t.appId);
|
|
38385
|
+
if (!set2) {
|
|
38386
|
+
set2 = /* @__PURE__ */ new Set();
|
|
38387
|
+
profilesByApp.set(t.appId, set2);
|
|
38388
|
+
}
|
|
38389
|
+
set2.add(p.toLowerCase());
|
|
38390
|
+
}
|
|
38391
|
+
const usedAppIds = new Set(
|
|
38392
|
+
tokens.filter((t) => t.source === "physical").map((t) => t.appId)
|
|
38393
|
+
);
|
|
38394
|
+
const resolvedLogicalApps = /* @__PURE__ */ new Map();
|
|
38395
|
+
for (const t of tokens) {
|
|
38396
|
+
if (t.source !== "logical") continue;
|
|
38397
|
+
const pLower = normalizedProfile(t.profile).toLowerCase();
|
|
38398
|
+
const logicalKey = `logical:${t.logicalName}@${pLower}`;
|
|
38399
|
+
if (resolvedLogicalApps.has(logicalKey)) continue;
|
|
38400
|
+
if (!resolutionContext) {
|
|
38401
|
+
throw new Error(
|
|
38402
|
+
`ArgumentError: logical app LAPP_${t.logicalName}@${pLower} requires logicalApps configuration.`
|
|
38403
|
+
);
|
|
38404
|
+
}
|
|
38405
|
+
const resolvedAppId = resolutionContext.resolveLogicalApp(t.logicalName, pLower);
|
|
38406
|
+
resolvedLogicalApps.set(logicalKey, resolvedAppId);
|
|
38407
|
+
usedAppIds.add(resolvedAppId);
|
|
38408
|
+
}
|
|
38409
|
+
const pairToMapped = /* @__PURE__ */ new Map();
|
|
38410
|
+
const appBindingByMappedApp = /* @__PURE__ */ new Map();
|
|
38411
|
+
for (const [appId, pSet] of profilesByApp.entries()) {
|
|
38412
|
+
const profiles = [...pSet].sort();
|
|
38413
|
+
if (profiles.length <= 1) continue;
|
|
38414
|
+
for (const pLower of profiles) {
|
|
38415
|
+
const mapped = nextVirtualAppId(usedAppIds);
|
|
38416
|
+
pairToMapped.set(`physical:${appId}@${pLower}`, mapped);
|
|
38417
|
+
appBindingByMappedApp.set(mapped, {
|
|
38418
|
+
source: "physical",
|
|
38419
|
+
mappedAppId: mapped,
|
|
38420
|
+
appId,
|
|
38421
|
+
profile: pLower
|
|
38422
|
+
});
|
|
38423
|
+
}
|
|
38424
|
+
}
|
|
38425
|
+
const out = [];
|
|
38426
|
+
const rewriteSegments = [];
|
|
38427
|
+
let normalizedLength = 0;
|
|
38428
|
+
let cursor = 0;
|
|
38429
|
+
const appendSegment = (text, sourceStart, sourceEnd, bindingMappedAppId) => {
|
|
38430
|
+
if (!text && sourceStart === sourceEnd) return;
|
|
38431
|
+
const normalizedStart = normalizedLength;
|
|
38432
|
+
out.push(text);
|
|
38433
|
+
normalizedLength += text.length;
|
|
38434
|
+
rewriteSegments.push({
|
|
38435
|
+
normalizedStart,
|
|
38436
|
+
normalizedEnd: normalizedLength,
|
|
38437
|
+
sourceStart,
|
|
38438
|
+
sourceEnd,
|
|
38439
|
+
...bindingMappedAppId === void 0 ? {} : { bindingMappedAppId }
|
|
38440
|
+
});
|
|
38441
|
+
};
|
|
38442
|
+
for (const t of tokens) {
|
|
38443
|
+
const p = normalizedProfile(t.profile);
|
|
38444
|
+
const pLower = p.toLowerCase();
|
|
38445
|
+
let binding;
|
|
38446
|
+
if (t.source === "physical") {
|
|
38447
|
+
const mapped = pairToMapped.get(`physical:${t.appId}@${pLower}`) ?? t.appId;
|
|
38448
|
+
binding = {
|
|
38449
|
+
source: "physical",
|
|
38450
|
+
mappedAppId: mapped,
|
|
38451
|
+
appId: t.appId,
|
|
38452
|
+
profile: pLower
|
|
38453
|
+
};
|
|
38454
|
+
} else {
|
|
38455
|
+
const logicalKey = `logical:${t.logicalName}@${pLower}`;
|
|
38456
|
+
let mapped = pairToMapped.get(logicalKey);
|
|
38457
|
+
if (mapped === void 0) {
|
|
38458
|
+
mapped = nextVirtualAppId(usedAppIds);
|
|
38459
|
+
pairToMapped.set(logicalKey, mapped);
|
|
38460
|
+
}
|
|
38461
|
+
binding = {
|
|
38462
|
+
source: "logical",
|
|
38463
|
+
logicalName: t.logicalName,
|
|
38464
|
+
mappedAppId: mapped,
|
|
38465
|
+
appId: resolvedLogicalApps.get(logicalKey),
|
|
38466
|
+
profile: pLower
|
|
38467
|
+
};
|
|
38468
|
+
}
|
|
38469
|
+
appBindingByMappedApp.set(binding.mappedAppId, binding);
|
|
38470
|
+
appendSegment(sql.slice(cursor, t.start), cursor, t.start);
|
|
38471
|
+
const subtableSuffix = sql.slice(t.referenceValueEnd, t.appEnd);
|
|
38472
|
+
const normalizedReference = t.source === "physical" ? `${sql.slice(t.start, t.referenceValueStart)}${binding.mappedAppId}${subtableSuffix}` : `APP${binding.mappedAppId}${subtableSuffix}`;
|
|
38473
|
+
appendSegment(
|
|
38474
|
+
normalizedReference,
|
|
38475
|
+
t.start,
|
|
38476
|
+
t.fullEnd,
|
|
38477
|
+
binding.mappedAppId
|
|
38478
|
+
);
|
|
38479
|
+
cursor = t.fullEnd;
|
|
38480
|
+
}
|
|
38481
|
+
appendSegment(sql.slice(cursor), cursor, sql.length);
|
|
38482
|
+
return {
|
|
38483
|
+
normalizedSql: out.join(""),
|
|
38484
|
+
hasProfileSyntax,
|
|
38485
|
+
appBindingByMappedApp,
|
|
38486
|
+
rewriteSegments
|
|
38487
|
+
};
|
|
38488
|
+
}
|
|
38489
|
+
function buildCacheContext(defaultProfile, appBindingByMappedApp) {
|
|
38490
|
+
if (appBindingByMappedApp.size === 0) return `default:${defaultProfile.toLowerCase()}`;
|
|
38491
|
+
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}`);
|
|
38492
|
+
return `apps:${pairs.join(",")}`;
|
|
38493
|
+
}
|
|
38494
|
+
|
|
38226
38495
|
// src/node/runtime.ts
|
|
38496
|
+
var privateConfigSnapshots = /* @__PURE__ */ new WeakMap();
|
|
38497
|
+
function cloneConfigSnapshot(config2) {
|
|
38498
|
+
return JSON.parse(JSON.stringify(config2));
|
|
38499
|
+
}
|
|
38500
|
+
function toConfigView(config2) {
|
|
38501
|
+
const profiles = Object.fromEntries(Object.entries(config2.profiles ?? {}).map(([name, p]) => [name, {
|
|
38502
|
+
baseUrl: p.baseUrl,
|
|
38503
|
+
logicalApps: p.logicalApps === void 0 ? void 0 : Object.freeze({ ...p.logicalApps }),
|
|
38504
|
+
allowPhysicalAppRefs: p.allowPhysicalAppRefs,
|
|
38505
|
+
passwordEnv: p.passwordEnv,
|
|
38506
|
+
tokenMapSources: p.tokenMap === void 0 ? void 0 : Object.freeze(Object.fromEntries(
|
|
38507
|
+
Object.entries(p.tokenMap).map(([key, value]) => [key, String(value).startsWith("env:") ? String(value).slice(4) : "inline"])
|
|
38508
|
+
))
|
|
38509
|
+
}]));
|
|
38510
|
+
return Object.freeze({ defaultProfile: config2.defaultProfile, profiles: Object.freeze(profiles) });
|
|
38511
|
+
}
|
|
38512
|
+
function resolveSqlContext(serverOptions, sql, inputProfile) {
|
|
38513
|
+
const configPath = serverOptions.configPath ?? envString("KSQL_CONFIG") ?? "./ksql.config.json";
|
|
38514
|
+
const config2 = cloneConfigSnapshot(loadOptionalKsqlConfig(configPath));
|
|
38515
|
+
const profileName = resolveDefaultProfile(config2, serverOptions, inputProfile);
|
|
38516
|
+
const resolutionContext = createAppResolutionContext(config2, profileName);
|
|
38517
|
+
const normalized = normalizeSqlAppProfiles(sql, profileName, resolutionContext);
|
|
38518
|
+
const bindings = normalized.appBindingByMappedApp;
|
|
38519
|
+
for (const binding of bindings.values()) {
|
|
38520
|
+
if (binding.source === "physical") resolutionContext.assertPhysicalAppAllowed(binding.profile);
|
|
38521
|
+
}
|
|
38522
|
+
const context = {
|
|
38523
|
+
normalizedSql: normalized.normalizedSql,
|
|
38524
|
+
bindings,
|
|
38525
|
+
cacheContext: buildCacheContext(profileName, bindings),
|
|
38526
|
+
profileName,
|
|
38527
|
+
rewriteSegments: Object.freeze(normalized.rewriteSegments.map((segment) => Object.freeze({ ...segment }))),
|
|
38528
|
+
hasProfileSyntax: normalized.hasProfileSyntax,
|
|
38529
|
+
configSnapshot: toConfigView(config2),
|
|
38530
|
+
logicalBindingLabels: new Map(
|
|
38531
|
+
[...bindings.values()].filter((b) => b.source === "logical").map((b) => [b.mappedAppId, `LAPP_${b.logicalName}@${b.profile}`])
|
|
38532
|
+
)
|
|
38533
|
+
};
|
|
38534
|
+
Object.freeze(context);
|
|
38535
|
+
privateConfigSnapshots.set(context, config2);
|
|
38536
|
+
return context;
|
|
38537
|
+
}
|
|
38538
|
+
function resolveTokenByMappedApp(args) {
|
|
38539
|
+
const tokenByMappedApp = /* @__PURE__ */ new Map();
|
|
38540
|
+
const tokenByPhysicalApp = /* @__PURE__ */ new Map();
|
|
38541
|
+
const missing = [];
|
|
38542
|
+
for (const mappedAppId of args.mappedAppIds) {
|
|
38543
|
+
const binding = args.bindings.get(mappedAppId);
|
|
38544
|
+
if (!binding && args.logicalBindingLabels.has(mappedAppId)) {
|
|
38545
|
+
throw new Error(`InternalError: binding is missing for logical app ${args.logicalBindingLabels.get(mappedAppId)}.`);
|
|
38546
|
+
}
|
|
38547
|
+
const appId = binding?.appId ?? mappedAppId;
|
|
38548
|
+
const profile2 = binding?.profile ?? args.profileName;
|
|
38549
|
+
const fromMap = args.effectiveTokenMap[`APP${appId}`];
|
|
38550
|
+
if (fromMap) {
|
|
38551
|
+
const token = resolveTokenValue(fromMap);
|
|
38552
|
+
tokenByMappedApp.set(mappedAppId, token);
|
|
38553
|
+
tokenByPhysicalApp.set(appId, token);
|
|
38554
|
+
continue;
|
|
38555
|
+
}
|
|
38556
|
+
if (binding?.source !== "logical" && args.mappedAppIds.length === 1 && args.singleToken) {
|
|
38557
|
+
tokenByMappedApp.set(mappedAppId, args.singleToken);
|
|
38558
|
+
tokenByPhysicalApp.set(appId, args.singleToken);
|
|
38559
|
+
continue;
|
|
38560
|
+
}
|
|
38561
|
+
missing.push(binding?.source === "logical" ? `LAPP_${binding.logicalName} (APP${appId})@${profile2}` : `APP${appId}@${profile2}`);
|
|
38562
|
+
}
|
|
38563
|
+
return { tokenByMappedApp, tokenByPhysicalApp, missing };
|
|
38564
|
+
}
|
|
38565
|
+
function resolveRuntimeBinding(context, mappedAppId) {
|
|
38566
|
+
const binding = context.bindings.get(mappedAppId);
|
|
38567
|
+
if (binding) return binding;
|
|
38568
|
+
const logicalLabel = context.logicalBindingLabels.get(mappedAppId);
|
|
38569
|
+
if (logicalLabel) {
|
|
38570
|
+
throw new Error(`InternalError: binding is missing for logical app ${logicalLabel}.`);
|
|
38571
|
+
}
|
|
38572
|
+
return { appId: mappedAppId, profile: context.profileName.toLowerCase() };
|
|
38573
|
+
}
|
|
38227
38574
|
function resolveDefaultProfile(config2, serverOptions, inputProfile) {
|
|
38228
38575
|
return inputProfile ?? serverOptions.profile ?? envString("KSQL_PROFILE") ?? config2.defaultProfile ?? "dev";
|
|
38229
38576
|
}
|
|
38230
38577
|
async function createKsqlRuntime(serverOptions, input) {
|
|
38231
|
-
const
|
|
38232
|
-
const config2 =
|
|
38233
|
-
|
|
38578
|
+
const sqlContext = input.sqlContext ?? resolveSqlContext(serverOptions, input.sql, input.profile);
|
|
38579
|
+
const config2 = privateConfigSnapshots.get(sqlContext);
|
|
38580
|
+
if (!config2) {
|
|
38581
|
+
throw new Error("InternalError: private config snapshot is missing for resolved SQL context.");
|
|
38582
|
+
}
|
|
38583
|
+
const profileName = sqlContext.profileName;
|
|
38234
38584
|
const profile2 = config2.profiles?.[profileName] ?? {};
|
|
38235
|
-
const
|
|
38236
|
-
const sql = normalized.normalizedSql;
|
|
38585
|
+
const sql = sqlContext.normalizedSql;
|
|
38237
38586
|
const maxRecords2 = input.maxRecords ?? envInt("KSQL_MAX_RECORDS") ?? profile2.query?.maxRecords ?? 500;
|
|
38238
38587
|
const fetchParallel2 = input.fetchParallel ?? envInt("KSQL_FETCH_PARALLEL") ?? profile2.query?.fetchParallel ?? 3;
|
|
38239
38588
|
if (!Number.isInteger(fetchParallel2) || fetchParallel2 < 1 || fetchParallel2 > 10) {
|
|
@@ -38249,11 +38598,12 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38249
38598
|
for (const appId of appIds) {
|
|
38250
38599
|
appProfileByApp.set(
|
|
38251
38600
|
appId,
|
|
38252
|
-
|
|
38601
|
+
sqlContext.bindings.get(appId)?.profile ?? profileName.toLowerCase()
|
|
38253
38602
|
);
|
|
38254
38603
|
}
|
|
38255
38604
|
const usedProfiles = /* @__PURE__ */ new Set([...appProfileByApp.values(), profileName]);
|
|
38256
38605
|
const profileClientMap = /* @__PURE__ */ new Map();
|
|
38606
|
+
const allTokenByMappedApp = /* @__PURE__ */ new Map();
|
|
38257
38607
|
const missingAppProfiles = [];
|
|
38258
38608
|
const tokenMapEnv = envString("KSQL_TOKEN_MAP");
|
|
38259
38609
|
const mapFromEnv = tokenMapEnv ? parseTokenMap(tokenMapEnv) : {};
|
|
@@ -38291,21 +38641,19 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38291
38641
|
);
|
|
38292
38642
|
const effectiveTokenMap = { ...mapFromConfig, ...mapFromEnv };
|
|
38293
38643
|
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}`);
|
|
38644
|
+
const resolvedTokens = resolveTokenByMappedApp({
|
|
38645
|
+
mappedAppIds: assignedAppIds,
|
|
38646
|
+
profileName: pName,
|
|
38647
|
+
bindings: sqlContext.bindings,
|
|
38648
|
+
logicalBindingLabels: sqlContext.logicalBindingLabels,
|
|
38649
|
+
effectiveTokenMap,
|
|
38650
|
+
singleToken
|
|
38651
|
+
});
|
|
38652
|
+
const tokenByApp = resolvedTokens.tokenByPhysicalApp;
|
|
38653
|
+
for (const [mappedAppId, token] of resolvedTokens.tokenByMappedApp) {
|
|
38654
|
+
allTokenByMappedApp.set(mappedAppId, token);
|
|
38308
38655
|
}
|
|
38656
|
+
missingAppProfiles.push(...resolvedTokens.missing);
|
|
38309
38657
|
if (assignedAppIds.length === 0 && singleToken) {
|
|
38310
38658
|
tokenByApp.set(0, singleToken);
|
|
38311
38659
|
}
|
|
@@ -38328,38 +38676,43 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38328
38676
|
if (missingAppProfiles.length > 0) {
|
|
38329
38677
|
throw new Error(`AuthError: token is missing for ${missingAppProfiles.join(", ")}.`);
|
|
38330
38678
|
}
|
|
38331
|
-
const
|
|
38679
|
+
const runtimeContext = {
|
|
38680
|
+
sqlContext,
|
|
38681
|
+
tokenByMappedApp: allTokenByMappedApp,
|
|
38682
|
+
clientsByProfile: profileClientMap
|
|
38683
|
+
};
|
|
38684
|
+
const defaultClient = runtimeContext.clientsByProfile.get(profileName);
|
|
38332
38685
|
if (!defaultClient) {
|
|
38333
38686
|
throw new Error(`AuthError: profile client is not resolved for "${profileName}".`);
|
|
38334
38687
|
}
|
|
38335
38688
|
const routedClient = {
|
|
38336
38689
|
getRecords: (params) => {
|
|
38337
|
-
const binding =
|
|
38338
|
-
const routed =
|
|
38690
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38691
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38339
38692
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38340
38693
|
return routed.getRecords({ ...params, app: binding.appId });
|
|
38341
38694
|
},
|
|
38342
38695
|
postRecords: (params) => {
|
|
38343
|
-
const binding =
|
|
38344
|
-
const routed =
|
|
38696
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38697
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38345
38698
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38346
38699
|
return routed.postRecords({ ...params, app: binding.appId });
|
|
38347
38700
|
},
|
|
38348
38701
|
putRecords: (params) => {
|
|
38349
|
-
const binding =
|
|
38350
|
-
const routed =
|
|
38702
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38703
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38351
38704
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38352
38705
|
return routed.putRecords({ ...params, app: binding.appId });
|
|
38353
38706
|
},
|
|
38354
38707
|
deleteRecords: (params) => {
|
|
38355
|
-
const binding =
|
|
38356
|
-
const routed =
|
|
38708
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, params.app);
|
|
38709
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38357
38710
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${params.app}.`);
|
|
38358
38711
|
return routed.deleteRecords({ ...params, app: binding.appId });
|
|
38359
38712
|
},
|
|
38360
38713
|
getFields: (appId) => {
|
|
38361
|
-
const binding =
|
|
38362
|
-
const routed =
|
|
38714
|
+
const binding = resolveRuntimeBinding(runtimeContext.sqlContext, appId);
|
|
38715
|
+
const routed = runtimeContext.clientsByProfile.get(binding.profile);
|
|
38363
38716
|
if (!routed) throw new Error(`AuthError: profile "${binding.profile}" is not resolved for APP${appId}.`);
|
|
38364
38717
|
return routed.getFields(binding.appId);
|
|
38365
38718
|
},
|
|
@@ -38378,7 +38731,7 @@ async function createKsqlRuntime(serverOptions, input) {
|
|
|
38378
38731
|
sql,
|
|
38379
38732
|
profileName,
|
|
38380
38733
|
client: gatedClient,
|
|
38381
|
-
cacheContext:
|
|
38734
|
+
cacheContext: sqlContext.cacheContext,
|
|
38382
38735
|
maxRecords: maxRecords2,
|
|
38383
38736
|
fetchParallel: fetchParallel2,
|
|
38384
38737
|
onLimit: onLimit2,
|
|
@@ -38590,11 +38943,6 @@ function noOpClient() {
|
|
|
38590
38943
|
getFields: fail
|
|
38591
38944
|
};
|
|
38592
38945
|
}
|
|
38593
|
-
function getToolProfile(serverOptions, inputProfile) {
|
|
38594
|
-
const configPath = getServerConfigPath(serverOptions);
|
|
38595
|
-
const config2 = loadOptionalKsqlConfig(configPath);
|
|
38596
|
-
return resolveDefaultProfile(config2, serverOptions, inputProfile);
|
|
38597
|
-
}
|
|
38598
38946
|
function getServerConfigPath(serverOptions) {
|
|
38599
38947
|
return serverOptions.configPath ?? envString("KSQL_CONFIG") ?? "./ksql.config.json";
|
|
38600
38948
|
}
|
|
@@ -38607,16 +38955,34 @@ function getSavedQueryCatalogPath(serverOptions) {
|
|
|
38607
38955
|
});
|
|
38608
38956
|
}
|
|
38609
38957
|
function normalizeSqlForTool(serverOptions, sql, inputProfile) {
|
|
38610
|
-
const
|
|
38611
|
-
const normalized = normalizeSqlAppProfiles(sql, profileName);
|
|
38958
|
+
const sqlContext = resolveSqlContext(serverOptions, sql, inputProfile);
|
|
38612
38959
|
return {
|
|
38613
|
-
profileName,
|
|
38614
|
-
normalizedSql:
|
|
38615
|
-
hasProfileSyntax:
|
|
38616
|
-
appBindingByMappedApp:
|
|
38617
|
-
cacheContext:
|
|
38960
|
+
profileName: sqlContext.profileName,
|
|
38961
|
+
normalizedSql: sqlContext.normalizedSql,
|
|
38962
|
+
hasProfileSyntax: sqlContext.hasProfileSyntax,
|
|
38963
|
+
appBindingByMappedApp: sqlContext.bindings,
|
|
38964
|
+
cacheContext: sqlContext.cacheContext,
|
|
38965
|
+
sqlContext,
|
|
38966
|
+
sourceSql: sql
|
|
38967
|
+
};
|
|
38968
|
+
}
|
|
38969
|
+
function toValidationBinding(mappedAppId, binding) {
|
|
38970
|
+
return binding.source === "logical" ? {
|
|
38971
|
+
source: binding.source,
|
|
38972
|
+
logicalName: binding.logicalName,
|
|
38973
|
+
mappedAppId,
|
|
38974
|
+
appId: binding.appId,
|
|
38975
|
+
profile: binding.profile
|
|
38976
|
+
} : {
|
|
38977
|
+
source: binding.source,
|
|
38978
|
+
mappedAppId,
|
|
38979
|
+
appId: binding.appId,
|
|
38980
|
+
profile: binding.profile
|
|
38618
38981
|
};
|
|
38619
38982
|
}
|
|
38983
|
+
function toExplainBindings(bindings) {
|
|
38984
|
+
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 });
|
|
38985
|
+
}
|
|
38620
38986
|
function explainSql(sql) {
|
|
38621
38987
|
return /^\s*EXPLAIN\b/i.test(sql) ? sql : `EXPLAIN ${sql}`;
|
|
38622
38988
|
}
|
|
@@ -38740,15 +39106,17 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38740
39106
|
const createRuntime = deps.createRuntime ?? createKsqlRuntime;
|
|
38741
39107
|
const executeSql = deps.executeSql ?? execute;
|
|
38742
39108
|
const executeBatchSql = deps.executeBatchSql ?? executeBatch;
|
|
39109
|
+
const validationContexts = /* @__PURE__ */ new WeakMap();
|
|
38743
39110
|
async function validate(input) {
|
|
38744
39111
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
38745
|
-
|
|
38746
|
-
|
|
38747
|
-
|
|
38748
|
-
|
|
38749
|
-
|
|
38750
|
-
|
|
38751
|
-
}
|
|
39112
|
+
let analysis;
|
|
39113
|
+
try {
|
|
39114
|
+
const statements = parseSqlStatements(normalized.normalizedSql);
|
|
39115
|
+
analysis = analyzeBatch(statements);
|
|
39116
|
+
} catch (err) {
|
|
39117
|
+
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
39118
|
+
}
|
|
39119
|
+
const appBindings = [...normalized.appBindingByMappedApp.entries()].map(([mappedAppId, binding]) => toValidationBinding(mappedAppId, binding));
|
|
38752
39120
|
const statementValidations = analysis.statements.map((s2) => ({
|
|
38753
39121
|
index: s2.index,
|
|
38754
39122
|
statementType: s2.statementType,
|
|
@@ -38778,10 +39146,12 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38778
39146
|
appBindings
|
|
38779
39147
|
};
|
|
38780
39148
|
if (analysis.statementCount > 1) {
|
|
38781
|
-
|
|
39149
|
+
const result2 = { ...common, batch: true };
|
|
39150
|
+
validationContexts.set(result2, normalized.sqlContext);
|
|
39151
|
+
return result2;
|
|
38782
39152
|
}
|
|
38783
39153
|
const s = statementValidations[0];
|
|
38784
|
-
|
|
39154
|
+
const result = {
|
|
38785
39155
|
...common,
|
|
38786
39156
|
batch: false,
|
|
38787
39157
|
statementType: s.statementType,
|
|
@@ -38791,17 +39161,26 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38791
39161
|
insertValuesCount: s.insertValuesCount,
|
|
38792
39162
|
appIds: s.appIds
|
|
38793
39163
|
};
|
|
39164
|
+
validationContexts.set(result, normalized.sqlContext);
|
|
39165
|
+
return result;
|
|
38794
39166
|
}
|
|
38795
39167
|
async function explain(input) {
|
|
38796
39168
|
const normalized = normalizeSqlForTool(serverOptions, input.sql, input.profile);
|
|
38797
|
-
const
|
|
39169
|
+
const appBindings = toExplainBindings(normalized.appBindingByMappedApp);
|
|
39170
|
+
let statements;
|
|
39171
|
+
try {
|
|
39172
|
+
statements = parseSqlStatements(normalized.normalizedSql);
|
|
39173
|
+
} catch (err) {
|
|
39174
|
+
throw restoreSqlContextError(err, normalized.sourceSql, normalized.sqlContext);
|
|
39175
|
+
}
|
|
38798
39176
|
if (statements.length > 1) {
|
|
38799
39177
|
const plans = buildBatchExplainPlans(normalized.normalizedSql);
|
|
38800
39178
|
return {
|
|
38801
39179
|
ok: true,
|
|
38802
39180
|
batch: true,
|
|
38803
39181
|
statementCount: plans.statementCount,
|
|
38804
|
-
statements: plans.statements
|
|
39182
|
+
statements: restoreSqlDiagnosticValue(plans.statements, normalized.appBindingByMappedApp),
|
|
39183
|
+
appBindings
|
|
38805
39184
|
};
|
|
38806
39185
|
}
|
|
38807
39186
|
const result = await executeSql(explainSql(normalized.normalizedSql), noOpClient(), {
|
|
@@ -38810,16 +39189,20 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38810
39189
|
if (result.type !== "SELECT") {
|
|
38811
39190
|
throw new Error(`ArgumentError: EXPLAIN returned unexpected result type ${result.type}.`);
|
|
38812
39191
|
}
|
|
38813
|
-
return
|
|
39192
|
+
return restoreSqlDiagnosticValue(
|
|
39193
|
+
{ ...toSelectPayload(result), appBindings },
|
|
39194
|
+
normalized.appBindingByMappedApp
|
|
39195
|
+
);
|
|
38814
39196
|
}
|
|
38815
|
-
async function query(input) {
|
|
38816
|
-
const validation = await validate(input);
|
|
39197
|
+
async function query(input, validated) {
|
|
39198
|
+
const validation = validated ?? await validate(input);
|
|
38817
39199
|
if (validation.batch) {
|
|
38818
39200
|
if (validation.containsDml) {
|
|
38819
39201
|
throw new Error("ArgumentError: batch contains DML statements. Use ksql_mutate.");
|
|
38820
39202
|
}
|
|
38821
39203
|
const runtime2 = await createRuntime(serverOptions, {
|
|
38822
39204
|
sql: input.sql,
|
|
39205
|
+
sqlContext: validationContexts.get(validation),
|
|
38823
39206
|
profile: input.profile,
|
|
38824
39207
|
maxRecords: input.maxRecords,
|
|
38825
39208
|
fetchParallel: input.fetchParallel,
|
|
@@ -38862,6 +39245,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38862
39245
|
}
|
|
38863
39246
|
const runtime = await createRuntime(serverOptions, {
|
|
38864
39247
|
sql: input.sql,
|
|
39248
|
+
sqlContext: validationContexts.get(validation),
|
|
38865
39249
|
profile: input.profile,
|
|
38866
39250
|
maxRecords: input.maxRecords,
|
|
38867
39251
|
fetchParallel: input.fetchParallel,
|
|
@@ -38907,6 +39291,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38907
39291
|
const selectBasedDml = containsSelectBasedDml(validation.statements);
|
|
38908
39292
|
const runtime = await createRuntime(serverOptions, {
|
|
38909
39293
|
sql: input.sql,
|
|
39294
|
+
sqlContext: validationContexts.get(validation),
|
|
38910
39295
|
profile: input.profile,
|
|
38911
39296
|
// SELECT-based DML を含む場合は dmlMaxRows で読み取りを絞らない(案A。
|
|
38912
39297
|
// resolveMutateRuntimeMaxRecords の doc コメント参照)
|
|
@@ -38951,9 +39336,9 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38951
39336
|
}
|
|
38952
39337
|
return { ...payload };
|
|
38953
39338
|
}
|
|
38954
|
-
async function mutate(input) {
|
|
39339
|
+
async function mutate(input, validated) {
|
|
38955
39340
|
const dmlMaxRows = requireDmlApproval(input, "ksql_mutate");
|
|
38956
|
-
const validation = await validate(input);
|
|
39341
|
+
const validation = validated ?? await validate(input);
|
|
38957
39342
|
if (validation.batch) {
|
|
38958
39343
|
return mutateBatch(input, validation, dmlMaxRows);
|
|
38959
39344
|
}
|
|
@@ -38969,6 +39354,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
38969
39354
|
const selectBasedDml = containsSelectBasedDml(validation.statements);
|
|
38970
39355
|
const runtime = await createRuntime(serverOptions, {
|
|
38971
39356
|
sql: input.sql,
|
|
39357
|
+
sqlContext: validationContexts.get(validation),
|
|
38972
39358
|
profile: input.profile,
|
|
38973
39359
|
// SELECT-based DML は dmlMaxRows で読み取りを絞らない(案A。
|
|
38974
39360
|
// resolveMutateRuntimeMaxRecords の doc コメント参照)
|
|
@@ -39089,7 +39475,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
39089
39475
|
fetchParallel: input.fetchParallel,
|
|
39090
39476
|
onLimit: input.onLimit,
|
|
39091
39477
|
timeout: input.timeout
|
|
39092
|
-
});
|
|
39478
|
+
}, validation);
|
|
39093
39479
|
return {
|
|
39094
39480
|
ok: true,
|
|
39095
39481
|
name: saved.name,
|
|
@@ -39105,7 +39491,7 @@ function createKsqlMcpTools(serverOptions, deps = {}) {
|
|
|
39105
39491
|
dmlMaxRows,
|
|
39106
39492
|
fetchParallel: input.fetchParallel,
|
|
39107
39493
|
timeout: input.timeout
|
|
39108
|
-
});
|
|
39494
|
+
}, validation);
|
|
39109
39495
|
return {
|
|
39110
39496
|
ok: true,
|
|
39111
39497
|
name: saved.name,
|
|
@@ -39275,7 +39661,7 @@ Options:
|
|
|
39275
39661
|
-h, --help Show help
|
|
39276
39662
|
`);
|
|
39277
39663
|
}
|
|
39278
|
-
var SERVER_VERSION = true ? "1.
|
|
39664
|
+
var SERVER_VERSION = true ? "1.13.2" : "0.0.0-dev";
|
|
39279
39665
|
function createServer(args) {
|
|
39280
39666
|
const server = new McpServer({
|
|
39281
39667
|
name: "ksql-mcp",
|