@llmops/core 0.3.1 → 0.3.2-beta.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/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as literal, C as variantsSchema, D as any, E as _enum, F as union, I as unknown, M as object, N as record, O as array, P as string, S as variantVersionsSchema, T as zod_default, _ as environmentsSchema, a as matchType, b as schemas, c as logger, d as validatePartialTableData, f as validateTableData, g as environmentSecretsSchema, h as configsSchema, i as getMigrations, j as number, k as boolean, l as parsePartialTableData, m as configVariantsSchema, n as createDatabaseFromConnection, o as runAutoMigrations, p as SCHEMA_METADATA, r as detectDatabaseType, s as getAuthClientOptions, t as createDatabase, u as parseTableData, v as llmRequestsSchema, w as workspaceSettingsSchema, x as targetingRulesSchema, y as providerConfigsSchema } from "./db-B-EsQtOz.mjs";
1
+ import { A as array, C as targetingRulesSchema, D as zod_default, E as workspaceSettingsSchema, F as record, I as string, L as union, M as literal, N as number, O as _enum, P as object, R as unknown, S as schemas, T as variantsSchema, _ as environmentsSchema, a as matchType, b as providerConfigsSchema, c as logger, d as validatePartialTableData, f as validateTableData, g as environmentSecretsSchema, h as configsSchema, i as getMigrations, j as boolean, k as any, l as parsePartialTableData, m as configVariantsSchema, n as createDatabaseFromConnection, o as runAutoMigrations, p as SCHEMA_METADATA, r as detectDatabaseType, s as getAuthClientOptions, t as createDatabase, u as parseTableData, v as guardrailConfigsSchema, w as variantVersionsSchema, x as providerGuardrailOverridesSchema, y as llmRequestsSchema } from "./db-Bkg85wso.mjs";
2
2
  import { n as executeWithSchema, t as createNeonDialect } from "./neon-dialect-DySGBYUi.mjs";
3
3
  import gateway from "@llmops/gateway";
4
4
  import { sql } from "kysely";
@@ -1454,6 +1454,99 @@ const createEnvironmentSecretDataLayer = (db) => {
1454
1454
  };
1455
1455
  };
1456
1456
 
