@memberjunction/server 6.1.4 → 6.1.5

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.
Files changed (71) hide show
  1. package/README.md +30 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/auth/magicLink/MagicLinkService.d.ts +17 -15
  4. package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -1
  5. package/dist/auth/magicLink/MagicLinkService.js +49 -35
  6. package/dist/auth/magicLink/MagicLinkService.js.map +1 -1
  7. package/dist/auth/magicLink/magicLinkCore.d.ts +14 -33
  8. package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -1
  9. package/dist/auth/magicLink/magicLinkCore.js +20 -52
  10. package/dist/auth/magicLink/magicLinkCore.js.map +1 -1
  11. package/dist/context.d.ts.map +1 -1
  12. package/dist/context.js +11 -23
  13. package/dist/context.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +36 -44
  16. package/dist/index.js.map +1 -1
  17. package/dist/postgresqlCompat.d.ts +8 -0
  18. package/dist/postgresqlCompat.d.ts.map +1 -0
  19. package/dist/postgresqlCompat.js +19 -0
  20. package/dist/postgresqlCompat.js.map +1 -0
  21. package/dist/postgresqlPoolSettings.d.ts +108 -0
  22. package/dist/postgresqlPoolSettings.d.ts.map +1 -0
  23. package/dist/postgresqlPoolSettings.js +134 -0
  24. package/dist/postgresqlPoolSettings.js.map +1 -0
  25. package/dist/resolvers/AdhocQueryResolver.d.ts +10 -20
  26. package/dist/resolvers/AdhocQueryResolver.d.ts.map +1 -1
  27. package/dist/resolvers/AdhocQueryResolver.js +54 -174
  28. package/dist/resolvers/AdhocQueryResolver.js.map +1 -1
  29. package/dist/resolvers/RealtimeClientSessionResolver.d.ts +44 -6
  30. package/dist/resolvers/RealtimeClientSessionResolver.d.ts.map +1 -1
  31. package/dist/resolvers/RealtimeClientSessionResolver.js +90 -34
  32. package/dist/resolvers/RealtimeClientSessionResolver.js.map +1 -1
  33. package/dist/resolvers/RunAIAgentResolver.d.ts.map +1 -1
  34. package/dist/resolvers/RunAIAgentResolver.js +2 -1
  35. package/dist/resolvers/RunAIAgentResolver.js.map +1 -1
  36. package/dist/resolvers/adhocTimeout.d.ts +7 -0
  37. package/dist/resolvers/adhocTimeout.d.ts.map +1 -0
  38. package/dist/resolvers/adhocTimeout.js +12 -0
  39. package/dist/resolvers/adhocTimeout.js.map +1 -0
  40. package/dist/services/TaskGraphActionRunner.d.ts +13 -8
  41. package/dist/services/TaskGraphActionRunner.d.ts.map +1 -1
  42. package/dist/services/TaskGraphActionRunner.js +16 -15
  43. package/dist/services/TaskGraphActionRunner.js.map +1 -1
  44. package/package.json +92 -92
  45. package/src/__tests__/AdhocQueryResolver.bugs.test.ts +12 -35
  46. package/src/__tests__/AdhocQueryResolver.pagination.test.ts +6 -2
  47. package/src/__tests__/AdhocQueryResolver.scopeGuard.test.ts +3 -3
  48. package/src/__tests__/RealtimeClientSessionResolver.test.ts +216 -2
  49. package/src/__tests__/TaskGraphActionRunner.durablePayload.test.ts +129 -0
  50. package/src/__tests__/adhocTimeoutClamp.test.ts +26 -0
  51. package/src/__tests__/magicLink.test.ts +15 -76
  52. package/src/__tests__/magicLinkService.consume.test.ts +224 -0
  53. package/src/__tests__/postgresqlPoolSettings.test.ts +131 -0
  54. package/src/__tests__/translateBracketsToPG.test.ts +20 -0
  55. package/src/auth/magicLink/MagicLinkService.ts +55 -36
  56. package/src/auth/magicLink/magicLinkCore.ts +19 -56
  57. package/src/context.ts +11 -24
  58. package/src/index.ts +40 -45
  59. package/src/postgresqlCompat.ts +21 -0
  60. package/src/postgresqlPoolSettings.ts +213 -0
  61. package/src/resolvers/AdhocQueryResolver.ts +64 -194
  62. package/src/resolvers/RealtimeClientSessionResolver.ts +93 -35
  63. package/src/resolvers/RunAIAgentResolver.ts +4 -1
  64. package/src/resolvers/adhocTimeout.ts +12 -0
  65. package/src/services/TaskGraphActionRunner.ts +16 -15
  66. package/dist/resolvers/adhoc-query-helpers.d.ts +0 -27
  67. package/dist/resolvers/adhoc-query-helpers.d.ts.map +0 -1
  68. package/dist/resolvers/adhoc-query-helpers.js +0 -42
  69. package/dist/resolvers/adhoc-query-helpers.js.map +0 -1
  70. package/src/__tests__/adhoc-query-helpers.test.ts +0 -50
  71. package/src/resolvers/adhoc-query-helpers.ts +0 -50
