@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.mjs
CHANGED
|
@@ -333,6 +333,14 @@ var init_view = __esm({
|
|
|
333
333
|
}
|
|
334
334
|
});
|
|
335
335
|
|
|
336
|
+
// src/dmv2/sdk/selectRowPolicy.ts
|
|
337
|
+
var init_selectRowPolicy = __esm({
|
|
338
|
+
"src/dmv2/sdk/selectRowPolicy.ts"() {
|
|
339
|
+
"use strict";
|
|
340
|
+
init_internal();
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
336
344
|
// src/dmv2/sdk/lifeCycle.ts
|
|
337
345
|
var init_lifeCycle = __esm({
|
|
338
346
|
"src/dmv2/sdk/lifeCycle.ts"() {
|
|
@@ -350,6 +358,9 @@ var init_webApp = __esm({
|
|
|
350
358
|
});
|
|
351
359
|
|
|
352
360
|
// src/dmv2/registry.ts
|
|
361
|
+
function getSelectRowPolicies() {
|
|
362
|
+
return getMooseInternal().selectRowPolicies;
|
|
363
|
+
}
|
|
353
364
|
var init_registry = __esm({
|
|
354
365
|
"src/dmv2/registry.ts"() {
|
|
355
366
|
"use strict";
|
|
@@ -372,6 +383,7 @@ var init_dmv2 = __esm({
|
|
|
372
383
|
init_materializedView();
|
|
373
384
|
init_sqlResource();
|
|
374
385
|
init_view();
|
|
386
|
+
init_selectRowPolicy();
|
|
375
387
|
init_lifeCycle();
|
|
376
388
|
init_webApp();
|
|
377
389
|
init_registry();
|
|
@@ -544,6 +556,16 @@ function formatElapsedTime(ms) {
|
|
|
544
556
|
const remainingSeconds = seconds % 60;
|
|
545
557
|
return `${minutes} minutes and ${remainingSeconds.toFixed(2)} seconds`;
|
|
546
558
|
}
|
|
559
|
+
function buildRowPolicyOptionsFromClaims(config, claims) {
|
|
560
|
+
const clickhouse_settings = /* @__PURE__ */ Object.create(null);
|
|
561
|
+
for (const [settingName, claimName] of Object.entries(config)) {
|
|
562
|
+
const value = claims[claimName];
|
|
563
|
+
if (value !== void 0 && value !== null) {
|
|
564
|
+
clickhouse_settings[settingName] = String(value);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return { role: MOOSE_RLS_ROLE, clickhouse_settings };
|
|
568
|
+
}
|
|
547
569
|
async function getTemporalClient(temporalUrl, namespace, clientCert, clientKey, apiKey2) {
|
|
548
570
|
try {
|
|
549
571
|
console.info(
|
|
@@ -580,7 +602,7 @@ async function getTemporalClient(temporalUrl, namespace, clientCert, clientKey,
|
|
|
580
602
|
return void 0;
|
|
581
603
|
}
|
|
582
604
|
}
|
|
583
|
-
var MooseClient, QueryClient, WorkflowClient;
|
|
605
|
+
var MooseClient, MOOSE_RLS_ROLE, MOOSE_RLS_USER, MOOSE_RLS_SETTING_PREFIX, QueryClient, WorkflowClient;
|
|
584
606
|
var init_helpers = __esm({
|
|
585
607
|
"src/consumption-apis/helpers.ts"() {
|
|
586
608
|
"use strict";
|
|
@@ -594,12 +616,17 @@ var init_helpers = __esm({
|
|
|
594
616
|
this.workflow = new WorkflowClient(temporalClient);
|
|
595
617
|
}
|
|
596
618
|
};
|
|
619
|
+
MOOSE_RLS_ROLE = "moose_rls_role";
|
|
620
|
+
MOOSE_RLS_USER = "moose_rls_user";
|
|
621
|
+
MOOSE_RLS_SETTING_PREFIX = "SQL_moose_rls_";
|
|
597
622
|
QueryClient = class {
|
|
598
623
|
client;
|
|
599
624
|
query_id_prefix;
|
|
600
|
-
|
|
625
|
+
rowPolicyOptions;
|
|
626
|
+
constructor(client, query_id_prefix, rowPolicyOptions) {
|
|
601
627
|
this.client = client;
|
|
602
628
|
this.query_id_prefix = query_id_prefix;
|
|
629
|
+
this.rowPolicyOptions = rowPolicyOptions;
|
|
603
630
|
}
|
|
604
631
|
async execute(sql3) {
|
|
605
632
|
const [query, query_params] = toQuery(sql3);
|
|
@@ -614,7 +641,11 @@ var init_helpers = __esm({
|
|
|
614
641
|
// where response buffering would harm streaming performance and concurrency
|
|
615
642
|
clickhouse_settings: {
|
|
616
643
|
asterisk_include_materialized_columns: 1,
|
|
617
|
-
asterisk_include_alias_columns: 1
|
|
644
|
+
asterisk_include_alias_columns: 1,
|
|
645
|
+
...this.rowPolicyOptions?.clickhouse_settings
|
|
646
|
+
},
|
|
647
|
+
...this.rowPolicyOptions && {
|
|
648
|
+
role: this.rowPolicyOptions.role
|
|
618
649
|
}
|
|
619
650
|
});
|
|
620
651
|
const elapsedMs = performance.now() - start;
|
|
@@ -859,13 +890,17 @@ var init_runtime = __esm({
|
|
|
859
890
|
const envUseSSL = this._parseBool(
|
|
860
891
|
this._env("MOOSE_CLICKHOUSE_CONFIG__USE_SSL")
|
|
861
892
|
);
|
|
893
|
+
const envRlsUser = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_USER");
|
|
894
|
+
const envRlsPassword = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_PASSWORD");
|
|
862
895
|
return {
|
|
863
896
|
host: envHost ?? projectConfig.clickhouse_config.host,
|
|
864
897
|
port: envPort ?? projectConfig.clickhouse_config.host_port.toString(),
|
|
865
898
|
username: envUser ?? projectConfig.clickhouse_config.user,
|
|
866
899
|
password: envPassword ?? projectConfig.clickhouse_config.password,
|
|
867
900
|
database: envDb ?? projectConfig.clickhouse_config.db_name,
|
|
868
|
-
useSSL: envUseSSL !== void 0 ? envUseSSL : projectConfig.clickhouse_config.use_ssl || false
|
|
901
|
+
useSSL: envUseSSL !== void 0 ? envUseSSL : projectConfig.clickhouse_config.use_ssl || false,
|
|
902
|
+
rlsUser: envRlsUser ?? projectConfig.clickhouse_config.rls_user ?? void 0,
|
|
903
|
+
rlsPassword: envRlsPassword ?? projectConfig.clickhouse_config.rls_password ?? void 0
|
|
869
904
|
};
|
|
870
905
|
}
|
|
871
906
|
async getStandaloneClickhouseConfig(overrides) {
|
|
@@ -880,6 +915,8 @@ var init_runtime = __esm({
|
|
|
880
915
|
const envUseSSL = this._parseBool(
|
|
881
916
|
this._env("MOOSE_CLICKHOUSE_CONFIG__USE_SSL")
|
|
882
917
|
);
|
|
918
|
+
const envRlsUser = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_USER");
|
|
919
|
+
const envRlsPassword = this._env("MOOSE_CLICKHOUSE_CONFIG__RLS_PASSWORD");
|
|
883
920
|
let projectConfig;
|
|
884
921
|
try {
|
|
885
922
|
projectConfig = await readProjectConfig();
|
|
@@ -900,7 +937,9 @@ var init_runtime = __esm({
|
|
|
900
937
|
username: overrides?.username ?? envUser ?? projectConfig?.clickhouse_config.user ?? defaults.username,
|
|
901
938
|
password: overrides?.password ?? envPassword ?? projectConfig?.clickhouse_config.password ?? defaults.password,
|
|
902
939
|
database: overrides?.database ?? envDb ?? projectConfig?.clickhouse_config.db_name ?? defaults.database,
|
|
903
|
-
useSSL: overrides?.useSSL ?? envUseSSL ?? projectConfig?.clickhouse_config.use_ssl ?? defaults.useSSL
|
|
940
|
+
useSSL: overrides?.useSSL ?? envUseSSL ?? projectConfig?.clickhouse_config.use_ssl ?? defaults.useSSL,
|
|
941
|
+
rlsUser: envRlsUser ?? projectConfig?.clickhouse_config.rls_user ?? void 0,
|
|
942
|
+
rlsPassword: envRlsPassword ?? projectConfig?.clickhouse_config.rls_password ?? void 0
|
|
904
943
|
};
|
|
905
944
|
}
|
|
906
945
|
async getKafkaConfig() {
|
|
@@ -940,54 +979,145 @@ var init_runtime = __esm({
|
|
|
940
979
|
var standalone_exports = {};
|
|
941
980
|
__export(standalone_exports, {
|
|
942
981
|
getMooseClients: () => getMooseClients,
|
|
943
|
-
getMooseUtils: () => getMooseUtils
|
|
982
|
+
getMooseUtils: () => getMooseUtils,
|
|
983
|
+
runWithRequestContext: () => runWithRequestContext
|
|
944
984
|
});
|
|
945
|
-
|
|
946
|
-
|
|
985
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
986
|
+
function runWithRequestContext(context, fn) {
|
|
987
|
+
return requestContextStorage.run(context, fn);
|
|
988
|
+
}
|
|
989
|
+
function isLegacyRequestArg(arg) {
|
|
990
|
+
if (arg === null || typeof arg !== "object") return false;
|
|
991
|
+
const obj = arg;
|
|
992
|
+
return "method" in obj || "url" in obj || "headers" in obj;
|
|
993
|
+
}
|
|
994
|
+
function getRowPoliciesConfigFromRegistry() {
|
|
995
|
+
const policies = getSelectRowPolicies();
|
|
996
|
+
if (policies.size === 0) return void 0;
|
|
997
|
+
const config = /* @__PURE__ */ Object.create(null);
|
|
998
|
+
for (const policy of policies.values()) {
|
|
999
|
+
config[`${MOOSE_RLS_SETTING_PREFIX}${policy.config.column}`] = policy.config.claim;
|
|
1000
|
+
}
|
|
1001
|
+
return config;
|
|
1002
|
+
}
|
|
1003
|
+
async function getMooseUtils(options) {
|
|
1004
|
+
if (options !== void 0 && isLegacyRequestArg(options)) {
|
|
947
1005
|
console.warn(
|
|
948
|
-
"[DEPRECATED] getMooseUtils(req) no longer requires a request parameter. Use getMooseUtils() instead."
|
|
1006
|
+
"[DEPRECATED] getMooseUtils(req) no longer requires a request parameter. Use getMooseUtils() instead, or getMooseUtils({ rlsContext }) for row policies."
|
|
949
1007
|
);
|
|
1008
|
+
options = void 0;
|
|
950
1009
|
}
|
|
951
1010
|
const runtimeContext = globalThis._mooseRuntimeContext;
|
|
952
1011
|
if (runtimeContext) {
|
|
953
|
-
return
|
|
954
|
-
client: runtimeContext.client,
|
|
955
|
-
sql,
|
|
956
|
-
jwt: runtimeContext.jwt
|
|
957
|
-
};
|
|
1012
|
+
return resolveRuntimeUtils(runtimeContext, options);
|
|
958
1013
|
}
|
|
959
|
-
|
|
960
|
-
|
|
1014
|
+
await ensureStandaloneInit();
|
|
1015
|
+
if (options?.rlsContext) {
|
|
1016
|
+
return createStandaloneRlsUtils(options.rlsContext);
|
|
961
1017
|
}
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
1018
|
+
return standaloneUtils;
|
|
1019
|
+
}
|
|
1020
|
+
function resolveRuntimeUtils(runtimeContext, options) {
|
|
1021
|
+
const reqCtx = requestContextStorage.getStore();
|
|
1022
|
+
const jwt = reqCtx?.jwt ?? runtimeContext.jwt;
|
|
1023
|
+
let rowPolicyOpts;
|
|
1024
|
+
if (options?.rlsContext) {
|
|
1025
|
+
if (!runtimeContext.rowPoliciesConfig) {
|
|
969
1026
|
throw new Error(
|
|
970
|
-
"
|
|
1027
|
+
"rlsContext was provided but no row policies are configured. Define at least one SelectRowPolicy before using rlsContext."
|
|
971
1028
|
);
|
|
972
1029
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1030
|
+
rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
1031
|
+
runtimeContext.rowPoliciesConfig,
|
|
1032
|
+
options.rlsContext
|
|
976
1033
|
);
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1034
|
+
} else {
|
|
1035
|
+
rowPolicyOpts = reqCtx?.rowPolicyOpts;
|
|
1036
|
+
}
|
|
1037
|
+
if (rowPolicyOpts) {
|
|
1038
|
+
const rlsClient = runtimeContext.rlsClickhouseClient ?? runtimeContext.clickhouseClient;
|
|
1039
|
+
const scopedQueryClient = new QueryClient(
|
|
1040
|
+
rlsClient,
|
|
1041
|
+
"rls-scoped",
|
|
1042
|
+
rowPolicyOpts
|
|
1043
|
+
);
|
|
1044
|
+
return {
|
|
1045
|
+
client: new MooseClient(scopedQueryClient, runtimeContext.temporalClient),
|
|
981
1046
|
sql,
|
|
982
|
-
jwt
|
|
1047
|
+
jwt
|
|
983
1048
|
};
|
|
984
|
-
return standaloneUtils;
|
|
985
|
-
})();
|
|
986
|
-
try {
|
|
987
|
-
return await initPromise;
|
|
988
|
-
} finally {
|
|
989
|
-
initPromise = null;
|
|
990
1049
|
}
|
|
1050
|
+
return {
|
|
1051
|
+
client: runtimeContext.client,
|
|
1052
|
+
sql,
|
|
1053
|
+
jwt
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
async function ensureStandaloneInit() {
|
|
1057
|
+
if (standaloneUtils) return;
|
|
1058
|
+
if (!initPromise) {
|
|
1059
|
+
initPromise = (async () => {
|
|
1060
|
+
await Promise.resolve().then(() => (init_runtime(), runtime_exports));
|
|
1061
|
+
const configRegistry = globalThis._mooseConfigRegistry;
|
|
1062
|
+
if (!configRegistry) {
|
|
1063
|
+
throw new Error(
|
|
1064
|
+
"Moose not initialized. Ensure you're running within a Moose app or have proper configuration set up."
|
|
1065
|
+
);
|
|
1066
|
+
}
|
|
1067
|
+
const clickhouseConfig = await configRegistry.getStandaloneClickhouseConfig();
|
|
1068
|
+
standaloneClickhouseConfig = clickhouseConfig;
|
|
1069
|
+
const clickhouseClient = getClickhouseClient(
|
|
1070
|
+
toClientConfig(clickhouseConfig)
|
|
1071
|
+
);
|
|
1072
|
+
const queryClient = new QueryClient(clickhouseClient, "standalone");
|
|
1073
|
+
const mooseClient = new MooseClient(queryClient);
|
|
1074
|
+
standaloneUtils = {
|
|
1075
|
+
client: mooseClient,
|
|
1076
|
+
sql,
|
|
1077
|
+
jwt: void 0
|
|
1078
|
+
};
|
|
1079
|
+
return standaloneUtils;
|
|
1080
|
+
})();
|
|
1081
|
+
try {
|
|
1082
|
+
await initPromise;
|
|
1083
|
+
} finally {
|
|
1084
|
+
initPromise = null;
|
|
1085
|
+
}
|
|
1086
|
+
} else {
|
|
1087
|
+
await initPromise;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
function createStandaloneRlsUtils(rlsContext) {
|
|
1091
|
+
const rowPoliciesConfig = getRowPoliciesConfigFromRegistry();
|
|
1092
|
+
if (!rowPoliciesConfig) {
|
|
1093
|
+
throw new Error(
|
|
1094
|
+
"rlsContext was provided but no SelectRowPolicy primitives are registered. Define at least one SelectRowPolicy before using rlsContext."
|
|
1095
|
+
);
|
|
1096
|
+
}
|
|
1097
|
+
if (!standaloneRlsClient && standaloneClickhouseConfig) {
|
|
1098
|
+
standaloneRlsClient = getClickhouseClient(
|
|
1099
|
+
toClientConfig({
|
|
1100
|
+
...standaloneClickhouseConfig,
|
|
1101
|
+
username: standaloneClickhouseConfig.rlsUser ?? MOOSE_RLS_USER,
|
|
1102
|
+
password: standaloneClickhouseConfig.rlsPassword ?? standaloneClickhouseConfig.password
|
|
1103
|
+
})
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
const rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
1107
|
+
rowPoliciesConfig,
|
|
1108
|
+
rlsContext
|
|
1109
|
+
);
|
|
1110
|
+
const rlsClient = standaloneRlsClient ?? standaloneUtils.client.query.client;
|
|
1111
|
+
const scopedQueryClient = new QueryClient(
|
|
1112
|
+
rlsClient,
|
|
1113
|
+
"rls-scoped",
|
|
1114
|
+
rowPolicyOpts
|
|
1115
|
+
);
|
|
1116
|
+
return {
|
|
1117
|
+
client: new MooseClient(scopedQueryClient),
|
|
1118
|
+
sql,
|
|
1119
|
+
jwt: void 0
|
|
1120
|
+
};
|
|
991
1121
|
}
|
|
992
1122
|
async function getMooseClients(config) {
|
|
993
1123
|
console.warn(
|
|
@@ -1012,15 +1142,19 @@ async function getMooseClients(config) {
|
|
|
1012
1142
|
const utils = await getMooseUtils();
|
|
1013
1143
|
return { client: utils.client };
|
|
1014
1144
|
}
|
|
1015
|
-
var standaloneUtils, initPromise, toClientConfig;
|
|
1145
|
+
var requestContextStorage, standaloneUtils, initPromise, standaloneRlsClient, standaloneClickhouseConfig, toClientConfig;
|
|
1016
1146
|
var init_standalone = __esm({
|
|
1017
1147
|
"src/consumption-apis/standalone.ts"() {
|
|
1018
1148
|
"use strict";
|
|
1019
1149
|
init_helpers();
|
|
1020
1150
|
init_commons();
|
|
1021
1151
|
init_sqlHelpers();
|
|
1152
|
+
init_registry();
|
|
1153
|
+
requestContextStorage = new AsyncLocalStorage();
|
|
1022
1154
|
standaloneUtils = null;
|
|
1023
1155
|
initPromise = null;
|
|
1156
|
+
standaloneRlsClient = null;
|
|
1157
|
+
standaloneClickhouseConfig = null;
|
|
1024
1158
|
toClientConfig = (config) => ({
|
|
1025
1159
|
...config,
|
|
1026
1160
|
useSSL: config.useSSL ? "true" : "false"
|
|
@@ -2917,7 +3051,8 @@ function createRegistryFrom(existing) {
|
|
|
2917
3051
|
workflows: toTrackingMap(existing?.workflows),
|
|
2918
3052
|
webApps: toTrackingMap(existing?.webApps),
|
|
2919
3053
|
materializedViews: toTrackingMap(existing?.materializedViews),
|
|
2920
|
-
views: toTrackingMap(existing?.views)
|
|
3054
|
+
views: toTrackingMap(existing?.views),
|
|
3055
|
+
selectRowPolicies: toTrackingMap(existing?.selectRowPolicies)
|
|
2921
3056
|
};
|
|
2922
3057
|
}
|
|
2923
3058
|
function getCachedLineage(registry) {
|
|
@@ -3271,7 +3406,11 @@ var init_internal = __esm({
|
|
|
3271
3406
|
void 0,
|
|
3272
3407
|
markRegistryMutated
|
|
3273
3408
|
),
|
|
3274
|
-
views: new MutationTrackingMap(void 0, markRegistryMutated)
|
|
3409
|
+
views: new MutationTrackingMap(void 0, markRegistryMutated),
|
|
3410
|
+
selectRowPolicies: new MutationTrackingMap(
|
|
3411
|
+
void 0,
|
|
3412
|
+
markRegistryMutated
|
|
3413
|
+
)
|
|
3275
3414
|
};
|
|
3276
3415
|
defaultRetentionPeriod = 60 * 60 * 24 * 7;
|
|
3277
3416
|
toInfraMap = (registry) => {
|
|
@@ -3284,6 +3423,7 @@ var init_internal = __esm({
|
|
|
3284
3423
|
const webApps = {};
|
|
3285
3424
|
const materializedViews = {};
|
|
3286
3425
|
const views = {};
|
|
3426
|
+
const selectRowPolicies = {};
|
|
3287
3427
|
const lineage = getCachedLineage(registry);
|
|
3288
3428
|
registry.tables.forEach((table) => {
|
|
3289
3429
|
const id = table.config.version ? `${table.name}_${table.config.version}` : table.name;
|
|
@@ -3531,6 +3671,14 @@ var init_internal = __esm({
|
|
|
3531
3671
|
metadata: view.metadata
|
|
3532
3672
|
};
|
|
3533
3673
|
});
|
|
3674
|
+
registry.selectRowPolicies.forEach((policy) => {
|
|
3675
|
+
selectRowPolicies[policy.name] = {
|
|
3676
|
+
name: policy.name,
|
|
3677
|
+
tables: policy.tableRefs,
|
|
3678
|
+
column: policy.config.column,
|
|
3679
|
+
claim: policy.config.claim
|
|
3680
|
+
};
|
|
3681
|
+
});
|
|
3534
3682
|
return {
|
|
3535
3683
|
topics,
|
|
3536
3684
|
tables,
|
|
@@ -3541,6 +3689,7 @@ var init_internal = __esm({
|
|
|
3541
3689
|
webApps,
|
|
3542
3690
|
materializedViews,
|
|
3543
3691
|
views,
|
|
3692
|
+
selectRowPolicies,
|
|
3544
3693
|
unloadedFiles: []
|
|
3545
3694
|
// Will be populated by dumpMooseInternal
|
|
3546
3695
|
};
|
|
@@ -3584,6 +3733,7 @@ var init_internal = __esm({
|
|
|
3584
3733
|
registry.webApps.clear();
|
|
3585
3734
|
registry.materializedViews.clear();
|
|
3586
3735
|
registry.views.clear();
|
|
3736
|
+
registry.selectRowPolicies.clear();
|
|
3587
3737
|
const outDir = getOutDir();
|
|
3588
3738
|
const compiledDir = path5.isAbsolute(outDir) ? outDir : path5.join(process3.cwd(), outDir);
|
|
3589
3739
|
Object.keys(__require.cache).forEach((key) => {
|
|
@@ -3923,9 +4073,9 @@ init_compiler_config();
|
|
|
3923
4073
|
|
|
3924
4074
|
// src/utils/structured-logging.ts
|
|
3925
4075
|
import * as util from "util";
|
|
3926
|
-
import { AsyncLocalStorage } from "async_hooks";
|
|
4076
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
3927
4077
|
function setupStructuredConsole(getContextField, contextFieldName) {
|
|
3928
|
-
const contextStorage = new
|
|
4078
|
+
const contextStorage = new AsyncLocalStorage2();
|
|
3929
4079
|
const originalConsole = {
|
|
3930
4080
|
log: console.log,
|
|
3931
4081
|
info: console.info,
|
|
@@ -4065,7 +4215,61 @@ var apiContextStorage = setupStructuredConsole(
|
|
|
4065
4215
|
(ctx) => ctx.apiName,
|
|
4066
4216
|
"api_name"
|
|
4067
4217
|
);
|
|
4068
|
-
|
|
4218
|
+
async function authenticateRequest(req, res, publicKey, jwtConfig, enforceAuth, rowPoliciesConfig) {
|
|
4219
|
+
const requireAuth = enforceAuth || !!rowPoliciesConfig;
|
|
4220
|
+
let jwtPayload;
|
|
4221
|
+
if (publicKey && jwtConfig) {
|
|
4222
|
+
const jwt = req.headers.authorization?.split(" ")[1];
|
|
4223
|
+
if (jwt) {
|
|
4224
|
+
try {
|
|
4225
|
+
const { payload } = await jose.jwtVerify(jwt, publicKey, {
|
|
4226
|
+
issuer: jwtConfig.issuer,
|
|
4227
|
+
audience: jwtConfig.audience
|
|
4228
|
+
});
|
|
4229
|
+
jwtPayload = payload;
|
|
4230
|
+
} catch (_error) {
|
|
4231
|
+
console.log("JWT verification failed");
|
|
4232
|
+
if (requireAuth) {
|
|
4233
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4234
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4235
|
+
return null;
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
} else if (requireAuth) {
|
|
4239
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4240
|
+
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4241
|
+
return null;
|
|
4242
|
+
}
|
|
4243
|
+
} else if (requireAuth) {
|
|
4244
|
+
if (rowPoliciesConfig) {
|
|
4245
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
4246
|
+
res.end(
|
|
4247
|
+
JSON.stringify({
|
|
4248
|
+
error: "Forbidden",
|
|
4249
|
+
message: "Row policies require JWT authentication. Configure jwt.secret in moose.config.toml."
|
|
4250
|
+
})
|
|
4251
|
+
);
|
|
4252
|
+
} else {
|
|
4253
|
+
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4254
|
+
res.end(
|
|
4255
|
+
JSON.stringify({
|
|
4256
|
+
error: "Unauthorized",
|
|
4257
|
+
message: "Authentication is enforced but no JWT configuration is available."
|
|
4258
|
+
})
|
|
4259
|
+
);
|
|
4260
|
+
}
|
|
4261
|
+
return null;
|
|
4262
|
+
}
|
|
4263
|
+
let rowPolicyOpts;
|
|
4264
|
+
if (rowPoliciesConfig && jwtPayload) {
|
|
4265
|
+
rowPolicyOpts = buildRowPolicyOptionsFromClaims(
|
|
4266
|
+
rowPoliciesConfig,
|
|
4267
|
+
jwtPayload
|
|
4268
|
+
);
|
|
4269
|
+
}
|
|
4270
|
+
return { jwtPayload, rowPolicyOpts };
|
|
4271
|
+
}
|
|
4272
|
+
var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig, rowPoliciesConfig, rlsClickhouseClient) => {
|
|
4069
4273
|
const sourceDir = getSourceDir();
|
|
4070
4274
|
const outDir = getOutDir();
|
|
4071
4275
|
const outRoot = path6.isAbsolute(outDir) ? outDir : path6.join(process.cwd(), outDir);
|
|
@@ -4077,37 +4281,19 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4077
4281
|
try {
|
|
4078
4282
|
const url = new URL(req.url || "", "http://localhost");
|
|
4079
4283
|
const fileName = url.pathname;
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
jwtPayload = payload;
|
|
4090
|
-
} catch (error) {
|
|
4091
|
-
console.log("JWT verification failed");
|
|
4092
|
-
if (enforceAuth) {
|
|
4093
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4094
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4095
|
-
httpLogger(req, res, start);
|
|
4096
|
-
return;
|
|
4097
|
-
}
|
|
4098
|
-
}
|
|
4099
|
-
} else if (enforceAuth) {
|
|
4100
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4101
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4102
|
-
httpLogger(req, res, start);
|
|
4103
|
-
return;
|
|
4104
|
-
}
|
|
4105
|
-
} else if (enforceAuth) {
|
|
4106
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
4107
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
4284
|
+
const authResult = await authenticateRequest(
|
|
4285
|
+
req,
|
|
4286
|
+
res,
|
|
4287
|
+
publicKey,
|
|
4288
|
+
jwtConfig,
|
|
4289
|
+
enforceAuth,
|
|
4290
|
+
rowPoliciesConfig
|
|
4291
|
+
);
|
|
4292
|
+
if (!authResult) {
|
|
4108
4293
|
httpLogger(req, res, start);
|
|
4109
4294
|
return;
|
|
4110
4295
|
}
|
|
4296
|
+
const { jwtPayload, rowPolicyOpts } = authResult;
|
|
4111
4297
|
const pathName = createPath(actualApisDir, fileName);
|
|
4112
4298
|
const paramsObject = Array.from(url.searchParams.entries()).reduce(
|
|
4113
4299
|
(obj, [key, value]) => {
|
|
@@ -4177,7 +4363,12 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4177
4363
|
console.log(`[API] | Executing API: ${matchedApiName}`);
|
|
4178
4364
|
});
|
|
4179
4365
|
}
|
|
4180
|
-
const
|
|
4366
|
+
const queryClickhouseClient = rowPolicyOpts && rlsClickhouseClient ? rlsClickhouseClient : clickhouseClient;
|
|
4367
|
+
const queryClient = new QueryClient(
|
|
4368
|
+
queryClickhouseClient,
|
|
4369
|
+
fileName,
|
|
4370
|
+
rowPolicyOpts
|
|
4371
|
+
);
|
|
4181
4372
|
const apiName = matchedApiName;
|
|
4182
4373
|
const result = await apiContextStorage.run({ apiName }, async () => {
|
|
4183
4374
|
return await userFuncModule(paramsObject, {
|
|
@@ -4233,13 +4424,15 @@ var apiHandler = async (publicKey, clickhouseClient, temporalClient, enforceAuth
|
|
|
4233
4424
|
}
|
|
4234
4425
|
};
|
|
4235
4426
|
};
|
|
4236
|
-
var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig) => {
|
|
4427
|
+
var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enforceAuth, jwtConfig, rowPoliciesConfig, rlsClickhouseClient) => {
|
|
4237
4428
|
const apiRequestHandler = await apiHandler(
|
|
4238
4429
|
publicKey,
|
|
4239
4430
|
clickhouseClient,
|
|
4240
4431
|
temporalClient,
|
|
4241
4432
|
enforceAuth,
|
|
4242
|
-
jwtConfig
|
|
4433
|
+
jwtConfig,
|
|
4434
|
+
rowPoliciesConfig,
|
|
4435
|
+
rlsClickhouseClient
|
|
4243
4436
|
);
|
|
4244
4437
|
const webApps = await getWebApps2();
|
|
4245
4438
|
const sortedWebApps = Array.from(webApps.values()).sort((a, b) => {
|
|
@@ -4261,30 +4454,22 @@ var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enfor
|
|
|
4261
4454
|
);
|
|
4262
4455
|
return;
|
|
4263
4456
|
}
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
} catch (error) {
|
|
4275
|
-
console.log("JWT verification failed for WebApp route");
|
|
4276
|
-
}
|
|
4277
|
-
}
|
|
4278
|
-
}
|
|
4457
|
+
const authResult = await authenticateRequest(
|
|
4458
|
+
req,
|
|
4459
|
+
res,
|
|
4460
|
+
publicKey,
|
|
4461
|
+
jwtConfig,
|
|
4462
|
+
enforceAuth,
|
|
4463
|
+
rowPoliciesConfig
|
|
4464
|
+
);
|
|
4465
|
+
if (!authResult) return;
|
|
4466
|
+
const { jwtPayload, rowPolicyOpts } = authResult;
|
|
4279
4467
|
for (const webApp of sortedWebApps) {
|
|
4280
4468
|
const mountPath = webApp.config.mountPath || "/";
|
|
4281
4469
|
const normalizedMount = mountPath.endsWith("/") && mountPath !== "/" ? mountPath.slice(0, -1) : mountPath;
|
|
4282
4470
|
const matches = pathname === normalizedMount || pathname.startsWith(normalizedMount + "/");
|
|
4283
4471
|
if (matches) {
|
|
4284
|
-
|
|
4285
|
-
const { getMooseUtils: getMooseUtils2 } = await Promise.resolve().then(() => (init_standalone(), standalone_exports));
|
|
4286
|
-
req.moose = await getMooseUtils2();
|
|
4287
|
-
}
|
|
4472
|
+
const { getMooseUtils: getMooseUtils2, runWithRequestContext: runWithRequestContext2 } = await Promise.resolve().then(() => (init_standalone(), standalone_exports));
|
|
4288
4473
|
let proxiedUrl = req.url;
|
|
4289
4474
|
if (normalizedMount !== "/") {
|
|
4290
4475
|
const pathWithoutMount = pathname.substring(normalizedMount.length) || "/";
|
|
@@ -4298,7 +4483,15 @@ var createMainRouter = async (publicKey, clickhouseClient, temporalClient, enfor
|
|
|
4298
4483
|
url: proxiedUrl
|
|
4299
4484
|
}
|
|
4300
4485
|
);
|
|
4301
|
-
await
|
|
4486
|
+
await runWithRequestContext2(
|
|
4487
|
+
{ rowPolicyOpts, jwt: jwtPayload },
|
|
4488
|
+
async () => {
|
|
4489
|
+
if (webApp.config.injectMooseUtils !== false) {
|
|
4490
|
+
modifiedReq.moose = await getMooseUtils2();
|
|
4491
|
+
}
|
|
4492
|
+
await webApp.handler(modifiedReq, res);
|
|
4493
|
+
}
|
|
4494
|
+
);
|
|
4302
4495
|
return;
|
|
4303
4496
|
} catch (error) {
|
|
4304
4497
|
console.error(`Error in WebApp ${webApp.name}:`, error);
|
|
@@ -4349,14 +4542,33 @@ var runApis = async (config) => {
|
|
|
4349
4542
|
const clickhouseClient = getClickhouseClient(
|
|
4350
4543
|
toClientConfig2(config.clickhouseConfig)
|
|
4351
4544
|
);
|
|
4545
|
+
let rlsClickhouseClient;
|
|
4546
|
+
if (config.rowPoliciesConfig) {
|
|
4547
|
+
rlsClickhouseClient = getClickhouseClient(
|
|
4548
|
+
toClientConfig2({
|
|
4549
|
+
...config.clickhouseConfig,
|
|
4550
|
+
username: config.clickhouseConfig.rlsUser ?? MOOSE_RLS_USER,
|
|
4551
|
+
password: config.clickhouseConfig.rlsPassword ?? config.clickhouseConfig.password
|
|
4552
|
+
})
|
|
4553
|
+
);
|
|
4554
|
+
}
|
|
4352
4555
|
let publicKey;
|
|
4353
4556
|
if (config.jwtConfig?.secret) {
|
|
4354
4557
|
console.log("Importing JWT public key...");
|
|
4355
4558
|
publicKey = await jose.importSPKI(config.jwtConfig.secret, "RS256");
|
|
4356
4559
|
}
|
|
4560
|
+
if (config.rowPoliciesConfig && !publicKey) {
|
|
4561
|
+
console.error(
|
|
4562
|
+
"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."
|
|
4563
|
+
);
|
|
4564
|
+
}
|
|
4357
4565
|
const runtimeQueryClient = new QueryClient(clickhouseClient, "runtime");
|
|
4358
4566
|
globalThis._mooseRuntimeContext = {
|
|
4359
|
-
client: new MooseClient(runtimeQueryClient, temporalClient)
|
|
4567
|
+
client: new MooseClient(runtimeQueryClient, temporalClient),
|
|
4568
|
+
clickhouseClient,
|
|
4569
|
+
rlsClickhouseClient,
|
|
4570
|
+
temporalClient,
|
|
4571
|
+
rowPoliciesConfig: config.rowPoliciesConfig
|
|
4360
4572
|
};
|
|
4361
4573
|
const server = http.createServer(
|
|
4362
4574
|
await createMainRouter(
|
|
@@ -4364,7 +4576,9 @@ var runApis = async (config) => {
|
|
|
4364
4576
|
clickhouseClient,
|
|
4365
4577
|
temporalClient,
|
|
4366
4578
|
config.enforceAuth,
|
|
4367
|
-
config.jwtConfig
|
|
4579
|
+
config.jwtConfig,
|
|
4580
|
+
config.rowPoliciesConfig,
|
|
4581
|
+
rlsClickhouseClient
|
|
4368
4582
|
)
|
|
4369
4583
|
);
|
|
4370
4584
|
const port = config.proxyPort !== void 0 ? config.proxyPort : 4001;
|
|
@@ -5383,7 +5597,10 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5383
5597
|
"--worker-count <count>",
|
|
5384
5598
|
"Number of worker processes for the consumption API cluster",
|
|
5385
5599
|
parseInt
|
|
5386
|
-
).
|
|
5600
|
+
).option(
|
|
5601
|
+
"--row-policies <json>",
|
|
5602
|
+
"JSON map of ClickHouse setting names to JWT claim names for row policy enforcement"
|
|
5603
|
+
).option("--rls-user <user>", "ClickHouse username for RLS queries").option("--rls-password <password>", "ClickHouse password for RLS queries").action(
|
|
5387
5604
|
(clickhouseDb, clickhouseHost, clickhousePort, clickhouseUsername, clickhousePassword, options) => {
|
|
5388
5605
|
runApis({
|
|
5389
5606
|
clickhouseConfig: {
|
|
@@ -5392,7 +5609,9 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5392
5609
|
port: clickhousePort,
|
|
5393
5610
|
username: clickhouseUsername,
|
|
5394
5611
|
password: clickhousePassword,
|
|
5395
|
-
useSSL: options.clickhouseUseSsl
|
|
5612
|
+
useSSL: options.clickhouseUseSsl,
|
|
5613
|
+
rlsUser: options.rlsUser,
|
|
5614
|
+
rlsPassword: options.rlsPassword
|
|
5396
5615
|
},
|
|
5397
5616
|
jwtConfig: {
|
|
5398
5617
|
secret: options.jwtSecret,
|
|
@@ -5408,7 +5627,27 @@ program.command("consumption-apis").description("Run consumption APIs").argument
|
|
|
5408
5627
|
} : void 0,
|
|
5409
5628
|
enforceAuth: options.enforceAuth,
|
|
5410
5629
|
proxyPort: options.proxyPort,
|
|
5411
|
-
workerCount: options.workerCount
|
|
5630
|
+
workerCount: options.workerCount,
|
|
5631
|
+
rowPoliciesConfig: options.rowPolicies ? (() => {
|
|
5632
|
+
let parsed;
|
|
5633
|
+
try {
|
|
5634
|
+
parsed = JSON.parse(options.rowPolicies);
|
|
5635
|
+
} catch (e) {
|
|
5636
|
+
console.error(
|
|
5637
|
+
`Failed to parse --row-policies JSON: ${e.message}`
|
|
5638
|
+
);
|
|
5639
|
+
process.exit(1);
|
|
5640
|
+
}
|
|
5641
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed) || !Object.values(parsed).every(
|
|
5642
|
+
(v) => typeof v === "string"
|
|
5643
|
+
)) {
|
|
5644
|
+
console.error(
|
|
5645
|
+
`Invalid --row-policies JSON: expected a flat object with string values`
|
|
5646
|
+
);
|
|
5647
|
+
process.exit(1);
|
|
5648
|
+
}
|
|
5649
|
+
return parsed;
|
|
5650
|
+
})() : void 0
|
|
5412
5651
|
});
|
|
5413
5652
|
}
|
|
5414
5653
|
);
|