1457
+ //#endregion
1458
+ //#region src/datalayer/guardrailConfigs.ts
1459
+ const createGuardrailConfig = zod_default.object({
1460
+ name: zod_default.string().min(1),
1461
+ pluginId: zod_default.string().min(1),
1462
+ functionId: zod_default.string().min(1),
1463
+ hookType: zod_default.enum(["beforeRequestHook", "afterRequestHook"]),
1464
+ parameters: zod_default.record(zod_default.string(), zod_default.unknown()).optional().default({}),
1465
+ enabled: zod_default.boolean().optional().default(true),
1466
+ priority: zod_default.number().int().optional().default(0),
1467
+ onFail: zod_default.enum(["block", "log"]).optional().default("block")
1468
+ });
1469
+ const updateGuardrailConfig = zod_default.object({
1470
+ id: zod_default.string().uuid(),
1471
+ name: zod_default.string().min(1).optional(),
1472
+ hookType: zod_default.enum(["beforeRequestHook", "afterRequestHook"]).optional(),
1473
+ parameters: zod_default.record(zod_default.string(), zod_default.unknown()).optional(),
1474
+ enabled: zod_default.boolean().optional(),
1475
+ priority: zod_default.number().int().optional(),
1476
+ onFail: zod_default.enum(["block", "log"]).optional()
1477
+ });
1478
+ const getGuardrailConfigById = zod_default.object({ id: zod_default.string().uuid() });
1479
+ const deleteGuardrailConfig = zod_default.object({ id: zod_default.string().uuid() });
1480
+ const listGuardrailConfigs = zod_default.object({
1481
+ limit: zod_default.number().int().positive().optional(),
1482
+ offset: zod_default.number().int().nonnegative().optional(),
1483
+ hookType: zod_default.enum(["beforeRequestHook", "afterRequestHook"]).optional(),
1484
+ enabled: zod_default.boolean().optional()
1485
+ });
1486
+ const createGuardrailConfigsDataLayer = (db) => {
1487
+ return {
1488
+ createGuardrailConfig: async (params) => {
1489
+ const value = await createGuardrailConfig.safeParseAsync(params);
1490
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
1491
+ const { name, pluginId, functionId, hookType, parameters, enabled, priority, onFail } = value.data;
1492
+ return db.insertInto("guardrail_configs").values({
1493
+ id: randomUUID(),
1494
+ name,
1495
+ pluginId,
1496
+ functionId,
1497
+ hookType,
1498
+ parameters: JSON.stringify(parameters),
1499
+ enabled,
1500
+ priority,
1501
+ onFail,
1502
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1503
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1504
+ }).returningAll().executeTakeFirst();
1505
+ },
1506
+ updateGuardrailConfig: async (params) => {
1507
+ const value = await updateGuardrailConfig.safeParseAsync(params);
1508
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
1509
+ const { id, name, hookType, parameters, enabled, priority, onFail } = value.data;
1510
+ const updateData = { updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
1511
+ if (name !== void 0) updateData.name = name;
1512
+ if (hookType !== void 0) updateData.hookType = hookType;
1513
+ if (parameters !== void 0) updateData.parameters = JSON.stringify(parameters);
1514
+ if (enabled !== void 0) updateData.enabled = enabled;
1515
+ if (priority !== void 0) updateData.priority = priority;
1516
+ if (onFail !== void 0) updateData.onFail = onFail;
1517
+ return db.updateTable("guardrail_configs").set(updateData).where("id", "=", id).returningAll().executeTakeFirst();
1518
+ },
1519
+ getGuardrailConfigById: async (params) => {
1520
+ const value = await getGuardrailConfigById.safeParseAsync(params);
1521
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
1522
+ const { id } = value.data;
1523
+ return db.selectFrom("guardrail_configs").selectAll().where("id", "=", id).executeTakeFirst();
1524
+ },
1525
+ deleteGuardrailConfig: async (params) => {
1526
+ const value = await deleteGuardrailConfig.safeParseAsync(params);
1527
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
1528
+ const { id } = value.data;
1529
+ return db.deleteFrom("guardrail_configs").where("id", "=", id).returningAll().executeTakeFirst();
1530
+ },
1531
+ listGuardrailConfigs: async (params) => {
1532
+ const value = await listGuardrailConfigs.safeParseAsync(params || {});
1533
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
1534
+ const { limit = 100, offset = 0, hookType, enabled } = value.data;
1535
+ let query = db.selectFrom("guardrail_configs").selectAll().orderBy("priority", "desc").orderBy("createdAt", "desc").limit(limit).offset(offset);
1536
+ if (hookType !== void 0) query = query.where("hookType", "=", hookType);
1537
+ if (enabled !== void 0) query = query.where("enabled", "=", enabled);
1538
+ return query.execute();
1539
+ },
1540
+ countGuardrailConfigs: async () => {
1541
+ const result = await db.selectFrom("guardrail_configs").select(db.fn.countAll().as("count")).executeTakeFirst();
1542
+ return Number(result?.count ?? 0);
1543
+ },
1544
+ getEnabledGuardrailsByHookType: async (hookType) => {
1545
+ return db.selectFrom("guardrail_configs").selectAll().where("hookType", "=", hookType).where("enabled", "=", true).orderBy("priority", "desc").execute();
1546
+ }
1547
+ };
1548
+ };
1549
+
1457
1550
  //#endregion
1458
1551
  //#region src/datalayer/llmRequests.ts
1459
1552
  /**
@@ -1943,6 +2036,111 @@ const createProviderConfigsDataLayer = (db) => {
1943
2036
  };
1944
2037
  };
1945
2038
 
2039
+ //#endregion
2040
+ //#region src/datalayer/providerGuardrailOverrides.ts
2041
+ const createProviderGuardrailOverride = zod_default.object({
2042
+ providerConfigId: zod_default.string().uuid(),
2043
+ guardrailConfigId: zod_default.string().uuid(),
2044
+ enabled: zod_default.boolean().optional().default(true),
2045
+ parameters: zod_default.record(zod_default.string(), zod_default.unknown()).nullable().optional()
2046
+ });
2047
+ const updateProviderGuardrailOverride = zod_default.object({
2048
+ id: zod_default.string().uuid(),
2049
+ enabled: zod_default.boolean().optional(),
2050
+ parameters: zod_default.record(zod_default.string(), zod_default.unknown()).nullable().optional()
2051
+ });
2052
+ const getOverrideById = zod_default.object({ id: zod_default.string().uuid() });
2053
+ const deleteOverride = zod_default.object({ id: zod_default.string().uuid() });
2054
+ const getOverridesByProviderConfigId = zod_default.object({ providerConfigId: zod_default.string().uuid() });
2055
+ const getOverridesByGuardrailConfigId = zod_default.object({ guardrailConfigId: zod_default.string().uuid() });
2056
+ const getOverrideByProviderAndGuardrail = zod_default.object({
2057
+ providerConfigId: zod_default.string().uuid(),
2058
+ guardrailConfigId: zod_default.string().uuid()
2059
+ });
2060
+ const createProviderGuardrailOverridesDataLayer = (db) => {
2061
+ return {
2062
+ createProviderGuardrailOverride: async (params) => {
2063
+ const value = await createProviderGuardrailOverride.safeParseAsync(params);
2064
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2065
+ const { providerConfigId, guardrailConfigId, enabled, parameters } = value.data;
2066
+ return db.insertInto("provider_guardrail_overrides").values({
2067
+ id: randomUUID(),
2068
+ providerConfigId,
2069
+ guardrailConfigId,
2070
+ enabled,
2071
+ parameters: parameters ? JSON.stringify(parameters) : null,
2072
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2073
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2074
+ }).returningAll().executeTakeFirst();
2075
+ },
2076
+ updateProviderGuardrailOverride: async (params) => {
2077
+ const value = await updateProviderGuardrailOverride.safeParseAsync(params);
2078
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2079
+ const { id, enabled, parameters } = value.data;
2080
+ const updateData = { updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
2081
+ if (enabled !== void 0) updateData.enabled = enabled;
2082
+ if (parameters !== void 0) updateData.parameters = parameters ? JSON.stringify(parameters) : null;
2083
+ return db.updateTable("provider_guardrail_overrides").set(updateData).where("id", "=", id).returningAll().executeTakeFirst();
2084
+ },
2085
+ getOverrideById: async (params) => {
2086
+ const value = await getOverrideById.safeParseAsync(params);
2087
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2088
+ const { id } = value.data;
2089
+ return db.selectFrom("provider_guardrail_overrides").selectAll().where("id", "=", id).executeTakeFirst();
2090
+ },
2091
+ deleteProviderGuardrailOverride: async (params) => {
2092
+ const value = await deleteOverride.safeParseAsync(params);
2093
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2094
+ const { id } = value.data;
2095
+ return db.deleteFrom("provider_guardrail_overrides").where("id", "=", id).returningAll().executeTakeFirst();
2096
+ },
2097
+ getOverridesByProviderConfigId: async (params) => {
2098
+ const value = await getOverridesByProviderConfigId.safeParseAsync(params);
2099
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2100
+ const { providerConfigId } = value.data;
2101
+ return db.selectFrom("provider_guardrail_overrides").selectAll().where("providerConfigId", "=", providerConfigId).execute();
2102
+ },
2103
+ getOverridesByGuardrailConfigId: async (params) => {
2104
+ const value = await getOverridesByGuardrailConfigId.safeParseAsync(params);
2105
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2106
+ const { guardrailConfigId } = value.data;
2107
+ return db.selectFrom("provider_guardrail_overrides").selectAll().where("guardrailConfigId", "=", guardrailConfigId).execute();
2108
+ },
2109
+ getOverrideByProviderAndGuardrail: async (params) => {
2110
+ const value = await getOverrideByProviderAndGuardrail.safeParseAsync(params);
2111
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2112
+ const { providerConfigId, guardrailConfigId } = value.data;
2113
+ return db.selectFrom("provider_guardrail_overrides").selectAll().where("providerConfigId", "=", providerConfigId).where("guardrailConfigId", "=", guardrailConfigId).executeTakeFirst();
2114
+ },
2115
+ upsertProviderGuardrailOverride: async (params) => {
2116
+ const value = await createProviderGuardrailOverride.safeParseAsync(params);
2117
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2118
+ const { providerConfigId, guardrailConfigId, enabled, parameters } = value.data;
2119
+ const existing = await db.selectFrom("provider_guardrail_overrides").selectAll().where("providerConfigId", "=", providerConfigId).where("guardrailConfigId", "=", guardrailConfigId).executeTakeFirst();
2120
+ if (existing) return db.updateTable("provider_guardrail_overrides").set({
2121
+ enabled,
2122
+ parameters: parameters ? JSON.stringify(parameters) : null,
2123
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2124
+ }).where("id", "=", existing.id).returningAll().executeTakeFirst();
2125
+ return db.insertInto("provider_guardrail_overrides").values({
2126
+ id: randomUUID(),
2127
+ providerConfigId,
2128
+ guardrailConfigId,
2129
+ enabled,
2130
+ parameters: parameters ? JSON.stringify(parameters) : null,
2131
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
2132
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
2133
+ }).returningAll().executeTakeFirst();
2134
+ },
2135
+ deleteOverridesByGuardrailConfigId: async (params) => {
2136
+ const value = await getOverridesByGuardrailConfigId.safeParseAsync(params);
2137
+ if (!value.success) throw new LLMOpsError(`Invalid parameters: ${value.error.message}`);
2138
+ const { guardrailConfigId } = value.data;
2139
+ return db.deleteFrom("provider_guardrail_overrides").where("guardrailConfigId", "=", guardrailConfigId).execute();
2140
+ }
2141
+ };
2142
+ };
2143
+
1946
2144
  //#endregion
1947
2145
  //#region src/datalayer/targetingRules.ts
1948
2146
  const createTargetingRule = zod_default.object({
@@ -2416,8 +2614,10 @@ const createDataLayer = async (db) => {
2416
2614
  ...createConfigVariantDataLayer(db),
2417
2615
  ...createEnvironmentDataLayer(db),
2418
2616
  ...createEnvironmentSecretDataLayer(db),
2617
+ ...createGuardrailConfigsDataLayer(db),
2419
2618
  ...createLLMRequestsDataLayer(db),
2420
2619
  ...createProviderConfigsDataLayer(db),
2620
+ ...createProviderGuardrailOverridesDataLayer(db),
2421
2621
  ...createTargetingRulesDataLayer(db),
2422
2622
  ...createVariantDataLayer(db),
2423
2623
  ...createVariantVersionsDataLayer(db),
@@ -2642,14 +2842,16 @@ var ManifestBuilder = class {
2642
2842
  * Build the complete routing manifest from database
2643
2843
  */
2644
2844
  async build() {
2645
- const [configs, environments, environmentSecrets, targetingRules, configVariants, variantVersions, providerConfigs] = await Promise.all([
2845
+ const [configs, environments, environmentSecrets, targetingRules, configVariants, variantVersions, providerConfigs, guardrailConfigs, providerGuardrailOverridesData] = await Promise.all([
2646
2846
  this.db.selectFrom("configs").selectAll().execute(),
2647
2847
  this.db.selectFrom("environments").selectAll().execute(),
2648
2848
  this.db.selectFrom("environment_secrets").selectAll().execute(),
2649
2849
  this.db.selectFrom("targeting_rules").where("enabled", "=", true).selectAll().execute(),
2650
2850
  this.db.selectFrom("config_variants").selectAll().execute(),
2651
2851
  this.db.selectFrom("variant_versions").selectAll().execute(),
2652
- this.db.selectFrom("provider_configs").selectAll().execute()
2852
+ this.db.selectFrom("provider_configs").selectAll().execute(),
2853
+ this.db.selectFrom("guardrail_configs").where("enabled", "=", true).selectAll().execute(),
2854
+ this.db.selectFrom("provider_guardrail_overrides").selectAll().execute()
2653
2855
  ]);
2654
2856
  const manifestConfigs = {};
2655
2857
  const configsBySlug = {};
@@ -2742,6 +2944,39 @@ var ManifestBuilder = class {
2742
2944
  if (b.priority !== a.priority) return b.priority - a.priority;
2743
2945
  return b.weight - a.weight;
2744
2946
  });
2947
+ const beforeRequestGuardrails = [];
2948
+ const afterRequestGuardrails = [];
2949
+ logger.info(`[ManifestBuilder] Found ${guardrailConfigs.length} enabled guardrail configs`);
2950
+ for (const guardrail of guardrailConfigs) {
2951
+ const parameters = typeof guardrail.parameters === "string" ? JSON.parse(guardrail.parameters) : guardrail.parameters;
2952
+ const manifestGuardrail = {
2953
+ id: guardrail.id,
2954
+ name: guardrail.name,
2955
+ pluginId: guardrail.pluginId,
2956
+ functionId: guardrail.functionId,
2957
+ hookType: guardrail.hookType,
2958
+ parameters: parameters ?? {},
2959
+ priority: guardrail.priority,
2960
+ onFail: guardrail.onFail
2961
+ };
2962
+ if (guardrail.hookType === "beforeRequestHook") beforeRequestGuardrails.push(manifestGuardrail);
2963
+ else afterRequestGuardrails.push(manifestGuardrail);
2964
+ }
2965
+ beforeRequestGuardrails.sort((a, b) => b.priority - a.priority);
2966
+ afterRequestGuardrails.sort((a, b) => b.priority - a.priority);
2967
+ const providerGuardrailOverrides = {};
2968
+ for (const override of providerGuardrailOverridesData) {
2969
+ const parameters = typeof override.parameters === "string" ? JSON.parse(override.parameters) : override.parameters;
2970
+ const manifestOverride = {
2971
+ id: override.id,
2972
+ providerConfigId: override.providerConfigId,
2973
+ guardrailConfigId: override.guardrailConfigId,
2974
+ enabled: override.enabled,
2975
+ parameters: parameters ?? null
2976
+ };
2977
+ if (!providerGuardrailOverrides[override.providerConfigId]) providerGuardrailOverrides[override.providerConfigId] = [];
2978
+ providerGuardrailOverrides[override.providerConfigId].push(manifestOverride);
2979
+ }
2745
2980
  return {
2746
2981
  version: Date.now(),
2747
2982
  builtAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -2750,7 +2985,12 @@ var ManifestBuilder = class {
2750
2985
  environments: manifestEnvironments,
2751
2986
  environmentsBySlug,
2752
2987
  routingTable,
2753
- secretToEnvironment
2988
+ secretToEnvironment,
2989
+ guardrails: {
2990
+ beforeRequestHook: beforeRequestGuardrails,
2991
+ afterRequestHook: afterRequestGuardrails
2992
+ },
2993
+ providerGuardrailOverrides
2754
2994
  };
2755
2995
  }
2756
2996
  };
@@ -2957,4 +3197,4 @@ var ManifestRouter = class {
2957
3197
  };
2958
3198
 
2959
3199
  //#endregion
2960
- export { CacheService, FileCacheBackend, MS, ManifestBuilder, ManifestRouter, ManifestService, MemoryCacheBackend, ModelsDevPricingProvider, SCHEMA_METADATA, SupportedProviders, calculateCost, chatCompletionCreateParamsBaseSchema, configVariantsSchema, configsSchema, createDataLayer, createDatabase, createDatabaseFromConnection, createLLMRequestsDataLayer, createNeonDialect, createProviderConfigsDataLayer, createWorkspaceSettingsDataLayer, detectDatabaseType, dollarsToMicroDollars, environmentSecretsSchema, environmentsSchema, executeWithSchema, formatCost, gateway, generateId, getAuthClientOptions, getDefaultPricingProvider, getMigrations, llmRequestsSchema, llmopsConfigSchema, logger, matchType, microDollarsToDollars, parsePartialTableData, parseTableData, providerConfigsSchema, runAutoMigrations, schemas, targetingRulesSchema, validateLLMOpsConfig, validatePartialTableData, validateTableData, variantJsonDataSchema, variantVersionsSchema, variantsSchema, workspaceSettingsSchema };
3200
+ export { CacheService, FileCacheBackend, MS, ManifestBuilder, ManifestRouter, ManifestService, MemoryCacheBackend, ModelsDevPricingProvider, SCHEMA_METADATA, SupportedProviders, calculateCost, chatCompletionCreateParamsBaseSchema, configVariantsSchema, configsSchema, createDataLayer, createDatabase, createDatabaseFromConnection, createGuardrailConfigsDataLayer, createLLMRequestsDataLayer, createNeonDialect, createProviderConfigsDataLayer, createProviderGuardrailOverridesDataLayer, createWorkspaceSettingsDataLayer, detectDatabaseType, dollarsToMicroDollars, environmentSecretsSchema, environmentsSchema, executeWithSchema, formatCost, gateway, generateId, getAuthClientOptions, getDefaultPricingProvider, getMigrations, guardrailConfigsSchema, llmRequestsSchema, llmopsConfigSchema, logger, matchType, microDollarsToDollars, parsePartialTableData, parseTableData, providerConfigsSchema, providerGuardrailOverridesSchema, runAutoMigrations, schemas, targetingRulesSchema, validateLLMOpsConfig, validatePartialTableData, validateTableData, variantJsonDataSchema, variantVersionsSchema, variantsSchema, workspaceSettingsSchema };
@@ -1,4 +1,4 @@
1
- const require_db = require('./db-Du2xmkGS.cjs');
1
+ const require_db = require('./db-CCKBHjuz.cjs');
2
2
  let kysely_neon = require("kysely-neon");
3
3
  require("@neondatabase/serverless");
4
4
 
@@ -1,3 +1,3 @@
1
- const require_neon_dialect = require('./neon-dialect-BR1nZmKX.cjs');
1
+ const require_neon_dialect = require('./neon-dialect-DmI-frVR.cjs');
2
2
 
3
3
  exports.createNeonDialect = require_neon_dialect.createNeonDialect;
@@ -1,4 +1,4 @@
1
- const require_db = require('./db-Du2xmkGS.cjs');
1
+ const require_db = require('./db-CCKBHjuz.cjs');
2
2
  let kysely = require("kysely");
3
3
 
4
4
  //#region src/db/node-sqlite-dialect.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llmops/core",
3
- "version": "0.3.1",
3
+ "version": "0.3.2-beta.2",
4
4
  "description": "Core LLMOps functionality and utilities",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -55,7 +55,7 @@
55
55
  "kysely": "^0.28.8",
56
56
  "kysely-neon": "^2.0.2",
57
57
  "pino": "^10.1.0",
58
- "@llmops/gateway": "^0.3.1"
58
+ "@llmops/gateway": "^0.3.2-beta.2"
59
59
  },
60
60
  "devDependencies": {
61
61
  "@types/json-logic-js": "^2.0.8",