@@ -75,25 +75,26 @@ export class TaskGraphActionRunner implements TaskActionRunner {
75
75
  }
76
76
 
77
77
  /**
78
- * Rebuilds the action's parameters from the task's stored payload.
78
+ * Rebuilds the action's parameters from the task's input, one parameter per key.
79
79
  *
80
- * **The values here have been through redaction**, because `Task.InputPayload` is persistent,
81
- * user-visible storage and nothing writes a raw `ActionParam[]` there. A parameter the binding
82
- * marked as not-logged therefore arrives absent rather than secret — the action sees a missing
83
- * value, which is the honest consequence of choosing not to persist it, and the reason durable
84
- * dispatch is opt-in per binding rather than the default.
80
+ * For a **durable entity-action** graph the input was written by `RedactParamsToRecord`
81
+ * (`@memberjunction/actions-base`) at deferral time, so its values have been through redaction:
82
+ * a parameter the binding marked as not-logged arrives absent rather than secret — the action
83
+ * sees a missing value, which is the honest consequence of choosing not to persist it, and the
84
+ * reason durable dispatch is opt-in per binding rather than the default. Every other graph's
85
+ * input is whatever its spec authored. This method re-applies no redaction rule in either case.
85
86
  *
86
- * Dependency outputs are merged underneath the task's own input so a node's explicit parameters
87
- * always win over an upstream node that happened to emit the same key.
87
+ * `InputPayload` already carries the dependency outputs: the dispatcher merges them underneath
88
+ * the task's own input (`mergedPayload`) before calling this runner, so a node's explicit
89
+ * parameters win and a step with an input mapping gets exactly the parameters it declared.
90
+ * `DependencyOutputs` is keyed by upstream task ID, not by parameter name, so it is deliberately
91
+ * not read here — spreading it would hand the action one extra parameter per dependency, named
92
+ * by a GUID and holding that task's whole output.
88
93
  */
89
94
  private buildParams(params: TaskActionRunParams): ActionParam[] {
90
- const merged: Record<string, unknown> = {};
91
- for (const [name, value] of params.DependencyOutputs) {
92
- merged[name] = value;
95
+ if (!params.InputPayload || typeof params.InputPayload !== 'object') {
96
+ return [];
93
97
  }
94
- if (params.InputPayload && typeof params.InputPayload === 'object') {
95
- Object.assign(merged, params.InputPayload as Record<string, unknown>);
96
- }
97
- return Object.entries(merged).map(([Name, Value]) => ({ Name, Value, Type: 'Input' }));
98
+ return Object.entries(params.InputPayload as Record<string, unknown>).map(([Name, Value]) => ({ Name, Value, Type: 'Input' }));
98
99
  }
99
100
  }
