@memberjunction/metadata-sync 6.2.0-edge.4 → 6.2.0-edge.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 (122) hide show
  1. package/README.md +115 -51
  2. package/dist/config.d.ts +5 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js.map +1 -1
  5. package/dist/index.d.ts +3 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/lib/RecordProcessor.d.ts +98 -0
  10. package/dist/lib/RecordProcessor.d.ts.map +1 -1
  11. package/dist/lib/RecordProcessor.js +424 -22
  12. package/dist/lib/RecordProcessor.js.map +1 -1
  13. package/dist/lib/RelatedEntityHandler.d.ts +4 -1
  14. package/dist/lib/RelatedEntityHandler.d.ts.map +1 -1
  15. package/dist/lib/RelatedEntityHandler.js +49 -11
  16. package/dist/lib/RelatedEntityHandler.js.map +1 -1
  17. package/dist/lib/created-record-key.d.ts +34 -0
  18. package/dist/lib/created-record-key.d.ts.map +1 -0
  19. package/dist/lib/created-record-key.js +46 -0
  20. package/dist/lib/created-record-key.js.map +1 -0
  21. package/dist/lib/deletion-auditor.d.ts.map +1 -1
  22. package/dist/lib/deletion-auditor.js +33 -2
  23. package/dist/lib/deletion-auditor.js.map +1 -1
  24. package/dist/lib/entity-field-names.d.ts +11 -0
  25. package/dist/lib/entity-field-names.d.ts.map +1 -0
  26. package/dist/lib/entity-field-names.js +15 -0
  27. package/dist/lib/entity-field-names.js.map +1 -0
  28. package/dist/lib/env-derived-fields.d.ts +23 -0
  29. package/dist/lib/env-derived-fields.d.ts.map +1 -0
  30. package/dist/lib/env-derived-fields.js +53 -0
  31. package/dist/lib/env-derived-fields.js.map +1 -0
  32. package/dist/lib/env-display.d.ts +54 -0
  33. package/dist/lib/env-display.d.ts.map +1 -0
  34. package/dist/lib/env-display.js +156 -0
  35. package/dist/lib/env-display.js.map +1 -0
  36. package/dist/lib/env-reference.d.ts +104 -0
  37. package/dist/lib/env-reference.d.ts.map +1 -0
  38. package/dist/lib/env-reference.js +241 -0
  39. package/dist/lib/env-reference.js.map +1 -0
  40. package/dist/lib/env-sql-redactor.d.ts +74 -0
  41. package/dist/lib/env-sql-redactor.d.ts.map +1 -0
  42. package/dist/lib/env-sql-redactor.js +297 -0
  43. package/dist/lib/env-sql-redactor.js.map +1 -0
  44. package/dist/lib/existing-record-index.d.ts +70 -0
  45. package/dist/lib/existing-record-index.d.ts.map +1 -0
  46. package/dist/lib/existing-record-index.js +158 -0
  47. package/dist/lib/existing-record-index.js.map +1 -0
  48. package/dist/lib/ignore-directories.d.ts +10 -0
  49. package/dist/lib/ignore-directories.d.ts.map +1 -0
  50. package/dist/lib/ignore-directories.js +12 -0
  51. package/dist/lib/ignore-directories.js.map +1 -0
  52. package/dist/lib/json-record-lines.d.ts +17 -0
  53. package/dist/lib/json-record-lines.d.ts.map +1 -0
  54. package/dist/lib/json-record-lines.js +170 -0
  55. package/dist/lib/json-record-lines.js.map +1 -0
  56. package/dist/lib/json-subproperty-externalization.d.ts.map +1 -1
  57. package/dist/lib/json-subproperty-externalization.js +3 -1
  58. package/dist/lib/json-subproperty-externalization.js.map +1 -1
  59. package/dist/lib/lookup-reference.d.ts +38 -0
  60. package/dist/lib/lookup-reference.d.ts.map +1 -0
  61. package/dist/lib/lookup-reference.js +62 -0
  62. package/dist/lib/lookup-reference.js.map +1 -0
  63. package/dist/lib/provider-utils.d.ts.map +1 -1
  64. package/dist/lib/provider-utils.js +2 -4
  65. package/dist/lib/provider-utils.js.map +1 -1
  66. package/dist/lib/pull-option-overrides.d.ts +24 -0
  67. package/dist/lib/pull-option-overrides.d.ts.map +1 -0
  68. package/dist/lib/pull-option-overrides.js +39 -0
  69. package/dist/lib/pull-option-overrides.js.map +1 -0
  70. package/dist/lib/push-directories.d.ts +42 -0
  71. package/dist/lib/push-directories.d.ts.map +1 -0
  72. package/dist/lib/push-directories.js +71 -0
  73. package/dist/lib/push-directories.js.map +1 -0
  74. package/dist/lib/push-when.d.ts +38 -0
  75. package/dist/lib/push-when.d.ts.map +1 -0
  76. package/dist/lib/push-when.js +84 -0
  77. package/dist/lib/push-when.js.map +1 -0
  78. package/dist/lib/record-dependency-analyzer.d.ts +2 -0
  79. package/dist/lib/record-dependency-analyzer.d.ts.map +1 -1
  80. package/dist/lib/record-dependency-analyzer.js.map +1 -1
  81. package/dist/lib/record-file-glob.d.ts +11 -0
  82. package/dist/lib/record-file-glob.d.ts.map +1 -0
  83. package/dist/lib/record-file-glob.js +10 -0
  84. package/dist/lib/record-file-glob.js.map +1 -0
  85. package/dist/lib/reference-parser.d.ts +3 -2
  86. package/dist/lib/reference-parser.d.ts.map +1 -1
  87. package/dist/lib/reference-parser.js +27 -27
  88. package/dist/lib/reference-parser.js.map +1 -1
  89. package/dist/lib/sync-engine.d.ts +46 -4
  90. package/dist/lib/sync-engine.d.ts.map +1 -1
  91. package/dist/lib/sync-engine.js +215 -59
  92. package/dist/lib/sync-engine.js.map +1 -1
  93. package/dist/lib/sync-state-manager.d.ts +7 -3
  94. package/dist/lib/sync-state-manager.d.ts.map +1 -1
  95. package/dist/lib/sync-state-manager.js +19 -4
  96. package/dist/lib/sync-state-manager.js.map +1 -1
  97. package/dist/lib/watch-file-filter.d.ts +31 -0
  98. package/dist/lib/watch-file-filter.d.ts.map +1 -0
  99. package/dist/lib/watch-file-filter.js +64 -0
  100. package/dist/lib/watch-file-filter.js.map +1 -0
  101. package/dist/plugins/index.d.ts.map +1 -1
  102. package/dist/plugins/index.js +44 -14
  103. package/dist/plugins/index.js.map +1 -1
  104. package/dist/services/PullService.d.ts +41 -1
  105. package/dist/services/PullService.d.ts.map +1 -1
  106. package/dist/services/PullService.js +261 -101
  107. package/dist/services/PullService.js.map +1 -1
  108. package/dist/services/PushService.d.ts +59 -0
  109. package/dist/services/PushService.d.ts.map +1 -1
  110. package/dist/services/PushService.js +435 -173
  111. package/dist/services/PushService.js.map +1 -1
  112. package/dist/services/ValidationService.d.ts +43 -8
  113. package/dist/services/ValidationService.d.ts.map +1 -1
  114. package/dist/services/ValidationService.js +338 -127
  115. package/dist/services/ValidationService.js.map +1 -1
  116. package/dist/services/WatchService.d.ts +26 -0
  117. package/dist/services/WatchService.d.ts.map +1 -1
  118. package/dist/services/WatchService.js +210 -75
  119. package/dist/services/WatchService.js.map +1 -1
  120. package/dist/types/validation.d.ts +6 -0
  121. package/dist/types/validation.d.ts.map +1 -1
  122. package/package.json +17 -16
