@514labs/moose-lib 0.6.457 → 0.6.458
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browserCompatible.d.mts +1 -1
- package/dist/browserCompatible.d.ts +1 -1
- package/dist/browserCompatible.js +152 -85
- package/dist/browserCompatible.js.map +1 -1
- package/dist/browserCompatible.mjs +149 -85
- package/dist/browserCompatible.mjs.map +1 -1
- package/dist/dmv2/index.d.mts +1 -1
- package/dist/dmv2/index.d.ts +1 -1
- package/dist/dmv2/index.js +152 -85
- package/dist/dmv2/index.js.map +1 -1
- package/dist/dmv2/index.mjs +149 -85
- package/dist/dmv2/index.mjs.map +1 -1
- package/dist/{index-FbIy0gSU.d.mts → index-BkvEUvtm.d.mts} +107 -7
- package/dist/{index-FbIy0gSU.d.ts → index-BkvEUvtm.d.ts} +107 -7
- package/dist/index.d.mts +17 -15
- package/dist/index.d.ts +17 -15
- package/dist/index.js +223 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +216 -42
- package/dist/index.mjs.map +1 -1
- package/dist/moose-runner.js +337 -98
- package/dist/moose-runner.js.map +1 -1
- package/dist/moose-runner.mjs +339 -100
- package/dist/moose-runner.mjs.map +1 -1
- package/package.json +1 -1
package/dist/moose-runner.js
CHANGED
|
@@ -350,6 +350,14 @@ var init_view = __esm({
|
|
|
350
350
|
}
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
+
// src/dmv2/sdk/selectRowPolicy.ts
|
|
354
|
+
var init_selectRowPolicy = __esm({
|
|
355
|
+
"src/dmv2/sdk/selectRowPolicy.ts"() {
|
|
356
|
+
"use strict";
|
|
357
|
+
init_internal();
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
353
361
|
// src/dmv2/sdk/lifeCycle.ts
|
|
354
362
|
var init_lifeCycle = __esm({
|
|
355
363
|
"src/dmv2/sdk/lifeCycle.ts"() {
|
|
@@ -367,6 +375,9 @@ var init_webApp = __esm({
|
|
|
367
375
|
});
|
|
368
376
|
|
|
369
377
|
// src/dmv2/registry.ts
|
|
378
|
+
function getSelectRowPolicies() {
|
|
379
|
+
return getMooseInternal().selectRowPolicies;
|
|
380
|
+
}
|
|
370
381
|
var init_registry = __esm({
|
|
371
382
|
"src/dmv2/registry.ts"() {
|
|
372
383
|
"use strict";
|
|
@@ -389,6 +400,7 @@ var init_dmv2 = __esm({
|
|
|
389
400
|
init_materializedView();
|
|
390
401
|
init_sqlResource();
|
|
391
402
|
init_view();
|
|
403
|
+
init_selectRowPolicy();
|
|
392
404
|
init_lifeCycle();
|
|
393
405
|
init_webApp();
|
|
394
406
|
init_registry();
|
|
@@ -554,6 +566,16 @@ function formatElapsedTime(ms) {
|
|
|
554
566
|
const remainingSeconds = seconds % 60;
|
|
555
567
|
return `${minutes} minutes and ${remainingSeconds.toFixed(2)} seconds`;
|
|
556
568
|
}
|
|
569
|
+
function buildRowPolicyOptionsFromClaims(config, claims) {
|
|
570
|
+
const clickhouse_settings = /* @__PURE__ */ Object.create(null);
|
|
571
|
+
for (const [settingName, claimName] of Object.entries(config)) {
|
|
572
|
+
const value = claims[claimName];
|
|
573
|
+
if (value !== void 0 && value !== null) {
|
|
574
|
+
clickhouse_settings[settingName] = String(value);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return { role: MOOSE_RLS_ROLE, clickhouse_settings };
|
|
578
|
+
}
|
|
557
579
|
async function getTemporalClient(temporalUrl, namespace, clientCert, clientKey, apiKey2) {
|
|
558
580
|
try {
|
|
559
581
|
console.info(
|
|
@@ -590,7 +612,7 @@ async function getTemporalClient(temporalUrl, namespace, clientCert, clientKey,
|
|
|
590
612
|
return void 0;
|
|
591
613
|
}
|
|
592
614
|
}
|
|
593
|
-
var import_client2, import_node_crypto3, import_perf_hooks, fs, MooseClient, QueryClient, WorkflowClient;
|
|
615
|
+
var import_client2, import_node_crypto3, import_perf_hooks, fs, MooseClient, MOOSE_RLS_ROLE, MOOSE_RLS_USER, MOOSE_RLS_SETTING_PREFIX, QueryClient, WorkflowClient;
|
|
594
616
|
var init_helpers = __esm({
|
|
595
617
|
"src/consumption-apis/helpers.ts"() {
|
|
596
618
|
"use strict";
|
|
@@ -608,12 +630,17 @@ var init_helpers = __esm({
|
|
|
608
630
|
this.workflow = new WorkflowClient(temporalClient);
|
|
609
631
|
}
|
|
610
632
|
};
|
|
633
|
+
MOOSE_RLS_ROLE = "moose_rls_role";
|
|
634
|
+
MOOSE_RLS_USER = "moose_rls_user";
|
|
635
|
+
MOOSE_RLS_SETTING_PREFIX = "SQL_moose_rls_";
|
|
611
636
|
QueryClient = class {
|
|
612
637
|
client;
|
|
613
638
|
query_id_prefix;
|
|
614
|
-
|
|
639
|
+
rowPolicyOptions;
|
|
640
|
+
constructor(client, query_id_prefix, rowPolicyOptions) {
|
|
615
641
|
this.client = client;
|
|
616
642
|
this.query_id_prefix = query_id_prefix;
|
|
643
|
+
this.rowPolicyOptions = rowPolicyOptions;
|
|
617
644
|
}
|
|
618
645
|
async execute(sql3) {
|
|
619
646
|
const [query, query_params] = toQuery(sql3);
|
|
@@ -628,7 +655,11 @@ var init_helpers = __esm({
|
|
|
628
655
|
// where response buffering would harm streaming performance and concurrency
|
|
629
656
|
clickhouse_settings: {
|
|
630
657
|
asterisk_include_materialized_columns: 1,
|
|
631
|
-
asterisk_include_alias_columns: 1
|
|
658
|
+
asterisk_include_alias_columns: 1,
|
|
659
|
+
...this.rowPolicyOptions?.clickhouse_settings
|
|
660
|
+
},
|
|
661
|
+
...this.rowPolicyOptions && {
|
|
662
|
+
role: this.rowPolicyOptions.role
|
|
632
663
|
}
|
|
633
664
|
});
|
|
634
665
|
const elapsedMs = import_perf_hooks.performance.now() - start;
|
|
@@ -874,13 +905,17 @@ var init_runtime = __esm({
|
|
|
874
905
|
const envUseSSL = this._parseBool(
|
|
875
906
|
this._env("MOOSE_CLICKHOUSE_CONFIG__USE_SSL")
|
|
876
907
|
);
|
|
908
|
+
const envRlsUser = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_USER");
|
|
909
|
+
const envRlsPassword = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_PASSWORD");
|
|
877
910
|
return {
|
|
878
911
|
host: envHost ?? projectConfig.clickhouse_config.host,
|
|
879
912
|
port: envPort ?? projectConfig.clickhouse_config.host_port.toString(),
|
|
880
913
|
username: envUser ?? projectConfig.clickhouse_config.user,
|
|
881
914
|
password: envPassword ?? projectConfig.clickhouse_config.password,
|
|
882
915
|
database: envDb ?? projectConfig.clickhouse_config.db_name,
|
|
883
|
-
useSSL: envUseSSL !== void 0 ? envUseSSL : projectConfig.clickhouse_config.use_ssl || false
|
|
916
|
+
useSSL: envUseSSL !== void 0 ? envUseSSL : projectConfig.clickhouse_config.use_ssl || false,
|
|
917
|
+
rlsUser: envRlsUser ?? projectConfig.clickhouse_config.rls_user ?? void 0,
|
|
918
|
+
rlsPassword: envRlsPassword ?? projectConfig.clickhouse_config.rls_password ?? void 0
|
|
884
919
|
};
|
|
885
920
|
}
|
|
886
921
|
async getStandaloneClickhouseConfig(overrides) {
|
|
@@ -895,6 +930,8 @@ var init_runtime = __esm({
|
|
|
895
930
|
const envUseSSL = this._parseBool(
|
|
896
931
|
this._env("MOOSE_CLICKHOUSE_CONFIG__USE_SSL")
|
|
897
932
|
);
|
|
933
|
+
const envRlsUser = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_USER");
|
|
934
|
+
const envRlsPassword = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_PASSWORD");
|
|
898
935
|
let projectConfig;
|
|
899
936
|
try {
|
|
900
937
|
projectConfig = await readProjectConfig();
|
|
@@ -915,7 +952,9 @@ var init_runtime = __esm({
|
|
|
915
952
|
username: overrides?.username ?? envUser ?? projectConfig?.clickhouse_config.user ?? defaults.username,
|
|
916
953
|
password: overrides?.password ?? envPassword ?? projectConfig?.clickhouse_config.password ?? defaults.password,
|
|
917
954
|
database: overrides?.database ?? envDb ?? projectConfig?.clickhouse_config.db_name ?? defaults.database,
|
|
918
|
-
useSSL: overrides?.useSSL ?? envUseSSL ?? projectConfig?.clickhouse_config.use_ssl ?? defaults.useSSL
|
|
955
|
+
useSSL: overrides?.useSSL ?? envUseSSL ?? projectConfig?.clickhouse_config.use_ssl ?? defaults.useSSL,
|
|
956
|
+
rlsUser: envRlsUser ?? projectConfig?.clickhouse_config.rls_user ?? void 0,
|
|
957
|
+
rlsPassword: envRlsPassword ?? projectConfig?.clickhouse_config.rls_password ?? void 0
|
|
919
958
|
};
|
|
920
959
|
}
|
|
921
960
|
async getKafkaConfig() {
|
|
@@ -955,54 +994,144 @@ var init_runtime = __esm({
|
|
|
955
994
|
var standalone_exports = {};
|
|
956
995
|
__export(standalone_exports, {
|
|
957
996
|
getMooseClients: () => getMooseClients,
|
|
958
|
-
getMooseUtils: () => getMooseUtils
|
|
997
|
+
getMooseUtils: () => getMooseUtils,
|
|
998
|
+
runWithRequestContext: () => runWithRequestContext
|
|
959
999
|
});
|
|
960
|
-
|
|
961
|
-
|
|
1000
|
+
function runWithRequestContext(context, fn) {
|
|
1001
|
+
return requestContextStorage.run(context, fn);
|
|
1002
|
+
}
|
|
1003
|
+
function isLegacyRequestArg(arg) {
|
|
1004
|
+
if (arg === null || typeof arg !== "object") return false;
|
|
1005
|
+
const obj = arg;
|
|
1006
|
+
return "method" in obj || "url" in obj || "headers" in obj;
|
|
1007
|
+
}
|
|
1008
|
+
function getRowPoliciesConfigFromRegistry() {
|
|
1009
|
+
const policies = getSelectRowPolicies();
|
|
1010
|
+
if (policies.size === 0) return void 0;
|
|
1011
|
+
const config = /* @__PURE__ */ Object.create(null);
|
|
1012
|
+
for (const policy of policies.values()) {
|
|
1013
|
+
config[`${MOOSE_RLS_SETTING_PREFIX}${policy.config.column}`] = policy.config.claim;
|
|
1014
|
+
}
|
|
1015
|
+
return config;
|
|
1016
|
+
}
|
|
1017
|
+
async function getMooseUtils(options) {
|
|
1018
|
+
if (options !== void 0 && isLegacyRequestArg(options)) {
|
|
962
1019
|
console.warn(
|
|
963
|
-
"[DEPRECATED] getMooseUtils(req) no longer requires a request parameter. Use getMooseUtils() instead."
|
|
1020
|
+
"[DEPRECATED] getMooseUtils(req) no longer requires a request parameter. Use getMooseUtils() instead, or getMooseUtils({ rlsContext }) for row policies."
|
|
964
1021
|
);
|
|
1022
|
+
options = void 0;
|
|
965
1023
|
}
|
|
966
1024
|
const runtimeContext = globalThis._mooseRuntimeContext;
|
|
967
1025
|
if (runtimeContext) {
|
|
968
|
-
return
|
|
969
|
-
client: runtimeContext.client,
|
|
970
|
-
sql,
|
|
971
|
-
jwt: runtimeContext.jwt
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
if (standaloneUtils) {
|
|
975
|
-
return standaloneUtils;
|
|
1026
|
+
return resolveRuntimeUtils(runtimeContext, options);
|
|
976
1027
|
}
|
|
977
|
-
|
|
978
|
-
|
|
1028
|
+
await ensureStandaloneInit();
|
|
1029
|
+
if (options?.rlsContext) {
|
|
1030
|
+
return createStandaloneRlsUtils(options.rlsContext);
|
|
979
1031
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1032
|
+
return standaloneUtils;
|
|
1033
|
+
}
|
|
1034
|
+
function resolveRuntimeUtils(runtimeContext, options) {
|
|
1035
|
+
const reqCtx = requestContextStorage.getStore();
|
|
1036
|
+
const jwt = reqCtx?.jwt ?? runtimeContext.jwt;
|
|
1037
|
+
let rowPolicyOpts;
|
|
1038
|
+
if (options?.rlsContext) {
|
|
1039
|
+
if (!runtimeContext.rowPoliciesConfig) {
|
|
984
1040
|
throw new Error(
|
|
985
|
-
"
|
|
1041
|
+
"rlsContext was provided but no row policies are configured. Define at least one SelectRowPolicy before using rlsContext."
|
|
986
1042
|
);
|
|
987
1043
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1044
|
+
rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
1045
|
+
runtimeContext.rowPoliciesConfig,
|
|
1046
|
+
options.rlsContext
|
|
991
1047
|
);
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
1048
|
+
} else {
|
|
1049
|
+
rowPolicyOpts = reqCtx?.rowPolicyOpts;
|
|
1050
|
+
}
|
|
1051
|
+
if (rowPolicyOpts) {
|
|
1052
|
+
const rlsClient = runtimeContext.rlsClickhouseClient ?? runtimeContext.clickhouseClient;
|
|
1053
|
+
const scopedQueryClient = new QueryClient(
|
|
1054
|
+
rlsClient,
|
|
1055
|
+
"rls-scoped",
|
|
1056
|
+
rowPolicyOpts
|
|
1057
|
+
);
|
|
1058
|
+
return {
|
|
1059
|
+
client: new MooseClient(scopedQueryClient, runtimeContext.temporalClient),
|
|
996
1060
|
sql,
|
|
997
|
-
jwt
|
|
1061
|
+
jwt
|
|
998
1062
|
};
|
|
999
|
-
return standaloneUtils;
|
|
1000
|
-
})();
|
|
1001
|
-
try {
|
|
1002
|
-
return await initPromise;
|
|
1003
|
-
} finally {
|
|
1004
|
-
initPromise = null;
|
|
1005
1063
|
}
|
|
1064
|
+
return {
|
|
1065
|
+
client: runtimeContext.client,
|
|
1066
|
+
sql,
|
|
1067
|
+
jwt
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
async function ensureStandaloneInit() {
|
|
1071
|
+
if (standaloneUtils) return;
|
|
1072
|
+
if (!initPromise) {
|
|
1073
|
+
initPromise = (async () => {
|
|
1074
|
+
await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
1075
|
+
const configRegistry = globalThis._mooseConfigRegistry;
|
|
1076
|
+
if (!configRegistry) {
|
|
1077
|
+
throw new Error(
|
|
1078
|
+
"Moose not initialized. Ensure you're running within a Moose app or have proper configuration set up."
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
const clickhouseConfig = await configRegistry.getStandaloneClickhouseConfig();
|
|
1082
|
+
standaloneClickhouseConfig = clickhouseConfig;
|
|
1083
|
+
const clickhouseClient = getClickhouseClient(
|
|
1084
|
+
toClientConfig(clickhouseConfig)
|
|
1085
|
+
);
|
|
1086
|
+
const queryClient = new QueryClient(clickhouseClient, "standalone");
|
|
1087
|
+
const mooseClient = new MooseClient(queryClient);
|
|
1088
|
+
standaloneUtils = {
|
|
1089
|
+
client: mooseClient,
|
|
1090
|
+
sql,
|
|
1091
|
+
jwt: void 0
|
|
1092
|
+
};
|
|
1093
|
+
return standaloneUtils;
|
|
1094
|
+
})();
|
|
1095
|
+
try {
|
|
1096
|
+
await initPromise;
|
|
1097
|
+
} finally {
|
|
1098
|
+
initPromise = null;
|
|
1099
|
+
}
|
|
1100
|
+
} else {
|
|
1101
|
+
await initPromise;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function createStandaloneRlsUtils(rlsContext) {
|
|
1105
|
+
const rowPoliciesConfig = getRowPoliciesConfigFromRegistry();
|
|
1106
|
+
if (!rowPoliciesConfig) {
|
|
1107
|
+
throw new Error(
|
|
1108
|
+
"rlsContext was provided but no SelectRowPolicy primitives are registered. Define at least one SelectRowPolicy before using rlsContext."
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
if (!standaloneRlsClient && standaloneClickhouseConfig) {
|
|
1112
|
+
standaloneRlsClient = getClickhouseClient(
|
|
1113
|
+
toClientConfig({
|
|
1114
|
+
...standaloneClickhouseConfig,
|
|
1115
|
+
username: standaloneClickhouseConfig.rlsUser ?? MOOSE_RLS_USER,
|
|
1116
|
+
password: standaloneClickhouseConfig.rlsPassword ?? standaloneClickhouseConfig.password
|
|
1117
|
+
})
|
|
1118
|
+
);
|
|
1119
|
+
}
|
|
1120
|
+
const rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
1121
|
+
rowPoliciesConfig,
|
|
1122
|
+
rlsContext
|
|
1123
|
+
);
|
|
1124
|
+
const rlsClient = standaloneRlsClient ?? standaloneUtils.client.query.client;
|
|
1125
|
+
const scopedQueryClient = new QueryClient(
|
|
1126
|
+
rlsClient,
|
|
1127
|
+
"rls-scoped",
|
|
1128
|
+
rowPolicyOpts
|
|
1129
|
+
);
|
|
1130
|
+
return {
|
|
1131
|
+
client: new MooseClient(scopedQueryClient),
|
|
1132
|
+
sql,
|
|
1133
|
+
jwt: void 0
|
|
1134
|
+
};
|
|
1006
1135
|
}
|
|
1007
1136
|
async function getMooseClients(config) {
|
|
1008
1137
|
console.warn(
|
|
@@ -1027,15 +1156,20 @@ async function getMooseClients(config) {
|
|
|
1027
1156
|
const utils = await getMooseUtils();
|
|
1028
1157
|
return { client: utils.client };
|
|
1029
1158
|
}
|
|
1030
|
-
var standaloneUtils, initPromise, toClientConfig;
|
|
1159
|
+
var import_node_async_hooks, requestContextStorage, standaloneUtils, initPromise, standaloneRlsClient, standaloneClickhouseConfig, toClientConfig;
|
|
1031
1160
|
var init_standalone = __esm({
|
|
1032
1161
|
"src/consumption-apis/standalone.ts"() {
|
|
1033
1162
|
"use strict";
|
|
1034
1163
|
init_helpers();
|
|
1035
1164
|
init_commons();
|
|
1036
1165
|
init_sqlHelpers();
|
|
1166
|
+
init_registry();
|
|
1167
|
+
import_node_async_hooks = require("async_hooks");
|
|
1168
|
+
requestContextStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
1037
1169
|
standaloneUtils = null;
|
|
1038
1170
|
initPromise = null;
|
|
1171
|
+
standaloneRlsClient = null;
|
|
1172
|
+
standaloneClickhouseConfig = null;
|
|
1039
1173
|
toClientConfig = (config) => ({
|
|
1040
1174
|
...config,
|
|
1041
1175
|
useSSL: config.useSSL ? "true" : "false"
|
|
@@ -2931,7 +3065,8 @@ function createRegistryFrom(existing) {
|
|
|
2931
3065
|
workflows: toTrackingMap(existing?.workflows),
|
|
2932
3066
|
webApps: toTrackingMap(existing?.webApps),
|
|
2933
3067
|
materializedViews: toTrackingMap(existing?.materializedViews),
|
|
2934
|
-
views: toTrackingMap(existing?.views)
|
|
3068
|
+
views: toTrackingMap(existing?.views),
|
|
3069
|
+
selectRowPolicies: toTrackingMap(existing?.selectRowPolicies)
|
|
2935
3070
|
};
|
|
2936
3071
|
}
|
|
2937
3072
|
function getCachedLineage(registry) {
|
|
@@ -3287,7 +3422,11 @@ var init_internal = __esm({
|
|
|
3287
3422
|
void 0,
|
|
3288
3423
|
markRegistryMutated
|
|
3289
3424
|
),
|
|
3290
|
-
views: new MutationTrackingMap(void 0, markRegistryMutated)
|
|
3425
|
+
views: new MutationTrackingMap(void 0, markRegistryMutated),
|
|
3426
|
+
selectRowPolicies: new MutationTrackingMap(
|
|
3427
|
+
void 0,
|
|
3428
|
+
markRegistryMutated
|
|
3429
|
+
)
|
|
3291
3430
|
};
|
|
3292
3431
|
defaultRetentionPeriod = 60 * 60 * 24 * 7;
|
|
3293
3432
|
toInfraMap = (registry) => {
|
|
@@ -3300,6 +3439,7 @@ var init_internal = __esm({
|
|
|
3300
3439
|
const webApps = {};
|
|
3301
3440
|
const materializedViews = {};
|
|
3302
3441
|
const views = {};
|
|
3442
|
+
const selectRowPolicies = {};
|
|
3303
3443
|
const lineage = getCachedLineage(registry);
|
|
3304
3444
|
registry.tables.forEach((table) => {
|
|
3305
3445
|
const id = table.config.version ? `${table.name}_${table.config.version}` : table.name;
|
|
@@ -3547,6 +3687,14 @@ var init_internal = __esm({
|
|
|
3547
3687
|
metadata: view.metadata
|
|
3548
3688
|
};
|
|
3549
3689
|
});
|
|
3690
|
+
registry.selectRowPolicies.forEach((policy) => {
|
|
3691
|
+
selectRowPolicies[policy.name] = {
|
|
3692
|
+
name: policy.name,
|
|
3693
|
+
tables: policy.tableRefs,
|
|
3694
|
+
column: policy.config.column,
|
|
3695
|
+
claim: policy.config.claim
|
|
3696
|
+
};
|
|
3697
|
+
});
|
|
3550
3698
|
return {
|
|
3551
3699
|
topics,
|
|
3552
3700
|
tables,
|
|
@@ -3557,6 +3705,7 @@ var init_internal = __esm({
|
|
|
3557
3705
|
webApps,
|
|
3558
3706
|
materializedViews,
|
|
3559
3707
|
views,
|
|
3708
|
+
selectRowPolicies,
|
|
3560
3709
|
unloadedFiles: []
|
|
3561
3710
|
// Will be populated by dumpMooseInternal
|
|
3562
3711
|
};
|
|
@@ -3600,6 +3749,7 @@ var init_internal = __esm({
|
|
|
3600
3749
|
registry.webApps.clear();
|
|
3601
3750
|
registry.materializedViews.clear();
|
|
3602
3751
|
registry.views.clear();
|
|
3752
|
+
registry.selectRowPolicies.clear();
|
|
3603
3753
|
const outDir = getOutDir();
|
|
3604
3754
|
const compiledDir = path5.isAbsolute(outDir) ? outDir : path5.join(import_process.default.cwd(), outDir);
|
|
3605
3755
|
Object.keys(require.cache).forEach((key) => {
|
|
@@ -4081,7 +4231,61 @@ var apiContextStorage = setupStructuredConsole(
|
|
|
4081
4231
|
(ctx) => ctx.apiName,
|
|
4082
4232
|
"api_name"
|
|
4083
4233
|
);
|
|
4084
|
-
|
|
4234
|
+
async function authenticateRequest(req, res, publicKey, jwtConfig, enforceAuth, rowPoliciesConfig) {
|
|
4235
|
+
const requireAuth = enforceAuth || !!rowPoliciesConfig;
|
|
4236
|
+
let jwtPayload;
|
|
4237
|
+
if (publicKey && jwtConfig) {
|
|
4238
|
+
const jwt = req.headers.authorization?.split(" ")[1];
|
|
4239
|
+
if (jwt) {
|
|
4240
|
+
try {
|
|
4241
|
+
const { payload } = await jose.jwtVerify(jwt, publicKey, {
|
|
4242
|
+
issuer: jwtConfig.issuer,
|
|
4243
|
+
audience: jwtConfig.audience
|
|
4244
|
+
});
|
|
4245
|
+
jwtPayload = payload;
|
|
4246
|
+
} catch (_error) {
|
|
4247
|
+
console.log("JWT verification failed");
|
|
4248
|
+
if (requireAuth) {
|
|
4249
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4250
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4251
|
+
return null;
|
|
4252
|
+
}
|
|
4253
|
+
}
|
|
4254
|
+
} else if (requireAuth) {
|
|
4255
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4256
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4257
|
+
return null;
|
|
4258
|
+
}
|
|
4259
|
+
} else if (requireAuth) {
|
|
4260
|
+
if (rowPoliciesConfig) {
|
|
4261
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
4262
|
+
res.end(
|
|
4263
|
+
JSON.stringify({
|
|
4264
|
+
error: "Forbidden",
|
|
4265
|
+
message: "Row policies require JWT authentication. Configure jwt.secret in moose.config.toml."
|
|
4266
|
+
})
|
|
4267
|
+
);
|
|
4268
|
+
} else {
|
|
4269
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4270
|
+
res.end(
|
|
4271
|
+
JSON.stringify({
|
|
4272
|
+
error: "Unauthorized",
|
|
4273
|
+
message: "Authentication is enforced but no JWT configuration is available."
|
|
4274
|
+
})
|
|
4275
|
+
);
|
|
4276
|
+
}
|
|
4277
|
+
return null;
|
|
4278
|
+
}
|
|
4279
|
+
let rowPolicyOpts;
|
|
4280
|
+
if (rowPoliciesConfig && jwtPayload) {
|
|
4281
|
+
rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
4282
|
+
rowPoliciesConfig,
|
|
4283
|
+
jwtPayload
|
|
4284
|
+
);
|
|
4285
|
+
}
|
|
4286
|
+
return { jwtPayload, rowPolicyOpts };
|
|
4287
|
+
}
|
|
4288
|
+
var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig, rowPoliciesConfig, rlsClickhouseClient) => {
|
|
4085
4289
|
const sourceDir = getSourceDir();
|
|
4086
4290
|
const outDir = getOutDir();
|
|
4087
4291
|
const outRoot = path6.isAbsolute(outDir) ? outDir : path6.join(process.cwd(), outDir);
|
|
@@ -4093,37 +4297,19 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4093
4297
|
try {
|
|
4094
4298
|
const url = new URL(req.url || "", "http://localhost");
|
|
4095
4299
|
const fileName = url.pathname;
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
jwtPayload = payload;
|
|
4106
|
-
} catch (error) {
|
|
4107
|
-
console.log("JWT verification failed");
|
|
4108
|
-
if (enforceAuth) {
|
|
4109
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4110
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4111
|
-
httpLogger(req, res, start);
|
|
4112
|
-
return;
|
|
4113
|
-
}
|
|
4114
|
-
}
|
|
4115
|
-
} else if (enforceAuth) {
|
|
4116
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4117
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4118
|
-
httpLogger(req, res, start);
|
|
4119
|
-
return;
|
|
4120
|
-
}
|
|
4121
|
-
} else if (enforceAuth) {
|
|
4122
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4123
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4300
|
+
const authResult = await authenticateRequest(
|
|
4301
|
+
req,
|
|
4302
|
+
res,
|
|
4303
|
+
publicKey,
|
|
4304
|
+
jwtConfig,
|
|
4305
|
+
enforceAuth,
|
|
4306
|
+
rowPoliciesConfig
|
|
4307
|
+
);
|
|
4308
|
+
if (!authResult) {
|
|
4124
4309
|
httpLogger(req, res, start);
|
|
4125
4310
|
return;
|
|
4126
4311
|
}
|
|
4312
|
+
const { jwtPayload, rowPolicyOpts } = authResult;
|
|
4127
4313
|
const pathName = createPath(actualApisDir, fileName);
|
|
4128
4314
|
const paramsObject = Array.from(url.searchParams.entries()).reduce(
|
|
4129
4315
|
(obj, [key, value]) => {
|
|
@@ -4193,7 +4379,12 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4193
4379
|
console.log(`[API] | Executing API: ${matchedApiName}`);
|
|
4194
4380
|
});
|
|
4195
4381
|
}
|
|
4196
|
-
const
|
|
4382
|
+
const queryClickhouseClient = rowPolicyOpts && rlsClickhouseClient ? rlsClickhouseClient : clickhouseClient;
|
|
4383
|
+
const queryClient = new QueryClient(
|
|
4384
|
+
queryClickhouseClient,
|
|
4385
|
+
fileName,
|
|
4386
|
+
rowPolicyOpts
|
|
4387
|
+
);
|
|
4197
4388
|
const apiName = matchedApiName;
|
|
4198
4389
|
const result = await apiContextStorage.run({ apiName }, async () => {
|
|
4199
4390
|
return await userFuncModule(paramsObject, {
|
|
@@ -4249,13 +4440,15 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4249
4440
|
}
|
|
4250
4441
|
};
|
|
4251
4442
|
};
|
|
4252
|
-
var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig) => {
|
|
4443
|
+
var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig, rowPoliciesConfig, rlsClickhouseClient) => {
|
|
4253
4444
|
const apiRequestHandler = await apiHandler(
|
|
4254
4445
|
publicKey,
|
|
4255
4446
|
clickhouseClient,
|
|
4256
4447
|
temporalClient,
|
|
4257
4448
|
enforceAuth,
|
|
4258
|
-
jwtConfig
|
|
4449
|
+
jwtConfig,
|
|
4450
|
+
rowPoliciesConfig,
|
|
4451
|
+
rlsClickhouseClient
|
|
4259
4452
|
);
|
|
4260
4453
|
const webApps = await getWebApps2();
|
|
4261
4454
|
const sortedWebApps = Array.from(webApps.values()).sort((a, b) => {
|
|
@@ -4277,30 +4470,22 @@ var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enfor
|
|
|
4277
4470
|
);
|
|
4278
4471
|
return;
|
|
4279
4472
|
}
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
} catch (error) {
|
|
4291
|
-
console.log("JWT verification failed for WebApp route");
|
|
4292
|
-
}
|
|
4293
|
-
}
|
|
4294
|
-
}
|
|
4473
|
+
const authResult = await authenticateRequest(
|
|
4474
|
+
req,
|
|
4475
|
+
res,
|
|
4476
|
+
publicKey,
|
|
4477
|
+
jwtConfig,
|
|
4478
|
+
enforceAuth,
|
|
4479
|
+
rowPoliciesConfig
|
|
4480
|
+
);
|
|
4481
|
+
if (!authResult) return;
|
|
4482
|
+
const { jwtPayload, rowPolicyOpts } = authResult;
|
|
4295
4483
|
for (const webApp of sortedWebApps) {
|
|
4296
4484
|
const mountPath = webApp.config.mountPath || "/";
|
|
4297
4485
|
const normalizedMount = mountPath.endsWith("/") && mountPath !== "/" ? mountPath.slice(0, -1) : mountPath;
|
|
4298
4486
|
const matches = pathname === normalizedMount || pathname.startsWith(normalizedMount + "/");
|
|
4299
4487
|
if (matches) {
|
|
4300
|
-
|
|
4301
|
-
const { getMooseUtils: getMooseUtils2 } = await Promise.resolve().then(() => (init_standalone(), standalone_exports));
|
|
4302
|
-
req.moose = await getMooseUtils2();
|
|
4303
|
-
}
|
|
4488
|
+
const { getMooseUtils: getMooseUtils2, runWithRequestContext: runWithRequestContext2 } = await Promise.resolve().then(() => (init_standalone(), standalone_exports));
|
|
4304
4489
|
let proxiedUrl = req.url;
|
|
4305
4490
|
if (normalizedMount !== "/") {
|
|
4306
4491
|
const pathWithoutMount = pathname.substring(normalizedMount.length) || "/";
|
|
@@ -4314,7 +4499,15 @@ var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enfor
|
|
|
4314
4499
|
url: proxiedUrl
|
|
4315
4500
|
}
|
|
4316
4501
|
);
|
|
4317
|
-
await
|
|
4502
|
+
await runWithRequestContext2(
|
|
4503
|
+
{ rowPolicyOpts, jwt: jwtPayload },
|
|
4504
|
+
async () => {
|
|
4505
|
+
if (webApp.config.injectMooseUtils !== false) {
|
|
4506
|
+
modifiedReq.moose = await getMooseUtils2();
|
|
4507
|
+
}
|
|
4508
|
+
await webApp.handler(modifiedReq, res);
|
|
4509
|
+
}
|
|
4510
|
+
);
|
|
4318
4511
|
return;
|
|
4319
4512
|
} catch (error) {
|
|
4320
4513
|
console.error(`Error in WebApp ${webApp.name}:`, error);
|
|
@@ -4365,14 +4558,33 @@ var runApis = async (config) => {
|
|
|
4365
4558
|
const clickhouseClient = getClickhouseClient(
|
|
4366
4559
|
toClientConfig2(config.clickhouseConfig)
|
|
4367
4560
|
);
|
|
4561
|
+
let rlsClickhouseClient;
|
|
4562
|
+
if (config.rowPoliciesConfig) {
|
|
4563
|
+
rlsClickhouseClient = getClickhouseClient(
|
|
4564
|
+
toClientConfig2({
|
|
4565
|
+
...config.clickhouseConfig,
|
|
4566
|
+
username: config.clickhouseConfig.rlsUser ?? MOOSE_RLS_USER,
|
|
4567
|
+
password: config.clickhouseConfig.rlsPassword ?? config.clickhouseConfig.password
|
|
4568
|
+
})
|
|
4569
|
+
);
|
|
4570
|
+
}
|
|
4368
4571
|
let publicKey;
|
|
4369
4572
|
if (config.jwtConfig?.secret) {
|
|
4370
4573
|
console.log("Importing JWT public key...");
|
|
4371
4574
|
publicKey = await jose.importSPKI(config.jwtConfig.secret, "RS256");
|
|
4372
4575
|
}
|
|
4576
|
+
if (config.rowPoliciesConfig && !publicKey) {
|
|
4577
|
+
console.error(
|
|
4578
|
+
"WARNING: Row policies are configured but no JWT public key is set. All consumption API requests will be rejected with 403. Configure jwt.secret in moose.config.toml to enable authentication."
|
|
4579
|
+
);
|
|
4580
|
+
}
|
|
4373
4581
|
const runtimeQueryClient = new QueryClient(clickhouseClient, "runtime");
|
|
4374
4582
|
globalThis._mooseRuntimeContext = {
|
|
4375
|
-
client: new MooseClient(runtimeQueryClient, temporalClient)
|
|
4583
|
+
client: new MooseClient(runtimeQueryClient, temporalClient),
|
|
4584
|
+
clickhouseClient,
|
|
4585
|
+
rlsClickhouseClient,
|
|
4586
|
+
temporalClient,
|
|
4587
|
+
rowPoliciesConfig: config.rowPoliciesConfig
|
|
4376
4588
|
};
|
|
4377
4589
|
const server = import_http.default.createServer(
|
|
4378
4590
|
await createMainRouter(
|
|
@@ -4380,7 +4592,9 @@ var runApis = async (config) => {
|
|
|
4380
4592
|
clickhouseClient,
|
|
4381
4593
|
temporalClient,
|
|
4382
4594
|
config.enforceAuth,
|
|
4383
|
-
config.jwtConfig
|
|
4595
|
+
config.jwtConfig,
|
|
4596
|
+
config.rowPoliciesConfig,
|
|
4597
|
+
rlsClickhouseClient
|
|
4384
4598
|
)
|
|
4385
4599
|
);
|
|
4386
4600
|
const port = config.proxyPort !== void 0 ? config.proxyPort : 4001;
|
|
@@ -5391,7 +5605,10 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5391
5605
|
"--worker-count <count>",
|
|
5392
5606
|
"Number of worker processes for the consumption API cluster",
|
|
5393
5607
|
parseInt
|
|
5394
|
-
).
|
|
5608
|
+
).option(
|
|
5609
|
+
"--row-policies <json>",
|
|
5610
|
+
"JSON map of ClickHouse setting names to JWT claim names for row policy enforcement"
|
|
5611
|
+
).option("--rls-user <user>", "ClickHouse username for RLS queries").option("--rls-password <password>", "ClickHouse password for RLS queries").action(
|
|
5395
5612
|
(clickhouseDb, clickhouseHost, clickhousePort, clickhouseUsername, clickhousePassword, options) => {
|
|
5396
5613
|
runApis({
|
|
5397
5614
|
clickhouseConfig: {
|
|
@@ -5400,7 +5617,9 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5400
5617
|
port: clickhousePort,
|
|
5401
5618
|
username: clickhouseUsername,
|
|
5402
5619
|
password: clickhousePassword,
|
|
5403
|
-
useSSL: options.clickhouseUseSsl
|
|
5620
|
+
useSSL: options.clickhouseUseSsl,
|
|
5621
|
+
rlsUser: options.rlsUser,
|
|
5622
|
+
rlsPassword: options.rlsPassword
|
|
5404
5623
|
},
|
|
5405
5624
|
jwtConfig: {
|
|
5406
5625
|
secret: options.jwtSecret,
|
|
@@ -5416,7 +5635,27 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5416
5635
|
} : void 0,
|
|
5417
5636
|
enforceAuth: options.enforceAuth,
|
|
5418
5637
|
proxyPort: options.proxyPort,
|
|
5419
|
-
workerCount: options.workerCount
|
|
5638
|
+
workerCount: options.workerCount,
|
|
5639
|
+
rowPoliciesConfig: options.rowPolicies ? (() => {
|
|
5640
|
+
let parsed;
|
|
5641
|
+
try {
|
|
5642
|
+
parsed = JSON.parse(options.rowPolicies);
|
|
5643
|
+
} catch (e) {
|
|
5644
|
+
console.error(
|
|
5645
|
+
`Failed to parse --row-policies JSON: ${e.message}`
|
|
5646
|
+
);
|
|
5647
|
+
process.exit(1);
|
|
5648
|
+
}
|
|
5649
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || !Object.values(parsed).every(
|
|
5650
|
+
(v) => typeof v === "string"
|
|
5651
|
+
)) {
|
|
5652
|
+
console.error(
|
|
5653
|
+
`Invalid --row-policies JSON: expected a flat object with string values`
|
|
5654
|
+
);
|
|
5655
|
+
process.exit(1);
|
|
5656
|
+
}
|
|
5657
|
+
return parsed;
|
|
5658
|
+
})() : void 0
|
|
5420
5659
|
});
|
|
5421
5660
|
}
|
|
5422
5661
|
);
|