@constructive-io/graphql-env 3.34.2 → 3.34.4

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 CHANGED
@@ -99,6 +99,14 @@ Restart the server after changing its environment. `capabilityExtensions`
99
99
  retains introspection metadata for extension capabilities; it does not install
100
100
  PostgreSQL extensions or change the API's exposed schemas.
101
101
 
102
+ ### Grafast Cache Limits
103
+ - `GRAPHILE_QUERY_CACHE_MAX_LENGTH` - Maximum parsed and validated queries retained per schema
104
+ - `GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH` - Maximum operations retained for plan lookup per schema
105
+ - `GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH` - Maximum context/variable-specific plans retained per operation
106
+
107
+ Each cache limit must be a safe integer of at least `2`. When omitted, Grafast's
108
+ upstream default for that cache remains in effect.
109
+
102
110
  ### Feature Flags
103
111
  - `FEATURES_SIMPLE_INFLECTION` - Enable simple inflection plugin
104
112
  - `FEATURES_OPPOSITE_BASE_NAMES` - Enable opposite base names
package/env.js CHANGED
@@ -2,18 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getGraphQLEnvVars = void 0;
4
4
  const _12factor_env_1 = require("12factor-env");
5
+ const grafast_cache_limits_1 = require("./grafast-cache-limits");
5
6
  const scoped_introspection_1 = require("./scoped-introspection");
6
7
  /**
7
8
  * @param env - Environment object to read from (defaults to process.env for backwards compatibility)
8
9
  */
9
10
  const getGraphQLEnvVars = (env = process.env) => {
10
11
  const scopedIntrospection = (0, scoped_introspection_1.getScopedIntrospectionEnv)(env);
11
- const { GRAPHILE_SCHEMA, FEATURES_SIMPLE_INFLECTION, FEATURES_OPPOSITE_BASE_NAMES, FEATURES_POSTGIS, API_ROUTING_SCHEMA, API_IS_PUBLIC, API_EXPOSED_SCHEMAS, API_META_SCHEMAS, API_ANON_ROLE, API_ROLE_NAME, API_FLUSH_TOKEN, API_INTROSPECTION_ROLE, EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL, CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL, SMS_PROVIDER, SMS_SENDER_ID, SMS_REQUEST_TIMEOUT_MS, SEND_SMS_DRY_RUN, DEVSMS_BASE_URL } = env;
12
+ const { GRAPHILE_SCHEMA, GRAPHILE_QUERY_CACHE_MAX_LENGTH, GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH, GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH, FEATURES_SIMPLE_INFLECTION, FEATURES_OPPOSITE_BASE_NAMES, FEATURES_POSTGIS, API_ROUTING_SCHEMA, API_IS_PUBLIC, API_EXPOSED_SCHEMAS, API_META_SCHEMAS, API_ANON_ROLE, API_ROLE_NAME, API_FLUSH_TOKEN, API_INTROSPECTION_ROLE, EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL, CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL, SMS_PROVIDER, SMS_SENDER_ID, SMS_REQUEST_TIMEOUT_MS, SEND_SMS_DRY_RUN, DEVSMS_BASE_URL } = env;
12
13
  // Keep this function as a partial env-override parser. SMS runtime defaults
13
14
  // belong to the consuming application; injecting them here would incorrectly
14
15
  // let an absent env var overwrite pgpm.json or consumer-specific values.
15
16
  const smsRequestTimeoutMs = (0, _12factor_env_1.parseEnvNumber)(SMS_REQUEST_TIMEOUT_MS);
16
17
  const smsDryRun = (0, _12factor_env_1.parseEnvBoolean)(SEND_SMS_DRY_RUN);
18
+ const hasGrafastCacheLimits = [
19
+ GRAPHILE_QUERY_CACHE_MAX_LENGTH,
20
+ GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH,
21
+ GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH
22
+ ].some(value => value !== undefined);
17
23
  const hasSmsEnvOverrides = Boolean(SMS_PROVIDER ||
18
24
  SMS_SENDER_ID ||
19
25
  smsRequestTimeoutMs !== undefined ||
@@ -28,6 +34,13 @@ const getGraphQLEnvVars = (env = process.env) => {
28
34
  }
29
35
  }
30
36
  }),
