@memberjunction/server 5.31.0 → 5.33.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "5.31.0",
3
+ "version": "5.33.0",
4
4
  "description": "MemberJunction: This project provides API access via GraphQL to the common data store.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./src/index.ts",
@@ -27,73 +27,73 @@
27
27
  "@as-integrations/express5": "^1.0.0",
28
28
  "@graphql-tools/schema": "latest",
29
29
  "@graphql-tools/utils": "^11.0.0",
30
- "@memberjunction/actions": "5.31.0",
31
- "@memberjunction/actions-apollo": "5.31.0",
32
- "@memberjunction/actions-base": "5.31.0",
33
- "@memberjunction/actions-bizapps-accounting": "5.31.0",
34
- "@memberjunction/actions-bizapps-crm": "5.31.0",
35
- "@memberjunction/actions-bizapps-formbuilders": "5.31.0",
36
- "@memberjunction/actions-bizapps-lms": "5.31.0",
37
- "@memberjunction/actions-bizapps-social": "5.31.0",
38
- "@memberjunction/ai": "5.31.0",
39
- "@memberjunction/ai-agent-manager": "5.31.0",
40
- "@memberjunction/ai-agent-manager-actions": "5.31.0",
41
- "@memberjunction/ai-agents": "5.31.0",
42
- "@memberjunction/ai-core-plus": "5.31.0",
43
- "@memberjunction/ai-mcp-client": "5.31.0",
44
- "@memberjunction/ai-prompts": "5.31.0",
45
- "@memberjunction/ai-provider-bundle": "5.31.0",
46
- "@memberjunction/ai-vector-sync": "5.31.0",
47
- "@memberjunction/ai-vectordb": "5.31.0",
48
- "@memberjunction/ai-vectors-pinecone": "5.31.0",
49
- "@memberjunction/aiengine": "5.31.0",
50
- "@memberjunction/api-keys": "5.31.0",
51
- "@memberjunction/auth-providers": "5.31.0",
52
- "@memberjunction/codegen-lib": "5.31.0",
53
- "@memberjunction/communication-ms-graph": "5.31.0",
54
- "@memberjunction/communication-sendgrid": "5.31.0",
55
- "@memberjunction/communication-types": "5.31.0",
56
- "@memberjunction/component-registry-client-sdk": "5.31.0",
57
- "@memberjunction/computer-use-engine": "5.31.0",
58
- "@memberjunction/config": "5.31.0",
59
- "@memberjunction/core": "5.31.0",
60
- "@memberjunction/core-actions": "5.31.0",
61
- "@memberjunction/core-entities": "5.31.0",
62
- "@memberjunction/core-entities-server": "5.31.0",
63
- "@memberjunction/data-context": "5.31.0",
64
- "@memberjunction/data-context-server": "5.31.0",
65
- "@memberjunction/doc-utils": "5.31.0",
66
- "@memberjunction/encryption": "5.31.0",
67
- "@memberjunction/entity-communications-base": "5.31.0",
68
- "@memberjunction/entity-communications-server": "5.31.0",
69
- "@memberjunction/external-change-detection": "5.31.0",
70
- "@memberjunction/generic-database-provider": "5.31.0",
71
- "@memberjunction/global": "5.31.0",
72
- "@memberjunction/graphql-dataprovider": "5.31.0",
73
- "@memberjunction/integration-engine": "5.31.0",
74
- "@memberjunction/integration-schema-builder": "5.31.0",
75
- "@memberjunction/interactive-component-types": "5.31.0",
76
- "@memberjunction/notifications": "5.31.0",
77
- "@memberjunction/postgresql-dataprovider": "5.31.0",
78
- "@memberjunction/queue": "5.31.0",
79
- "@memberjunction/redis-provider": "5.31.0",
80
- "@memberjunction/scheduling-actions": "5.31.0",
81
- "@memberjunction/scheduling-base-types": "5.31.0",
82
- "@memberjunction/scheduling-engine": "5.31.0",
83
- "@memberjunction/scheduling-engine-base": "5.31.0",
84
- "@memberjunction/schema-engine": "5.31.0",
85
- "@memberjunction/search-engine": "5.31.0",
86
- "@memberjunction/server-extensions-core": "5.31.0",
87
- "@memberjunction/skip-types": "5.31.0",
88
- "@memberjunction/sql-dialect": "5.31.0",
89
- "@memberjunction/sqlserver-dataprovider": "5.31.0",
90
- "@memberjunction/storage": "5.31.0",
91
- "@memberjunction/tag-engine": "5.31.0",
92
- "@memberjunction/tag-engine-base": "5.31.0",
93
- "@memberjunction/templates": "5.31.0",
94
- "@memberjunction/testing-engine": "5.31.0",
95
- "@memberjunction/testing-engine-base": "5.31.0",
96
- "@memberjunction/version-history": "5.31.0",
30
+ "@memberjunction/actions": "5.33.0",
31
+ "@memberjunction/actions-apollo": "5.33.0",
32
+ "@memberjunction/actions-base": "5.33.0",
33
+ "@memberjunction/actions-bizapps-accounting": "5.33.0",
34
+ "@memberjunction/actions-bizapps-crm": "5.33.0",
35
+ "@memberjunction/actions-bizapps-formbuilders": "5.33.0",
36
+ "@memberjunction/actions-bizapps-lms": "5.33.0",
37
+ "@memberjunction/actions-bizapps-social": "5.33.0",
38
+ "@memberjunction/ai": "5.33.0",
39
+ "@memberjunction/ai-agent-manager": "5.33.0",
40
+ "@memberjunction/ai-agent-manager-actions": "5.33.0",
41
+ "@memberjunction/ai-agents": "5.33.0",
42
+ "@memberjunction/ai-core-plus": "5.33.0",
43
+ "@memberjunction/ai-mcp-client": "5.33.0",
44
+ "@memberjunction/ai-prompts": "5.33.0",
45
+ "@memberjunction/ai-provider-bundle": "5.33.0",
46
+ "@memberjunction/ai-vector-sync": "5.33.0",
47
+ "@memberjunction/ai-vectordb": "5.33.0",
48
+ "@memberjunction/ai-vectors-pinecone": "5.33.0",
49
+ "@memberjunction/aiengine": "5.33.0",
50
+ "@memberjunction/api-keys": "5.33.0",
51
+ "@memberjunction/auth-providers": "5.33.0",
52
+ "@memberjunction/codegen-lib": "5.33.0",
53
+ "@memberjunction/communication-ms-graph": "5.33.0",
54
+ "@memberjunction/communication-sendgrid": "5.33.0",
55
+ "@memberjunction/communication-types": "5.33.0",
56
+ "@memberjunction/component-registry-client-sdk": "5.33.0",
57
+ "@memberjunction/computer-use-engine": "5.33.0",
58
+ "@memberjunction/config": "5.33.0",
59
+ "@memberjunction/core": "5.33.0",
60
+ "@memberjunction/core-actions": "5.33.0",
61
+ "@memberjunction/core-entities": "5.33.0",
62
+ "@memberjunction/core-entities-server": "5.33.0",
63
+ "@memberjunction/data-context": "5.33.0",
64
+ "@memberjunction/data-context-server": "5.33.0",
65
+ "@memberjunction/doc-utils": "5.33.0",
66
+ "@memberjunction/encryption": "5.33.0",
67
+ "@memberjunction/entity-communications-base": "5.33.0",
68
+ "@memberjunction/entity-communications-server": "5.33.0",
69
+ "@memberjunction/external-change-detection": "5.33.0",
70
+ "@memberjunction/generic-database-provider": "5.33.0",
71
+ "@memberjunction/global": "5.33.0",
72
+ "@memberjunction/graphql-dataprovider": "5.33.0",
73
+ "@memberjunction/integration-engine": "5.33.0",
74
+ "@memberjunction/integration-schema-builder": "5.33.0",
75
+ "@memberjunction/interactive-component-types": "5.33.0",
76
+ "@memberjunction/notifications": "5.33.0",
77
+ "@memberjunction/postgresql-dataprovider": "5.33.0",
78
+ "@memberjunction/queue": "5.33.0",
79
+ "@memberjunction/redis-provider": "5.33.0",
80
+ "@memberjunction/scheduling-actions": "5.33.0",
81
+ "@memberjunction/scheduling-base-types": "5.33.0",
82
+ "@memberjunction/scheduling-engine": "5.33.0",
83
+ "@memberjunction/scheduling-engine-base": "5.33.0",
84
+ "@memberjunction/schema-engine": "5.33.0",
85
+ "@memberjunction/search-engine": "5.33.0",
86
+ "@memberjunction/server-extensions-core": "5.33.0",
87
+ "@memberjunction/skip-types": "5.33.0",
88
+ "@memberjunction/sql-dialect": "5.33.0",
89
+ "@memberjunction/sqlserver-dataprovider": "5.33.0",
90
+ "@memberjunction/storage": "5.33.0",
91
+ "@memberjunction/tag-engine": "5.33.0",
92
+ "@memberjunction/tag-engine-base": "5.33.0",
93
+ "@memberjunction/templates": "5.33.0",
94
+ "@memberjunction/testing-engine": "5.33.0",
95
+ "@memberjunction/testing-engine-base": "5.33.0",
96
+ "@memberjunction/version-history": "5.33.0",
97
97
  "@types/compression": "^1.8.1",