@@ -1,27 +0,0 @@
1
- /**
2
- * Pure, dependency-free helpers for {@link AdhocQueryResolver}. Kept in their own
3
- * module (no type-graphql / mssql imports) so the total-row-count boundary logic is
4
- * unit-testable without standing up the GraphQL resolver or a database.
5
- */
6
- /**
7
- * Determines the exact total row count from the page alone, when it can be known
8
- * without a separate `COUNT(*)`:
9
- *
10
- * - **Not paging** (`maxRows == null`): the query ran uncapped, so every row came
11
- * back — the total is just the number returned.
12
- * - **Short page** (`pageLength < maxRows`): a page shorter than the page size means
13
- * there are no rows beyond it, so the total is `startRow + pageLength` exactly.
14
- * - **Full page** (`pageLength >= maxRows`): more rows may exist — returns `null` to
15
- * signal that a `COUNT(*)` is required to know the true total.
16
- */
17
- export declare function exactTotalFromPage(startRow: number, pageLength: number, maxRows: number | null): number | null;
18
- /**
19
- * Reads the total row count from a `COUNT(*)` recordset (`[{ TotalRowCount }]`),
20
- * falling back to `fallback` when the count is absent, non-numeric, or negative — so
21
- * an unexpected count shape never yields a misleading total. `fallback` should be a
22
- * safe lower bound (e.g. `startRow + rowsReturned`).
23
- */
24
- export declare function resolveAdhocTotalRowCount(countRows: ReadonlyArray<{
25
- TotalRowCount?: unknown;
26
- }> | null | undefined, fallback: number): number;
27
- //# sourceMappingURL=adhoc-query-helpers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adhoc-query-helpers.d.ts","sourceRoot":"","sources":["../../src/resolvers/adhoc-query-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GAAG,IAAI,GACvB,MAAM,GAAG,IAAI,CAQf;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACrC,SAAS,EAAE,aAAa,CAAC;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EACxE,QAAQ,EAAE,MAAM,GACjB,MAAM,CASR"}
@@ -1,42 +0,0 @@
1
- /**
2
- * Pure, dependency-free helpers for {@link AdhocQueryResolver}. Kept in their own
3
- * module (no type-graphql / mssql imports) so the total-row-count boundary logic is
4
- * unit-testable without standing up the GraphQL resolver or a database.
5
- */
6
- /**
7
- * Determines the exact total row count from the page alone, when it can be known
8
- * without a separate `COUNT(*)`:
9
- *
10
- * - **Not paging** (`maxRows == null`): the query ran uncapped, so every row came
11
- * back — the total is just the number returned.
12
- * - **Short page** (`pageLength < maxRows`): a page shorter than the page size means
13
- * there are no rows beyond it, so the total is `startRow + pageLength` exactly.
14
- * - **Full page** (`pageLength >= maxRows`): more rows may exist — returns `null` to
15
- * signal that a `COUNT(*)` is required to know the true total.
16
- */
17
- export function exactTotalFromPage(startRow, pageLength, maxRows) {
18
- if (maxRows == null) {
19
- return pageLength;
20
- }
21
- if (pageLength < maxRows) {
22
- return startRow + pageLength;
23
- }
24
- return null;
25
- }
26
- /**
27
- * Reads the total row count from a `COUNT(*)` recordset (`[{ TotalRowCount }]`),
28
- * falling back to `fallback` when the count is absent, non-numeric, or negative — so
29
- * an unexpected count shape never yields a misleading total. `fallback` should be a
30
- * safe lower bound (e.g. `startRow + rowsReturned`).
31
- */
32
- export function resolveAdhocTotalRowCount(countRows, fallback) {
33
- const raw = countRows?.[0]?.TotalRowCount;
34
- if (raw != null) {
35
- const n = Number(raw);
36
- if (Number.isFinite(n) && n >= 0) {
37
- return Math.floor(n);
38
- }
39
- }
40
- return fallback;
41
- }
42
- //# sourceMappingURL=adhoc-query-helpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"adhoc-query-helpers.js","sourceRoot":"","sources":["../../src/resolvers/adhoc-query-helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAC9B,QAAgB,EAChB,UAAkB,EAClB,OAAsB;IAEtB,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,UAAU,CAAC;IACtB,CAAC;IACD,IAAI,UAAU,GAAG,OAAO,EAAE,CAAC;QACvB,OAAO,QAAQ,GAAG,UAAU,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACrC,SAAwE,EACxE,QAAgB;IAEhB,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC;IAC1C,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QACd,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;IACL,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC"}
@@ -1,50 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { exactTotalFromPage, resolveAdhocTotalRowCount } from '../resolvers/adhoc-query-helpers';
3
-
4
- describe('exactTotalFromPage', () => {
5
- it('returns the row count when not paging (maxRows null) — the query was uncapped', () => {
6
- expect(exactTotalFromPage(0, 47, null)).toBe(47);
7
- expect(exactTotalFromPage(0, 0, null)).toBe(0);
8
- });
9
-
10
- it('returns startRow + pageLength for a SHORT page (fewer rows than the page size)', () => {
11
- expect(exactTotalFromPage(0, 47, 100)).toBe(47); // page 1, short → exact total
12
- expect(exactTotalFromPage(200, 30, 100)).toBe(230); // page 3, short last page
13
- expect(exactTotalFromPage(100, 0, 100)).toBe(100); // empty page past the end
14
- });
15
-
16
- it('returns null for a FULL page — a COUNT is required because more rows may exist', () => {
17
- expect(exactTotalFromPage(0, 100, 100)).toBeNull();
18
- expect(exactTotalFromPage(500, 100, 100)).toBeNull();
19
- });
20
-
21
- it('treats an over-full page defensively as "needs count" (should not occur with OFFSET/FETCH)', () => {
22
- expect(exactTotalFromPage(0, 150, 100)).toBeNull();
23
- });
24
- });
25
-
26
- describe('resolveAdhocTotalRowCount', () => {
27
- it('reads TotalRowCount from the count recordset', () => {
28
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 2087 }], 100)).toBe(2087);
29
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 0 }], 100)).toBe(0);
30
- });
31
-
32
- it('floors a fractional/stringified count', () => {
33
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: 42.9 }], 0)).toBe(42);
34
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: '2087' as unknown as number }], 0)).toBe(2087);
35
- });
36
-
37
- it('falls back when the count is absent, empty, null, or malformed', () => {
38
- expect(resolveAdhocTotalRowCount(null, 100)).toBe(100);
39
- expect(resolveAdhocTotalRowCount(undefined, 100)).toBe(100);
40
- expect(resolveAdhocTotalRowCount([], 100)).toBe(100);
41
- expect(resolveAdhocTotalRowCount([{}], 100)).toBe(100);
42
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: null }], 100)).toBe(100);
43
- });
44
-
45
- it('falls back on non-finite or negative counts (never reports a misleading total)', () => {
46
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: Number.NaN }], 100)).toBe(100);
47
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: -5 }], 100)).toBe(100);
48
- expect(resolveAdhocTotalRowCount([{ TotalRowCount: Infinity }], 100)).toBe(100);
49
- });
50
- });
@@ -1,50 +0,0 @@
1
- /**
2
- * Pure, dependency-free helpers for {@link AdhocQueryResolver}. Kept in their own
3
- * module (no type-graphql / mssql imports) so the total-row-count boundary logic is
4
- * unit-testable without standing up the GraphQL resolver or a database.
5
- */
6
-
7
- /**
8
- * Determines the exact total row count from the page alone, when it can be known
9
- * without a separate `COUNT(*)`:
10
- *
11
- * - **Not paging** (`maxRows == null`): the query ran uncapped, so every row came
12
- * back — the total is just the number returned.
13
- * - **Short page** (`pageLength < maxRows`): a page shorter than the page size means
14
- * there are no rows beyond it, so the total is `startRow + pageLength` exactly.
15
- * - **Full page** (`pageLength >= maxRows`): more rows may exist — returns `null` to
16
- * signal that a `COUNT(*)` is required to know the true total.
17
- */
18
- export function exactTotalFromPage(
19
- startRow: number,
20
- pageLength: number,
21
- maxRows: number | null,
22
- ): number | null {
23
- if (maxRows == null) {
24
- return pageLength;
25
- }
26
- if (pageLength < maxRows) {
27
- return startRow + pageLength;
28
- }
29
- return null;
30
- }
31
-
32
- /**
33
- * Reads the total row count from a `COUNT(*)` recordset (`[{ TotalRowCount }]`),
34
- * falling back to `fallback` when the count is absent, non-numeric, or negative — so
35
- * an unexpected count shape never yields a misleading total. `fallback` should be a
36
- * safe lower bound (e.g. `startRow + rowsReturned`).
37
- */
38
- export function resolveAdhocTotalRowCount(
39
- countRows: ReadonlyArray<{ TotalRowCount?: unknown }> | null | undefined,
40
- fallback: number,
41
- ): number {
42
- const raw = countRows?.[0]?.TotalRowCount;
43
- if (raw != null) {
44
- const n = Number(raw);
45
- if (Number.isFinite(n) && n >= 0) {
46
- return Math.floor(n);
47
- }
48
- }
49
- return fallback;
50
- }