@@ -0,0 +1,241 @@
1
+ /**
2
+ * @fileoverview Parsing and checks for `@env:` references in metadata files.
3
+ * @module env-reference
4
+ */
5
+ import { METADATA_KEYWORDS } from '../constants/metadata-keywords.js';
6
+ import { MIN_MASKED_VALUE_LENGTH } from './env-display.js';
7
+ /** Matches `@env:VARIABLE`, with an optional `?optional` modifier. */
8
+ export const ENV_REFERENCE_PATTERN = /^@env:([^?]+)(\?optional)?$/;
9
+ /**
10
+ * Parses an `@env:` reference.
11
+ * @returns The parsed reference, or null when the value is not a valid `@env:` reference
12
+ */
13
+ export function ParseEnvReference(value) {
14
+ if (typeof value !== 'string' || !value.startsWith(METADATA_KEYWORDS.ENV)) {
15
+ return null;
16
+ }
17
+ const match = value.match(ENV_REFERENCE_PATTERN);
18
+ if (!match) {
19
+ return null;
20
+ }
21
+ return { VariableName: match[1], Optional: match[2] !== undefined };
22
+ }
23
+ /** True when an environment value is `true` or `1`, ignoring case and surrounding spaces. */
24
+ export function IsEnvFlagTrue(value) {
25
+ const normalized = value?.trim().toLowerCase();
26
+ return normalized === 'true' || normalized === '1';
27
+ }
28
+ /** Thrown when an `@env:VAR?optional` reference names a variable that is not set. */
29
+ export class OptionalEnvMissingError extends Error {
30
+ constructor(variableName) {
31
+ super(`Optional environment variable not set: ${variableName}`);
32
+ this.name = 'OptionalEnvMissingError';
33
+ this.VariableName = variableName;
34
+ }
35
+ }
36
+ /** Thrown when a non-optional `@env:` reference names a variable that is not set. Holds names only. */
37
+ export class EnvVariableNotSetError extends Error {
38
+ constructor(variableName, field, entityName) {
39
+ super(`Environment variable not found: ${variableName}`);
40
+ this.name = 'EnvVariableNotSetError';
41
+ this.VariableName = variableName;
42
+ this.Field = field;
43
+ this.EntityName = entityName;
44
+ }
45
+ /** The same error for the given field (and entity, when given). */
46
+ ForField(field, entityName) {
47
+ return new EnvVariableNotSetError(this.VariableName, field, entityName ?? this.EntityName);
48
+ }
49
+ /** The same error inside a composition path, such as `collections.Lines[0]`; an entity already named is kept. */
50
+ Within(compositionPath, entityName) {
51
+ const field = this.Field ? `${compositionPath}.${this.Field}` : compositionPath;
52
+ return new EnvVariableNotSetError(this.VariableName, field, this.EntityName ?? entityName);
53
+ }
54
+ }
55
+ /** The warning push gives when it leaves out a field whose optional variable is not set. */
56
+ export function OptionalEnvSkipMessage(entityName, fieldName, variableName) {
57
+ return `${entityName}.${fieldName} was not pushed: optional variable ${variableName} is not set`;
58
+ }
59
+ /**
60
+ * Decides whether pull keeps an existing `@env:` reference instead of the database value.
61
+ * The result never contains the variable's value.
62
+ * @returns The reference to keep, or null when the existing value is not a valid `@env:` reference
63
+ */
64
+ export function KeepEnvReference(existingValue, databaseValue, env = process.env) {
65
+ if (typeof existingValue !== 'string') {
66
+ return null;
67
+ }
68
+ const reference = ParseEnvReference(existingValue);
69
+ if (!reference) {
70
+ return null;
71
+ }
72
+ const envValue = env[reference.VariableName];
73
+ let check = 'Unset';
74
+ if (envValue !== undefined) {
75
+ check = comparable(envValue) === comparable(databaseValue) ? 'Match' : 'Drift';
76
+ }
77
+ return { Reference: existingValue, VariableName: reference.VariableName, Check: check };
78
+ }
79
+ function comparable(value) {
80
+ return value === null || value === undefined ? null : String(value).trim();
81
+ }
82
+ /** True for a plain object or an array. */
83
+ export function IsJsonContainer(value) {
84
+ if (Array.isArray(value)) {
85
+ return true;
86
+ }
87
+ return value !== null && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype;
88
+ }
89
+ /** True when an object or array holds a valid `@env:` string at any depth. */
90
+ export function HasNestedEnvReference(value) {
91
+ return IsJsonContainer(value) && containsEnvLeaf(value);
92
+ }
93
+ function containsEnvLeaf(value) {
94
+ if (typeof value === 'string') {
95
+ return ParseEnvReference(value) !== null;
96
+ }
97
+ if (Array.isArray(value)) {
98
+ return value.some(containsEnvLeaf);
99
+ }
100
+ if (IsJsonContainer(value)) {
101
+ return Object.values(value).some(containsEnvLeaf);
102
+ }
103
+ return false;
104
+ }
105
+ /**
106
+ * Keeps `@env:` references inside a JSON field. The database value decides the structure and every
107
+ * other leaf. A reference is put back only at a path that also exists in the database value; arrays
108
+ * match by index. When the merged JSON would still hold the value (6 or more characters) of a variable
109
+ * that the existing value references, the existing value is kept as is.
110
+ * @returns null when the existing value is not an object or array, or holds no valid `@env:` string
111
+ */
112
+ export function KeepNestedEnvReferences(existingValue, databaseValue, env = process.env) {
113
+ if (!IsJsonContainer(existingValue) || !containsEnvLeaf(existingValue)) {
114
+ return null;
115
+ }
116
+ const parsed = parseJsonContainer(databaseValue);
117
+ if (parsed === null) {
118
+ return { Value: structuredClone(existingValue), Kept: [], KeptFileValue: true, LeftValueVariables: [] };
119
+ }
120
+ const value = structuredClone(parsed);
121
+ const kept = [];
122
+ putBackReferences(existingValue, value, '', kept, env);
123
+ const leftValueVariables = findLeftValueVariables(existingValue, value, env);
124
+ if (leftValueVariables.length > 0) {
125
+ return {
126
+ Value: structuredClone(existingValue),
127
+ Kept: [],
128
+ KeptFileValue: true,
129
+ LeftValueVariables: leftValueVariables,
130
+ };
131
+ }
132
+ return { Value: value, Kept: kept, KeptFileValue: false, LeftValueVariables: [] };
133
+ }
134
+ /** Sorted names of the referenced variables whose value is still in the merged JSON. */
135
+ function findLeftValueVariables(existing, merged, env) {
136
+ const mergedText = JSON.stringify(merged);
137
+ return [...collectEnvVariableNames(existing, new Set())]
138
+ .filter((name) => holdsEnvValue(mergedText, env[name]))
139
+ .sort();
140
+ }
141
+ function collectEnvVariableNames(value, names) {
142
+ if (typeof value === 'string') {
143
+ const reference = ParseEnvReference(value);
144
+ if (reference) {
145
+ names.add(reference.VariableName);
146
+ }
147
+ }
148
+ else if (Array.isArray(value)) {
149
+ value.forEach((item) => collectEnvVariableNames(item, names));
150
+ }
151
+ else if (IsJsonContainer(value)) {
152
+ Object.values(value).forEach((item) => collectEnvVariableNames(item, names));
153
+ }
154
+ return names;
155
+ }
156
+ /** Most JSON-escape levels the left-over check looks for (a JSON string inside a JSON string, and so on). */
157
+ const MAX_ESCAPE_LEVELS = 4;
158
+ /** True when the text holds the trimmed value, plain or JSON-escaped one or more times. */
159
+ function holdsEnvValue(text, envValue) {
160
+ const trimmed = envValue?.trim();
161
+ if (!trimmed || trimmed.length < MIN_MASKED_VALUE_LENGTH) {
162
+ return false;
163
+ }
164
+ let form = trimmed;
165
+ for (let level = 0; level <= MAX_ESCAPE_LEVELS; level++) {
166
+ if (text.includes(form)) {
167
+ return true;
168
+ }
169
+ const escaped = JSON.stringify(form).slice(1, -1);
170
+ if (escaped === form) {
171
+ return false;
172
+ }
173
+ form = escaped;
174
+ }
175
+ return false;
176
+ }
177
+ function parseJsonContainer(value) {
178
+ if (IsJsonContainer(value)) {
179
+ return value;
180
+ }
181
+ if (typeof value !== 'string') {
182
+ return null;
183
+ }
184
+ try {
185
+ const parsed = JSON.parse(value);
186
+ return IsJsonContainer(parsed) ? parsed : null;
187
+ }
188
+ catch {
189
+ return null;
190
+ }
191
+ }
192
+ function putBackReferences(existing, target, path, kept, env) {
193
+ if (Array.isArray(existing)) {
194
+ if (!Array.isArray(target)) {
195
+ return;
196
+ }
197
+ const count = Math.min(existing.length, target.length);
198
+ for (let i = 0; i < count; i++) {
199
+ const reference = keepLeaf(existing[i], target[i], `${path}[${i}]`, kept, env);
200
+ if (reference !== null) {
201
+ target[i] = reference;
202
+ }
203
+ }
204
+ return;
205
+ }
206
+ if (Array.isArray(target)) {
207
+ return;
208
+ }
209
+ for (const [key, item] of Object.entries(existing)) {
210
+ if (!Object.prototype.hasOwnProperty.call(target, key)) {
211
+ continue;
212
+ }
213
+ const reference = keepLeaf(item, target[key], appendKey(path, key), kept, env);
214
+ if (reference !== null) {
215
+ target[key] = reference;
216
+ }
217
+ }
218
+ }
219
+ /** The reference to put at this path, or null. Walks into nested objects and arrays. */
220
+ function keepLeaf(existingItem, targetItem, path, kept, env) {
221
+ if (typeof existingItem === 'string') {
222
+ const comparable = IsJsonContainer(targetItem) ? JSON.stringify(targetItem) : targetItem;
223
+ const result = KeepEnvReference(existingItem, comparable, env);
224
+ if (!result) {
225
+ return null;
226
+ }
227
+ kept.push({ Path: path, Reference: result.Reference, VariableName: result.VariableName, Check: result.Check });
228
+ return result.Reference;
229
+ }
230
+ if (IsJsonContainer(existingItem) && IsJsonContainer(targetItem)) {
231
+ putBackReferences(existingItem, targetItem, path, kept, env);
232
+ }
233
+ return null;
234
+ }
235
+ function appendKey(path, key) {
236
+ if (/^[A-Za-z_$][\w$]*$/.test(key)) {
237
+ return path ? `${path}.${key}` : key;
238
+ }
239
+ return `${path}[${JSON.stringify(key)}]`;
240
+ }
241
+ //# sourceMappingURL=env-reference.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-reference.js","sourceRoot":"","sources":["../../src/lib/env-reference.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ import type { BaseEntity } from '@memberjunction/core';
2
+ import type { SyncEngine } from './sync-engine.js';
3
+ /** Replaces registered SET lines and gives names-only warnings for one push. */
4
+ export declare class EnvSqlRedactor {
5
+ private readonly variables;
6
+ private readonly env;
7
+ /** Registrations by save-call hash; `ANY_SUFFIX` holds those registered without a hash. */
8
+ private readonly fieldsByHash;
9
+ private readonly primaryKeys;
10
+ private transformFailed;
11
+ /** `variables` is read when `Warnings` runs, so a set that grows during the run can be passed. */
12
+ constructor(variables: ReadonlySet<string>, env?: NodeJS.ProcessEnv);
13
+ /**
14
+ * Registers a field whose value is in a save statement. With `saveCallHash` (the 12-hex
15
+ * `GenericDatabaseProvider.SaveCallVariableHash` of the record), only the SET line of that save
16
+ * call is replaced. Without it, the SET line of any save call with the same code name and literal
17
+ * is replaced. A null or undefined value is not registered, because no SET line is written for it.
18
+ * A registration stays for the whole push.
19
+ */
20
+ Register(entityName: string, fieldName: string, codeName: string, value: unknown, variableNames: ReadonlySet<string>, saveCallHash?: string): void;
21
+ /** Registers an env-sourced primary key field. Its value stays in the log, so it gives a warning. */
22
+ RegisterPrimaryKey(entityName: string, fieldName: string, variableNames: ReadonlySet<string>): void;
23
+ /**
24
+ * Registers the env-sourced fields that the save statement of `entity` holds. Each field is
25
+ * registered at the IS-A level whose table holds it, with that level's save-call hash. A level's
26
+ * statement holds every field when `fullRow` (a create or alwaysPush) or when its entity has no
27
+ * generated update procedure (the full save SQL is logged); else only the changed fields.
28
+ * Key fields give a warning. `envFields` keys are matched without regard to case. Call it right
29
+ * before the save, so the hash uses the key values the provider hashes.
30
+ */
31
+ RegisterEntityFields(entity: BaseEntity, envFields: ReadonlyMap<string, ReadonlySet<string>> | undefined, fullRow: boolean): void;
32
+ /**
33
+ * The `SqlLoggingOptions.TransformStatement` function. It can run many times on the same text and
34
+ * on text that is never written. It only marks fields as matched and never throws; on an
35
+ * unexpected error it returns a comment in place of the statement.
36
+ */
37
+ readonly Transform: (sql: string) => string;
38
+ /** Names-only warnings for the SQL log at `sqlLogPath`. Reads the written log; never throws. */
39
+ Warnings(sqlLogPath: string): string[];
40
+ private fieldsForHash;
41
+ /** The registrations that can match the statement: those of each suffix in it, and those without a hash. */
42
+ private candidateFields;
43
+ private replaceSetLines;
44
+ private unmatchedFieldWarnings;
45
+ private primaryKeyWarnings;
46
+ /**
47
+ * For each resolved variable other than a key variable: a warning when its value is in the
48
+ * written log, or when it is not set now and so cannot be checked.
49
+ */
50
+ private variableValueWarnings;
51
+ }
52
+ /** The sync engine members an `EnvSqlLog` uses. */
53
+ type EnvSqlLogEngine = Pick<SyncEngine, 'BeforeLookupCreateSave' | 'ResolvedEnvVariables'>;
54
+ /**
55
+ * The redactor of one open SQL log, with the `SyncEngine.BeforeLookupCreateSave` hook that registers
56
+ * each record a `?create` lookup creates (with the full row, because a create writes every field).
57
+ */
58
+ export declare class EnvSqlLog {
59
+ readonly Redactor: EnvSqlRedactor;
60
+ private readonly engine;
61
+ private readonly hook;
62
+ /** Creates the redactor over the engine's resolved variables and sets the engine's hook. */
63
+ constructor(engine: EnvSqlLogEngine);
64
+ /** Clears the engine's hook when it is still this log's hook. */
65
+ Close(): void;
66
+ }
67
+ /**
68
+ * Adds a field that was left out because its `?optional` variable is not set. The SQL log then
69
+ * leaves the field's SET line out by name, as for an env-sourced field: a full-row save would
70
+ * otherwise write the field's database value.
71
+ */
72
+ export declare function AddSkippedOptionalEnvField(envFields: Map<string, Set<string>> | undefined, fieldName: string, variableName: string): void;
73
+ export {};
74
+ //# sourceMappingURL=env-sql-redactor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-sql-redactor.d.ts","sourceRoot":"","sources":["../../src/lib/env-sql-redactor.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAqBhD,gFAAgF;AAChF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAsB;IAChD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoB;IACxC,2FAA2F;IAC3F,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiD;IAC9E,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyC;IACrE,OAAO,CAAC,eAAe,CAAS;IAEhC,kGAAkG;gBACtF,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,GAAG,GAAE,MAAM,CAAC,UAAwB;IAKhF;;;;;;OAMG;IACH,QAAQ,CACN,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI;IAoBP,qGAAqG;IACrG,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI;IAUnG;;;;;;;OAOG;IACH,oBAAoB,CAClB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAC/D,OAAO,EAAE,OAAO,GACf,IAAI;IAuBP;;;;OAIG;IACH,QAAQ,CAAC,SAAS,GAAI,KAAK,MAAM,KAAG,MAAM,CAOxC;IAEF,gGAAgG;IAChG,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAYtC,OAAO,CAAC,aAAa;IASrB,4GAA4G;IAC5G,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,sBAAsB;IAU9B,OAAO,CAAC,kBAAkB;IAM1B;;;OAGG;IACH,OAAO,CAAC,qBAAqB;CAiB9B;AAqFD,mDAAmD;AACnD,KAAK,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,wBAAwB,GAAG,sBAAsB,CAAC,CAAC;AAE3F;;;GAGG;AACH,qBAAa,SAAS;IACpB,SAAgB,QAAQ,EAAE,cAAc,CAAC;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoD;IAEzE,4FAA4F;gBAChF,MAAM,EAAE,eAAe;IAOnC,iEAAiE;IACjE,KAAK,IAAI,IAAI;CAKd;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAC/C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,IAAI,CAON"}
@@ -0,0 +1,297 @@
1
+ /**
2
+ * @fileoverview Leaves the values of env-sourced fields out of the push SQL log.
3
+ *
4
+ * SQL Server saves set each parameter with one line: `SET @<CodeName>_<12 hex>[_n] = <literal>`.
5
+ * For a registered field, that line is replaced with a comment. The variable is then NULL in the
6
+ * recorded statement, so a replayed update keeps the target's value. A primary key cannot be left
7
+ * out; it gives a warning. After the run, the written log is searched for the values of the
8
+ * resolved variables. All messages name variables, never values.
9
+ * @module env-sql-redactor
10
+ */
11
+ import fs from 'fs';
12
+ import { GenericDatabaseProvider } from '@memberjunction/generic-database-provider';
13
+ import { EnvDisplayMask } from './env-display.js';
14
+ /** Registrations made without a save-call hash, which match any 12-hex suffix. */
15
+ const ANY_SUFFIX = '';
16
+ /** The 12-hex save-call hash of a variable suffix in a statement (`_<hash>` or `_<hash>_<n>`). */
17
+ const SAVE_CALL_SUFFIX = /_([0-9a-fA-F]{12})(?![0-9a-fA-F])/g;
18
+ /** Replaces registered SET lines and gives names-only warnings for one push. */
19
+ export class EnvSqlRedactor {
20
+ /** `variables` is read when `Warnings` runs, so a set that grows during the run can be passed. */
21
+ constructor(variables, env = process.env) {
22
+ /** Registrations by save-call hash; `ANY_SUFFIX` holds those registered without a hash. */
23
+ this.fieldsByHash = new Map();
24
+ this.primaryKeys = new Map();
25
+ this.transformFailed = false;
26
+ /**
27
+ * The `SqlLoggingOptions.TransformStatement` function. It can run many times on the same text and
28
+ * on text that is never written. It only marks fields as matched and never throws; on an
29
+ * unexpected error it returns a comment in place of the statement.
30
+ */
31
+ this.Transform = (sql) => {
32
+ try {
33
+ return this.replaceSetLines(sql);
34
+ }
35
+ catch {
36
+ this.transformFailed = true;
37
+ return '-- Statement not logged: env values could not be left out';
38
+ }
39
+ };
40
+ this.variables = variables;
41
+ this.env = env;
42
+ }
43
+ /**
44
+ * Registers a field whose value is in a save statement. With `saveCallHash` (the 12-hex
45
+ * `GenericDatabaseProvider.SaveCallVariableHash` of the record), only the SET line of that save
46
+ * call is replaced. Without it, the SET line of any save call with the same code name and literal
47
+ * is replaced. A null or undefined value is not registered, because no SET line is written for it.
48
+ * A registration stays for the whole push.
49
+ */
50
+ Register(entityName, fieldName, codeName, value, variableNames, saveCallHash) {
51
+ const literals = sqlLiteralsOf(value);
52
+ if (literals.length === 0) {
53
+ return;
54
+ }
55
+ const hash = saveCallHash?.toLowerCase() ?? ANY_SUFFIX;
56
+ const fields = this.fieldsForHash(hash);
57
+ const key = [entityName, fieldName, codeName, ...literals].join('\u0000');
58
+ if (fields.has(key)) {
59
+ return;
60
+ }
61
+ fields.set(key, {
62
+ EntityName: entityName,
63
+ FieldName: fieldName,
64
+ Sources: sourcesOf(variableNames),
65
+ Pattern: setLinePattern(codeName, hash, literals),
66
+ Matched: false,
67
+ });
68
+ }
69
+ /** Registers an env-sourced primary key field. Its value stays in the log, so it gives a warning. */
70
+ RegisterPrimaryKey(entityName, fieldName, variableNames) {
71
+ const field = `${entityName}.${fieldName}`;
72
+ const existing = this.primaryKeys.get(field);
73
+ if (existing) {
74
+ variableNames.forEach((name) => existing.Variables.add(name));
75
+ }
76
+ else {
77
+ this.primaryKeys.set(field, { Field: field, Variables: new Set(variableNames) });
78
+ }
79
+ }
80
+ /**
81
+ * Registers the env-sourced fields that the save statement of `entity` holds. Each field is
82
+ * registered at the IS-A level whose table holds it, with that level's save-call hash. A level's
83
+ * statement holds every field when `fullRow` (a create or alwaysPush) or when its entity has no
84
+ * generated update procedure (the full save SQL is logged); else only the changed fields.
85
+ * Key fields give a warning. `envFields` keys are matched without regard to case. Call it right
86
+ * before the save, so the hash uses the key values the provider hashes.
87
+ */
88
+ RegisterEntityFields(entity, envFields, fullRow) {
89
+ if (!envFields || envFields.size === 0) {
90
+ return;
91
+ }
92
+ const keyNames = new Set(entity.EntityInfo.PrimaryKeys.map((pk) => pk.Name));
93
+ for (const [key, variables] of envFields) {
94
+ const fieldName = entity.GetFieldByName(key)?.Name ?? key;
95
+ if (keyNames.has(fieldName)) {
96
+ this.RegisterPrimaryKey(entity.EntityInfo.Name, fieldName, variables);
97
+ continue;
98
+ }
99
+ const level = owningLevel(entity, fieldName);
100
+ const field = level.GetFieldByName(fieldName);
101
+ const levelInfo = level.EntityInfo;
102
+ const holdsField = fullRow || !levelInfo.spUpdateGenerated || fieldName in level.GetChangesSinceLastSave();
103
+ if (field && holdsField) {
104
+ const keyValues = level.PrimaryKey?.KeyValuePairs?.map((pair) => pair.Value) ?? [];
105
+ const saveCallHash = GenericDatabaseProvider.SaveCallVariableHash(levelInfo.SchemaName, levelInfo.BaseTable, keyValues);
106
+ this.Register(levelInfo.Name, fieldName, field.EntityFieldInfo.CodeName, level.Get(fieldName), variables, saveCallHash);
107
+ }
108
+ }
109
+ }
110
+ /** Names-only warnings for the SQL log at `sqlLogPath`. Reads the written log; never throws. */
111
+ Warnings(sqlLogPath) {
112
+ const failure = this.transformFailed
113
+ ? [`SQL log ${sqlLogPath}: env values could not be left out of a statement. Check the log before you share it.`]
114
+ : [];
115
+ return [
116
+ ...failure,
117
+ ...this.unmatchedFieldWarnings(sqlLogPath),
118
+ ...this.primaryKeyWarnings(sqlLogPath),
119
+ ...this.variableValueWarnings(sqlLogPath),
120
+ ];
121
+ }
122
+ fieldsForHash(hash) {
123
+ let fields = this.fieldsByHash.get(hash);
124
+ if (!fields) {
125
+ fields = new Map();
126
+ this.fieldsByHash.set(hash, fields);
127
+ }
128
+ return fields;
129
+ }
130
+ /** The registrations that can match the statement: those of each suffix in it, and those without a hash. */
131
+ candidateFields(sql) {
132
+ const hashes = new Set([ANY_SUFFIX]);
133
+ for (const match of sql.matchAll(SAVE_CALL_SUFFIX)) {
134
+ hashes.add(match[1].toLowerCase());
135
+ }
136
+ const candidates = [];
137
+ for (const hash of hashes) {
138
+ this.fieldsByHash.get(hash)?.forEach((field) => candidates.push(field));
139
+ }
140
+ return candidates;
141
+ }
142
+ replaceSetLines(sql) {
143
+ if (this.fieldsByHash.size === 0) {
144
+ return sql;
145
+ }
146
+ let result = sql;
147
+ for (const field of this.candidateFields(sql)) {
148
+ const comment = `-- ${field.EntityName}.${field.FieldName}: not recorded, value comes from ${field.Sources}`;
149
+ const next = result.replace(field.Pattern, (_line, indent) => `${indent}${comment}`);
150
+ if (next !== result) {
151
+ field.Matched = true;
152
+ result = next;
153
+ }
154
+ }
155
+ return result;
156
+ }
157
+ unmatchedFieldWarnings(sqlLogPath) {
158
+ return [...this.fieldsByHash.values()]
159
+ .flatMap((fields) => [...fields.values()])
160
+ .filter((field) => !field.Matched)
161
+ .map((field) => `SQL log ${sqlLogPath}: the line for ${field.EntityName}.${field.FieldName} (from ${field.Sources}) was not found, so its value may be in the log. Check the log before you share it.`);
162
+ }
163
+ primaryKeyWarnings(sqlLogPath) {
164
+ return [...this.primaryKeys.values()].map((key) => `SQL log ${sqlLogPath}: ${key.Field} is a primary key from ${sourcesOf(key.Variables)}. The log holds its value. Check the log before you share it.`);
165
+ }
166
+ /**
167
+ * For each resolved variable other than a key variable: a warning when its value is in the
168
+ * written log, or when it is not set now and so cannot be checked.
169
+ */
170
+ variableValueWarnings(sqlLogPath) {
171
+ const logText = readLog(sqlLogPath);
172
+ if (logText === null) {
173
+ return [`SQL log ${sqlLogPath}: the log could not be read to check for env values. Check the log before you share it.`];
174
+ }
175
+ const keyVariables = new Set();
176
+ this.primaryKeys.forEach((key) => key.Variables.forEach((name) => keyVariables.add(name)));
177
+ const warnings = [];
178
+ for (const name of [...this.variables].filter((variable) => !keyVariables.has(variable)).sort()) {
179
+ if (this.env[name] === undefined) {
180
+ warnings.push(`SQL log ${sqlLogPath}: @env:${name} is not set now, so the log could not be checked for its value. Check the log before you share it.`);
181
+ }
182
+ else if (valueIsInText(name, logText, this.env)) {
183
+ warnings.push(`SQL log ${sqlLogPath}: the value of @env:${name} appears in the log. Check the log before you share it.`);
184
+ }
185
+ }
186
+ return warnings;
187
+ }
188
+ }
189
+ /** The IS-A level of `entity` whose table holds the field: walks up while a parent holds it. */
190
+ function owningLevel(entity, fieldName) {
191
+ let level = entity;
192
+ while (level.ISAParent && level.EntityInfo.ParentEntityFieldNames?.has(fieldName)) {
193
+ level = level.ISAParent;
194
+ }
195
+ return level;
196
+ }
197
+ /** The log text, or null when the file cannot be read. */
198
+ function readLog(sqlLogPath) {
199
+ try {
200
+ return fs.readFileSync(sqlLogPath, 'utf8');
201
+ }
202
+ catch {
203
+ return null;
204
+ }
205
+ }
206
+ /** True when the variable's value is in the text, found with the same forms and length rule as `EnvDisplayMask.MaskText`. */
207
+ function valueIsInText(name, text, env) {
208
+ return EnvDisplayMask.ForVariables([name], env).MaskText(text) !== text;
209
+ }
210
+ /** `@env:A` or `@env:A, @env:B`, sorted. */
211
+ function sourcesOf(variableNames) {
212
+ return [...variableNames].sort().map((name) => `@env:${name}`).join(', ');
213
+ }
214
+ /** The literal forms SQL Server writes for a value in a SET line. Empty when none can be matched. */
215
+ function sqlLiteralsOf(value) {
216
+ if (value instanceof Date) {
217
+ return Number.isNaN(value.getTime()) ? [] : [`'${value.toISOString()}'`];
218
+ }
219
+ if (typeof value === 'boolean') {
220
+ return [value ? '1' : '0'];
221
+ }
222
+ if (typeof value === 'number' || typeof value === 'bigint') {
223
+ return [String(value)];
224
+ }
225
+ if (value !== null && typeof value === 'object') {
226
+ return quotedLiterals(JSON.stringify(value));
227
+ }
228
+ if (typeof value !== 'string') {
229
+ return [];
230
+ }
231
+ return [...quotedLiterals(value), ...stringValueLiterals(value)];
232
+ }
233
+ /** The number or bit literal forms of a string value that holds a number or a boolean. */
234
+ function stringValueLiterals(value) {
235
+ const trimmed = value.trim();
236
+ const literals = [];
237
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
238
+ literals.push(trimmed);
239
+ }
240
+ const lower = trimmed.toLowerCase();
241
+ if (lower === 'true') {
242
+ literals.push('1');
243
+ }
244
+ else if (lower === 'false') {
245
+ literals.push('0');
246
+ }
247
+ return literals;
248
+ }
249
+ function quotedLiterals(text) {
250
+ const escaped = text.replace(/'/g, "''");
251
+ return [`N'${escaped}'`, `'${escaped}'`];
252
+ }
253
+ function escapeRegExp(text) {
254
+ return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
255
+ }
256
+ /**
257
+ * One whole `SET @<codeName>_<suffix>[_n] = <literal>` line; group 1 is the indent. The suffix is
258
+ * the given hash, or any 12 hex when the hash is `ANY_SUFFIX`.
259
+ */
260
+ function setLinePattern(codeName, hash, literals) {
261
+ const alternatives = literals.map(escapeRegExp).join('|');
262
+ const suffix = hash === ANY_SUFFIX ? '[0-9a-fA-F]{12}' : escapeRegExp(hash);
263
+ return new RegExp(`^([ \\t]*)SET @${escapeRegExp(codeName)}_${suffix}(?:_\\d+)? = (?:${alternatives})[ \\t]*$`, 'gm');
264
+ }
265
+ /**
266
+ * The redactor of one open SQL log, with the `SyncEngine.BeforeLookupCreateSave` hook that registers
267
+ * each record a `?create` lookup creates (with the full row, because a create writes every field).
268
+ */
269
+ export class EnvSqlLog {
270
+ /** Creates the redactor over the engine's resolved variables and sets the engine's hook. */
271
+ constructor(engine) {
272
+ this.engine = engine;
273
+ this.Redactor = new EnvSqlRedactor(engine.ResolvedEnvVariables);
274
+ this.hook = (created, envFields) => this.Redactor.RegisterEntityFields(created, envFields, true);
275
+ engine.BeforeLookupCreateSave = this.hook;
276
+ }
277
+ /** Clears the engine's hook when it is still this log's hook. */
278
+ Close() {
279
+ if (this.engine.BeforeLookupCreateSave === this.hook) {
280
+ this.engine.BeforeLookupCreateSave = null;
281
+ }
282
+ }
283
+ }
284
+ /**
285
+ * Adds a field that was left out because its `?optional` variable is not set. The SQL log then
286
+ * leaves the field's SET line out by name, as for an env-sourced field: a full-row save would
287
+ * otherwise write the field's database value.
288
+ */
289
+ export function AddSkippedOptionalEnvField(envFields, fieldName, variableName) {
290
+ if (!envFields) {
291
+ return;
292
+ }
293
+ const variables = envFields.get(fieldName) ?? new Set();
294
+ variables.add(variableName);
295
+ envFields.set(fieldName, variables);
296
+ }
297
+ //# sourceMappingURL=env-sql-redactor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-sql-redactor.js","sourceRoot":"","sources":["../../src/lib/env-sql-redactor.ts"],"names":[],"mappings":"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"}