98
98
  "@types/cors": "^2.8.19",
99
99
  "@types/jsonwebtoken": "9.0.10",
@@ -94,6 +94,25 @@ vi.mock('@memberjunction/core', () => ({
94
94
  SetProvider: vi.fn(),
95
95
  }));
96
96
 
97
+ // `resolveDbPlatformFromEnv` lives in `@memberjunction/generic-database-provider`
98
+ // (server-only — it touches `process.env`). The real package would pull in
99
+ // AI / actions / queue transitively, which is too heavy for a unit-test mock.
100
+ // Inline the actual implementation here so the env-var-handling tests below
101
+ // exercise the genuine behavior (they're testing this function).
102
+ vi.mock('@memberjunction/generic-database-provider', () => ({
103
+ resolveDbPlatformFromEnv: (envVarName: string = 'DB_PLATFORM'): 'sqlserver' | 'postgresql' | undefined => {
104
+ const raw = process.env[envVarName];
105
+ if (raw === undefined) return undefined;
106
+ const normalized = raw.trim().toLowerCase();
107
+ if (normalized === '') return undefined;
108
+ if (normalized === 'sqlserver' || normalized === 'postgresql') return normalized;
109
+ throw new Error(
110
+ `Invalid ${envVarName} value '${raw}'. Must be 'sqlserver' or 'postgresql' (case-insensitive). ` +
111
+ `Legacy aliases ('mssql', 'postgres', 'pg') and the legacy env var DB_TYPE are no longer supported.`,
112
+ );
113
+ },
114
+ }));
115
+
97
116
  vi.mock('@memberjunction/sqlserver-dataprovider', () => ({
98
117
  SQLServerDataProvider: vi.fn(),
99
118
  SQLServerProviderConfigData: vi.fn(),
@@ -116,14 +135,14 @@ import {
116
135
  GetReadWriteProvider,
117
136
  } from '../util.js';
118
137
 
119
- // getDbType is a pure function in index.ts, but importing index.ts triggers
120
- // type-graphql. Replicate the logic here for isolated testing.
121
- function getDbType(): 'sqlserver' | 'postgresql' {
122
- const dbType = process.env.DB_TYPE?.toLowerCase();
123
- if (dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg') {
124
- return 'postgresql';
125
- }
126
- return 'sqlserver';
138
+ // `index.ts` exports `getDbType` but importing it triggers type-graphql at
139
+ // module load time, which is too heavy for a unit test. Re-derive the same
140
+ // logic here using the canonical helper from @memberjunction/global so the
141
+ // behavior under test stays in lockstep with production.
142
+ import { resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
143
+ import type { DatabasePlatform } from '@memberjunction/core';
144
+ function getDbType(): DatabasePlatform {
145
+ return resolveDbPlatformFromEnv() ?? 'sqlserver';
127
146
  }
128
147
 
129
148
  // --------------------------------------------------------------------------
@@ -196,52 +215,80 @@ describe('Database Abstraction Layer', () => {
196
215
  });
197
216
 
198
217
  // ======================================================================
199
- // 1. DB_TYPE detection
218
+ // 1. DB_PLATFORM detection (strict: throws on typo, DB_TYPE no longer read)
200
219
  // ======================================================================
201
- describe('getDbType – DB_TYPE environment detection', () => {
202
- it('should return "sqlserver" when DB_TYPE is not set', () => {
220
+ describe('getDbType – DB_PLATFORM env detection', () => {
221
+ beforeEach(() => {
222
+ // Clear both vars before each case. DB_PLATFORM is what the resolver
223
+ // reads now; DB_TYPE is cleared too so we can prove it's ignored
224
+ // (no silent fallback to the removed legacy var).
225
+ delete process.env.DB_PLATFORM;
203
226
  delete process.env.DB_TYPE;
204
- expect(getDbType()).toBe('sqlserver');
205
227
  });
206
228
 
207
- it('should return "postgresql" when DB_TYPE is "postgresql"', () => {
208
- process.env.DB_TYPE = 'postgresql';
209
- expect(getDbType()).toBe('postgresql');
229
+ it('returns "sqlserver" by default when DB_PLATFORM is not set', () => {
230
+ expect(getDbType()).toBe('sqlserver');
210
231
  });
211
232
 
212
- it('should return "postgresql" when DB_TYPE is "postgres"', () => {
213
- process.env.DB_TYPE = 'postgres';
233
+ it('returns "postgresql" when DB_PLATFORM is the canonical "postgresql"', () => {
234
+ process.env.DB_PLATFORM = 'postgresql';
214
235
  expect(getDbType()).toBe('postgresql');
215
236
  });
216
237
 
217
- it('should return "postgresql" when DB_TYPE is "pg"', () => {
218
- process.env.DB_TYPE = 'pg';
219
- expect(getDbType()).toBe('postgresql');
238
+ it('returns "sqlserver" when DB_PLATFORM is the canonical "sqlserver"', () => {
239
+ process.env.DB_PLATFORM = 'sqlserver';
240
+ expect(getDbType()).toBe('sqlserver');
220
241
  });
221
242
 
222
- it('should be case-insensitive for DB_TYPE values', () => {
223
- process.env.DB_TYPE = 'PostgreSQL';
243
+ it('is case-insensitive for canonical values', () => {
244
+ process.env.DB_PLATFORM = 'PostgreSQL';
224
245
  expect(getDbType()).toBe('postgresql');
225
246
 
226
- process.env.DB_TYPE = 'POSTGRES';
227
- expect(getDbType()).toBe('postgresql');
228
-
229
- process.env.DB_TYPE = 'PG';
230
- expect(getDbType()).toBe('postgresql');
247
+ process.env.DB_PLATFORM = 'SQLSERVER';
248
+ expect(getDbType()).toBe('sqlserver');
231
249
  });
232
250
 
233
- it('should return "sqlserver" for unrecognized DB_TYPE values', () => {
234
- process.env.DB_TYPE = 'mysql';
251
+ it('treats empty-string DB_PLATFORM as unset (returns "sqlserver" default)', () => {
252
+ process.env.DB_PLATFORM = '';
235
253
  expect(getDbType()).toBe('sqlserver');
236
254
  });
237
255
 
238
- it('should return "sqlserver" for empty-string DB_TYPE', () => {
239
- process.env.DB_TYPE = '';
256
+ it('treats whitespace-only DB_PLATFORM as unset', () => {
257
+ process.env.DB_PLATFORM = ' ';
240
258
  expect(getDbType()).toBe('sqlserver');
241
259
  });
242
260
 
243
- it('should return "sqlserver" when DB_TYPE is "sqlserver"', () => {
244
- process.env.DB_TYPE = 'sqlserver';
261
+ it('throws on legacy alias "mssql"', () => {
262
+ process.env.DB_PLATFORM = 'mssql';
263
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM value 'mssql'/);
264
+ });
265
+
266
+ it('throws on legacy alias "postgres"', () => {
267
+ process.env.DB_PLATFORM = 'postgres';
268
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM value 'postgres'/);
269
+ });
270
+
271
+ it('throws on legacy alias "pg"', () => {
272
+ process.env.DB_PLATFORM = 'pg';
273
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM value 'pg'/);
274
+ });
275
+
276
+ it('throws on unrecognized value "mysql"', () => {
277
+ process.env.DB_PLATFORM = 'mysql';
278
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM value 'mysql'/);
279
+ });
280
+
281
+ it('error message names the offending env var (so callers know which one)', () => {
282
+ process.env.DB_PLATFORM = 'oracle';
283
+ expect(() => getDbType()).toThrow(
284
+ /Must be 'sqlserver' or 'postgresql'/,
285
+ );
286
+ });
287
+
288
+ it('ignores DB_TYPE entirely (legacy env var no longer consulted)', () => {
289
+ // Before strict mode, DB_TYPE was the primary, then a fallback. Now
290
+ // it's neither — anyone with DB_TYPE in their .env must rename it.
291
+ process.env.DB_TYPE = 'postgresql';
245
292
  expect(getDbType()).toBe('sqlserver');
246
293
  });
247
294
  });
@@ -487,32 +534,32 @@ describe('Database Abstraction Layer', () => {
487
534
  // 7. Context creation – database type branching in contextFunction
488
535
  // ======================================================================
489
536
  describe('Database type branching for context creation', () => {
490
- it('should identify postgres when DB_TYPE is "postgresql"', () => {
491
- process.env.DB_TYPE = 'postgresql';
492
- const dbType = process.env.DB_TYPE?.toLowerCase();
493
- const isPostgres = dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg';
494
- expect(isPostgres).toBe(true);
537
+ beforeEach(() => {
538
+ delete process.env.DB_PLATFORM;
539
+ delete process.env.DB_TYPE;
495
540
  });
496
541
 
497
- it('should identify postgres when DB_TYPE is "pg"', () => {
498
- process.env.DB_TYPE = 'pg';
499
- const dbType = process.env.DB_TYPE?.toLowerCase();
500
- const isPostgres = dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg';
501
- expect(isPostgres).toBe(true);
542
+ // The branching logic in context creation goes through the same
543
+ // canonical helper that getDbType() uses, so all callers see one
544
+ // consistent platform value.
545
+ it('identifies postgres when DB_PLATFORM is "postgresql"', () => {
546
+ process.env.DB_PLATFORM = 'postgresql';
547
+ expect(getDbType() === 'postgresql').toBe(true);
502
548
  });
503
549
 
504
- it('should not identify postgres when DB_TYPE is "sqlserver"', () => {
505
- process.env.DB_TYPE = 'sqlserver';
506
- const dbType = process.env.DB_TYPE?.toLowerCase();
507
- const isPostgres = dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg';
508
- expect(isPostgres).toBe(false);
550
+ it('throws (does not silently downgrade) on legacy alias "pg"', () => {
551
+ process.env.DB_PLATFORM = 'pg';
552
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM/);
509
553
  });
510
554
 
511
- it('should not identify postgres when DB_TYPE is undefined', () => {
512
- delete process.env.DB_TYPE;
513
- const dbType = process.env.DB_TYPE?.toLowerCase();
514
- const isPostgres = dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg';
515
- expect(isPostgres).toBe(false);
555
+ it('does not identify postgres when DB_PLATFORM is "sqlserver"', () => {
556
+ process.env.DB_PLATFORM = 'sqlserver';
557
+ expect(getDbType() === 'postgresql').toBe(false);
558
+ });
559
+
560
+ it('does not identify postgres when DB_PLATFORM is undefined', () => {
561
+ delete process.env.DB_PLATFORM;
562
+ expect(getDbType() === 'postgresql').toBe(false);
516
563
  });
517
564
  });
518
565
 
@@ -793,23 +840,38 @@ describe('Database Abstraction Layer', () => {
793
840
  // 14. getDbType return type
794
841
  // ======================================================================
795
842
  describe('getDbType return type compliance', () => {
796
- it('should return a value matching the DatabasePlatform union type', () => {
843
+ beforeEach(() => {
844
+ delete process.env.DB_PLATFORM;
797
845
  delete process.env.DB_TYPE;
846
+ });
847
+
848
+ it('returns a value matching the DatabasePlatform union type when unset', () => {
798
849
  const result = getDbType();
799
850
  const validValues: string[] = ['sqlserver', 'postgresql'];
800
851
  expect(validValues).toContain(result);
801
852
  });
802
853
 
803
- it('should always return one of the two valid DatabasePlatform values', () => {
804
- const testValues = ['', 'oracle', 'mysql', 'sqlite', 'mongodb', undefined];
805
- for (const val of testValues) {
854
+ it('returns a canonical value or throws never returns a non-canonical string', () => {
855
+ // Strict contract: getDbType() either returns one of the two canonical
856
+ // platform names, or throws. There's no third "fallback to default"
857
+ // outcome for non-empty unrecognized values — silent fallback was the
858
+ // bug we're eliminating.
859
+ const validReturns = ['sqlserver', 'postgresql'];
860
+
861
+ // Unset / empty / whitespace return the default
862
+ for (const val of [undefined, '', ' ']) {
806
863
  if (val === undefined) {
807
- delete process.env.DB_TYPE;
864
+ delete process.env.DB_PLATFORM;
808
865
  } else {
809
- process.env.DB_TYPE = val;
866
+ process.env.DB_PLATFORM = val;
810
867
  }
811
- const result = getDbType();
812
- expect(['sqlserver', 'postgresql']).toContain(result);
868
+ expect(validReturns).toContain(getDbType());
869
+ }
870
+
871
+ // Unrecognized non-empty values throw
872
+ for (const val of ['oracle', 'mysql', 'sqlite', 'mongodb']) {
873
+ process.env.DB_PLATFORM = val;
874
+ expect(() => getDbType()).toThrow(/Invalid DB_PLATFORM/);
813
875
  }
814
876
  });
815
877
  });
@@ -110,9 +110,16 @@ export class NewUserBase {
110
110
  LogStatus(`Created User Application ${application.Name} for new user ${user.Name}`);
111
111
 
112
112
  const rv: RunView = new RunView();
113
+ // Boolean literal goes through the active provider's dialect:
114
+ // SQL Server emits `= 1`, PostgreSQL emits `= TRUE`.
115
+ // This keeps the filter server-side (no client-side `.filter()`
116
+ // pass) and uses the single source-of-truth helper instead of
117
+ // hardcoded SQL that is correct on one dialect but breaks on
118
+ // the other.
119
+ const trueLit = provider.Dialect.BooleanLiteral(true);
113
120
  const rvResult: RunViewResult<MJApplicationEntityEntityType> = await rv.RunView({
114
121
  EntityName: 'MJ: Application Entities',
115
- ExtraFilter: `ApplicationID = '${application.ID}' and DefaultForNewUser = 1`,
122
+ ExtraFilter: `ApplicationID = '${application.ID}' AND DefaultForNewUser = ${trueLit}`,
116
123
  }, contextUser);
117
124
 
118
125
  if(!rvResult.Success){
@@ -120,9 +127,11 @@ export class NewUserBase {
120
127
  continue;
121
128
  }
122
129
 
123
- LogStatus(`Creating ${rvResult.Results.length} User Application Entities for User Application ${application.Name} for new user ${user.Name}`);
130
+ const defaultForNewUserEntities = rvResult.Results;
124
131
 
125
- for(const [index, appEntity] of rvResult.Results.entries()){
132
+ LogStatus(`Creating ${defaultForNewUserEntities.length} User Application Entities for User Application ${application.Name} for new user ${user.Name}`);
133
+
134
+ for(const [index, appEntity] of defaultForNewUserEntities.entries()){
126
135
  const userAppEntity: MJUserApplicationEntityEntity = await md.GetEntityObject<MJUserApplicationEntityEntity>('MJ: User Application Entities', contextUser);
127
136
  userAppEntity.NewRecord();
128
137
  userAppEntity.UserApplicationID = userApplication.ID;
package/src/context.ts CHANGED
@@ -18,8 +18,27 @@ import { DatabaseProviderBase } from '@memberjunction/core';
18
18
  import { SQLServerDataProvider, SQLServerProviderConfigData, UserCache } from '@memberjunction/sqlserver-dataprovider';
19
19
  import { Metadata } from '@memberjunction/core';
20
20
  import { UUIDsEqual } from '@memberjunction/global';
21
+ import { resolveDbPlatformFromEnv } from '@memberjunction/generic-database-provider';
21
22
  import { GetAPIKeyEngine } from '@memberjunction/api-keys';
22
23
 
24
+ /**
25
+ * Renders a value for one-line console logging without Node's `[Object]` truncation.
26
+ * Arrays keep their structure; non-array objects collapse to JSON, truncated at `maxLen`.
27
+ * Objects whose JSON exceeds `maxLen` and contain nested structure are recursed into so
28
+ * outer keys remain visible.
29
+ */
30
+ function shortenForLog(value: unknown, maxLen = 300): unknown {
31
+ if (value === null || typeof value !== 'object') return value;
32
+ if (Array.isArray(value)) return value.map((v) => shortenForLog(v, maxLen));
33
+ const json = JSON.stringify(value);
34
+ if (json.length <= maxLen) return json;
35
+ const result: Record<string, unknown> = {};
36
+ for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
37
+ result[k] = shortenForLog(v, maxLen);
38
+ }
39
+ return result;
40
+ }
41
+
23
42
  const verifyAsync = async (issuer: string, token: string): Promise<jwt.JwtPayload> =>
24
43
  new Promise((resolve, reject) => {
25
44
  const options = getValidationOptions(issuer);
@@ -323,7 +342,7 @@ export const contextFunction =
323
342
  const reqAny = req as any;
324
343
  const operationName: string | undefined = reqAny.body?.operationName;
325
344
  if (operationName !== 'IntrospectionQuery') {
326
- console.log({ operationName, variables: reqAny.body?.variables || undefined });
345
+ console.dir({ operationName, variables: shortenForLog(reqAny.body?.variables) }, { depth: null, breakLength: 200 });
327
346
  }
328
347
 
329
348
  // Auth already happened in the unified auth middleware — just read the result
@@ -356,8 +375,7 @@ async function createPerRequestProviders(
356
375
  dataSource: sql.ConnectionPool,
357
376
  dataSources: DataSourceInfo[]
358
377
  ): Promise<Array<{ provider: DatabaseProviderBase; type: 'Read-Write' | 'Read-Only' }>> {
359
- const dbType = process.env.DB_TYPE?.toLowerCase();
360
- const isPostgres = dbType === 'postgresql' || dbType === 'postgres' || dbType === 'pg';
378
+ const isPostgres = resolveDbPlatformFromEnv() === 'postgresql';
361
379
 
362
380
  let p: DatabaseProviderBase;
363
381
  if (isPostgres) {