37
+ ...(hasGrafastCacheLimits && {
38
+ grafastCache: (0, grafast_cache_limits_1.normalizeGrafastCacheLimits)({
39
+ queryCacheMaxLength: (0, grafast_cache_limits_1.parseGrafastCacheLimitEnv)(GRAPHILE_QUERY_CACHE_MAX_LENGTH, 'GRAPHILE_QUERY_CACHE_MAX_LENGTH'),
40
+ operationsCacheMaxLength: (0, grafast_cache_limits_1.parseGrafastCacheLimitEnv)(GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH, 'GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH'),
41
+ operationOperationPlansCacheMaxLength: (0, grafast_cache_limits_1.parseGrafastCacheLimitEnv)(GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH, 'GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH')
42
+ })
43
+ }),
31
44
  ...(GRAPHILE_SCHEMA && {
32
45
  schema: GRAPHILE_SCHEMA.includes(',')
33
46
  ? GRAPHILE_SCHEMA.split(',').map(s => s.trim())
package/esm/env.js CHANGED
@@ -1,16 +1,22 @@
1
1
  import { parseEnvBoolean, parseEnvNumber } from '12factor-env';
2
+ import { normalizeGrafastCacheLimits, parseGrafastCacheLimitEnv } from './grafast-cache-limits';
2
3
  import { getScopedIntrospectionEnv } from './scoped-introspection';
3
4
  /**
4
5
  * @param env - Environment object to read from (defaults to process.env for backwards compatibility)
5
6
  */
6
7
  export const getGraphQLEnvVars = (env = process.env) => {
7
8
  const scopedIntrospection = getScopedIntrospectionEnv(env);
8
- const { GRAPHILE_SCHEMA, FEATURES_SIMPLE_INFLECTION, FEATURES_OPPOSITE_BASE_NAMES, FEATURES_POSTGIS, API_ROUTING_SCHEMA, API_IS_PUBLIC, API_EXPOSED_SCHEMAS, API_META_SCHEMAS, API_ANON_ROLE, API_ROLE_NAME, API_FLUSH_TOKEN, API_INTROSPECTION_ROLE, EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL, CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL, SMS_PROVIDER, SMS_SENDER_ID, SMS_REQUEST_TIMEOUT_MS, SEND_SMS_DRY_RUN, DEVSMS_BASE_URL } = env;
9
+ const { GRAPHILE_SCHEMA, GRAPHILE_QUERY_CACHE_MAX_LENGTH, GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH, GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH, FEATURES_SIMPLE_INFLECTION, FEATURES_OPPOSITE_BASE_NAMES, FEATURES_POSTGIS, API_ROUTING_SCHEMA, API_IS_PUBLIC, API_EXPOSED_SCHEMAS, API_META_SCHEMAS, API_ANON_ROLE, API_ROLE_NAME, API_FLUSH_TOKEN, API_INTROSPECTION_ROLE, EMBEDDER_PROVIDER, EMBEDDER_MODEL, EMBEDDER_BASE_URL, CHAT_PROVIDER, CHAT_MODEL, CHAT_BASE_URL, SMS_PROVIDER, SMS_SENDER_ID, SMS_REQUEST_TIMEOUT_MS, SEND_SMS_DRY_RUN, DEVSMS_BASE_URL } = env;
9
10
  // Keep this function as a partial env-override parser. SMS runtime defaults
10
11
  // belong to the consuming application; injecting them here would incorrectly
11
12
  // let an absent env var overwrite pgpm.json or consumer-specific values.
12
13
  const smsRequestTimeoutMs = parseEnvNumber(SMS_REQUEST_TIMEOUT_MS);
13
14
  const smsDryRun = parseEnvBoolean(SEND_SMS_DRY_RUN);
15
+ const hasGrafastCacheLimits = [
16
+ GRAPHILE_QUERY_CACHE_MAX_LENGTH,
17
+ GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH,
18
+ GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH
19
+ ].some(value => value !== undefined);
14
20
  const hasSmsEnvOverrides = Boolean(SMS_PROVIDER ||
15
21
  SMS_SENDER_ID ||
16
22
  smsRequestTimeoutMs !== undefined ||
@@ -25,6 +31,13 @@ export const getGraphQLEnvVars = (env = process.env) => {
25
31
  }
26
32
  }
27
33
  }),
34
+ ...(hasGrafastCacheLimits && {
35
+ grafastCache: normalizeGrafastCacheLimits({
36
+ queryCacheMaxLength: parseGrafastCacheLimitEnv(GRAPHILE_QUERY_CACHE_MAX_LENGTH, 'GRAPHILE_QUERY_CACHE_MAX_LENGTH'),
37
+ operationsCacheMaxLength: parseGrafastCacheLimitEnv(GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH, 'GRAPHILE_OPERATIONS_CACHE_MAX_LENGTH'),
38
+ operationOperationPlansCacheMaxLength: parseGrafastCacheLimitEnv(GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH, 'GRAPHILE_OPERATION_PLANS_CACHE_MAX_LENGTH')
39
+ })
40
+ }),
28
41
  ...(GRAPHILE_SCHEMA && {
29
42
  schema: GRAPHILE_SCHEMA.includes(',')
30
43
  ? GRAPHILE_SCHEMA.split(',').map(s => s.trim())
@@ -0,0 +1,4 @@
1
+ import type { GrafastCacheLimits } from '@constructive-io/graphql-types';
2
+ export declare const parseGrafastCacheLimitEnv: (value: string | undefined, envName: string) => number | undefined;
3
+ /** Validate every configuration source before cache bounds reach Grafast. */
4
+ export declare const normalizeGrafastCacheLimits: (limits: GrafastCacheLimits | undefined) => Readonly<GrafastCacheLimits> | undefined;
@@ -0,0 +1,39 @@
1
+ import { parseEnvNumber } from '12factor-env';
2
+ const LIMIT_KEYS = [
3
+ 'queryCacheMaxLength',
4
+ 'operationsCacheMaxLength',
5
+ 'operationOperationPlansCacheMaxLength',
6
+ ];
7
+ const assertGrafastCacheLimit = (value, label) => {
8
+ if (!Number.isSafeInteger(value) || value < 2) {
9
+ throw new Error(`${label} must be a safe integer of at least 2`);
10
+ }
11
+ return value;
12
+ };
13
+ export const parseGrafastCacheLimitEnv = (value, envName) => {
14
+ if (value === undefined)
15
+ return undefined;
16
+ return assertGrafastCacheLimit(parseEnvNumber(value), envName);
17
+ };
18
+ /** Validate every configuration source before cache bounds reach Grafast. */
19
+ export const normalizeGrafastCacheLimits = (limits) => {
20
+ if (limits === undefined)
21
+ return undefined;
22
+ if (typeof limits !== 'object' || limits === null || Array.isArray(limits)) {
23
+ throw new Error('graphile.grafastCache must be an object');
24
+ }
25
+ const allowedKeys = new Set(LIMIT_KEYS);
26
+ for (const key of Object.keys(limits)) {
27
+ if (!allowedKeys.has(key)) {
28
+ throw new Error(`graphile.grafastCache contains unsupported setting '${key}'`);
29
+ }
30
+ }
31
+ const normalized = {};
32
+ for (const key of LIMIT_KEYS) {
33
+ const value = limits[key];
34
+ if (value !== undefined) {
35
+ normalized[key] = assertGrafastCacheLimit(value, `graphile.grafastCache.${key}`);
36
+ }
37
+ }
38
+ return Object.freeze(normalized);
39
+ };
package/esm/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { getGraphQLEnvVars } from './env';
2
+ export { normalizeGrafastCacheLimits } from './grafast-cache-limits';
2
3
  export { getConstructiveEnvOptions, getEnvOptions } from './merge';
3
4
  export type { DevSmsOptions, SmsOptions } from '@constructive-io/graphql-types';
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  // Export Constructive-specific env functions
2
2
  export { getGraphQLEnvVars } from './env';
3
+ export { normalizeGrafastCacheLimits } from './grafast-cache-limits';
3
4
  export { getConstructiveEnvOptions, getEnvOptions } from './merge';
package/esm/merge.js CHANGED
@@ -2,6 +2,7 @@ import { constructiveGraphqlDefaults } from '@constructive-io/graphql-types';
2
2
  import { getEnvOptions as getPgpmEnvOptions, loadConfigSync, replaceArrays } from '@pgpmjs/env';
3
3
  import deepmerge from 'deepmerge';
4
4
  import { getGraphQLEnvVars } from './env';
5
+ import { normalizeGrafastCacheLimits } from './grafast-cache-limits';
5
6
  /**
6
7
  * Get Constructive environment options by merging:
7
8
  * 1. Core PGPM defaults (from @pgpmjs/env)
@@ -27,7 +28,7 @@ export const getEnvOptions = (overrides = {}, cwd = process.cwd(), env = process
27
28
  // even though loadConfigSync returns PgpmOptions type
28
29
  const configOptions = loadConfigSync(cwd);
29
30
  // Merge in order: core -> graphql defaults -> config (for graphql keys) -> graphql env -> overrides
30
- return deepmerge.all([
31
+ const options = deepmerge.all([
31
32
  coreOptions,
32
33
  constructiveGraphqlDefaults,
33
34
  // Only merge graphql-related keys from config (if present)
@@ -42,6 +43,11 @@ export const getEnvOptions = (overrides = {}, cwd = process.cwd(), env = process
42
43
  ], {
43
44
  arrayMerge: replaceArrays
44
45
  });
46
+ const grafastCache = normalizeGrafastCacheLimits(options.graphile?.grafastCache);
47
+ if (grafastCache !== undefined && options.graphile) {
48
+ options.graphile = { ...options.graphile, grafastCache };
49
+ }
50
+ return options;
45
51
  };
46
52
  /**
47
53
  * Alias - same as getEnvOptions
@@ -0,0 +1,4 @@
1
+ import type { GrafastCacheLimits } from '@constructive-io/graphql-types';
2
+ export declare const parseGrafastCacheLimitEnv: (value: string | undefined, envName: string) => number | undefined;
3
+ /** Validate every configuration source before cache bounds reach Grafast. */
4
+ export declare const normalizeGrafastCacheLimits: (limits: GrafastCacheLimits | undefined) => Readonly<GrafastCacheLimits> | undefined;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeGrafastCacheLimits = exports.parseGrafastCacheLimitEnv = void 0;
4
+ const _12factor_env_1 = require("12factor-env");
5
+ const LIMIT_KEYS = [
6
+ 'queryCacheMaxLength',
7
+ 'operationsCacheMaxLength',
8
+ 'operationOperationPlansCacheMaxLength',
9
+ ];
10
+ const assertGrafastCacheLimit = (value, label) => {
11
+ if (!Number.isSafeInteger(value) || value < 2) {
12
+ throw new Error(`${label} must be a safe integer of at least 2`);
13
+ }
14
+ return value;
15
+ };
16
+ const parseGrafastCacheLimitEnv = (value, envName) => {
17
+ if (value === undefined)
18
+ return undefined;
19
+ return assertGrafastCacheLimit((0, _12factor_env_1.parseEnvNumber)(value), envName);
20
+ };
21
+ exports.parseGrafastCacheLimitEnv = parseGrafastCacheLimitEnv;
22
+ /** Validate every configuration source before cache bounds reach Grafast. */
23
+ const normalizeGrafastCacheLimits = (limits) => {
24
+ if (limits === undefined)
25
+ return undefined;
26
+ if (typeof limits !== 'object' || limits === null || Array.isArray(limits)) {
27
+ throw new Error('graphile.grafastCache must be an object');
28
+ }
29
+ const allowedKeys = new Set(LIMIT_KEYS);
30
+ for (const key of Object.keys(limits)) {
31
+ if (!allowedKeys.has(key)) {
32
+ throw new Error(`graphile.grafastCache contains unsupported setting '${key}'`);
33
+ }
34
+ }
35
+ const normalized = {};
36
+ for (const key of LIMIT_KEYS) {
37
+ const value = limits[key];
38
+ if (value !== undefined) {
39
+ normalized[key] = assertGrafastCacheLimit(value, `graphile.grafastCache.${key}`);
40
+ }
41
+ }
42
+ return Object.freeze(normalized);
43
+ };
44
+ exports.normalizeGrafastCacheLimits = normalizeGrafastCacheLimits;
package/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { getGraphQLEnvVars } from './env';
2
+ export { normalizeGrafastCacheLimits } from './grafast-cache-limits';
2
3
  export { getConstructiveEnvOptions, getEnvOptions } from './merge';
3
4
  export type { DevSmsOptions, SmsOptions } from '@constructive-io/graphql-types';
package/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEnvOptions = exports.getConstructiveEnvOptions = exports.getGraphQLEnvVars = void 0;
3
+ exports.getEnvOptions = exports.getConstructiveEnvOptions = exports.normalizeGrafastCacheLimits = exports.getGraphQLEnvVars = void 0;
4
4
  // Export Constructive-specific env functions
5
5
  var env_1 = require("./env");
6
6
  Object.defineProperty(exports, "getGraphQLEnvVars", { enumerable: true, get: function () { return env_1.getGraphQLEnvVars; } });
7
+ var grafast_cache_limits_1 = require("./grafast-cache-limits");
8
+ Object.defineProperty(exports, "normalizeGrafastCacheLimits", { enumerable: true, get: function () { return grafast_cache_limits_1.normalizeGrafastCacheLimits; } });
7
9
  var merge_1 = require("./merge");
8
10
  Object.defineProperty(exports, "getConstructiveEnvOptions", { enumerable: true, get: function () { return merge_1.getConstructiveEnvOptions; } });
9
11
  Object.defineProperty(exports, "getEnvOptions", { enumerable: true, get: function () { return merge_1.getEnvOptions; } });
package/merge.js CHANGED
@@ -8,6 +8,7 @@ const graphql_types_1 = require("@constructive-io/graphql-types");
8
8
  const env_1 = require("@pgpmjs/env");
9
9
  const deepmerge_1 = __importDefault(require("deepmerge"));
10
10
  const env_2 = require("./env");
11
+ const grafast_cache_limits_1 = require("./grafast-cache-limits");
11
12
  /**
12
13
  * Get Constructive environment options by merging:
13
14
  * 1. Core PGPM defaults (from @pgpmjs/env)
@@ -33,7 +34,7 @@ const getEnvOptions = (overrides = {}, cwd = process.cwd(), env = process.env) =
33
34
  // even though loadConfigSync returns PgpmOptions type
34
35
  const configOptions = (0, env_1.loadConfigSync)(cwd);
35
36
  // Merge in order: core -> graphql defaults -> config (for graphql keys) -> graphql env -> overrides
36
- return deepmerge_1.default.all([
37
+ const options = deepmerge_1.default.all([
37
38
  coreOptions,
38
39
  graphql_types_1.constructiveGraphqlDefaults,
39
40
  // Only merge graphql-related keys from config (if present)
@@ -48,6 +49,11 @@ const getEnvOptions = (overrides = {}, cwd = process.cwd(), env = process.env) =
48
49
  ], {
49
50
  arrayMerge: env_1.replaceArrays
50
51
  });
52
+ const grafastCache = (0, grafast_cache_limits_1.normalizeGrafastCacheLimits)(options.graphile?.grafastCache);
53
+ if (grafastCache !== undefined && options.graphile) {
54
+ options.graphile = { ...options.graphile, grafastCache };
55
+ }
56
+ return options;
51
57
  };
52
58
  exports.getEnvOptions = getEnvOptions;
53
59
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-env",
3
- "version": "3.34.2",
3
+ "version": "3.34.4",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "Constructive environment configuration with GraphQL/Graphile support",
6
6
  "main": "index.js",
@@ -30,8 +30,8 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "12factor-env": "^1.33.0",
33
- "@constructive-io/graphql-types": "^3.33.2",
34
- "@pgpmjs/env": "^2.45.2",
33
+ "@constructive-io/graphql-types": "^3.33.4",
34
+ "@pgpmjs/env": "^2.46.1",
35
35
  "deepmerge": "^4.3.1"
36
36
  },
37
37
  "keywords": [
@@ -45,5 +45,5 @@
45
45
  "devDependencies": {
46
46
  "makage": "^0.8.0"
47
47
  },
48
- "gitHead": "e05686fb94c5e22c954436f18c25aa4439b9e83e"
48
+ "gitHead": "34e91da5b3dd9c0cae14875afe609993acf53a84"
49
49
  }