@memberjunction/core 6.2.0-edge.5 → 6.2.0-edge.6

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 (121) hide show
  1. package/dist/generic/BaseEntitySaveQueue.d.ts +15 -0
  2. package/dist/generic/BaseEntitySaveQueue.d.ts.map +1 -1
  3. package/dist/generic/BaseEntitySaveQueue.js +21 -0
  4. package/dist/generic/BaseEntitySaveQueue.js.map +1 -1
  5. package/dist/generic/alternateBaseViews.d.ts +119 -0
  6. package/dist/generic/alternateBaseViews.d.ts.map +1 -0
  7. package/dist/generic/alternateBaseViews.js +223 -0
  8. package/dist/generic/alternateBaseViews.js.map +1 -0
  9. package/dist/generic/baseEngine.d.ts +53 -9
  10. package/dist/generic/baseEngine.d.ts.map +1 -1
  11. package/dist/generic/baseEngine.js +194 -35
  12. package/dist/generic/baseEngine.js.map +1 -1
  13. package/dist/generic/baseEngineRegistry.d.ts.map +1 -1
  14. package/dist/generic/baseEngineRegistry.js +2 -1
  15. package/dist/generic/baseEngineRegistry.js.map +1 -1
  16. package/dist/generic/baseEntity.d.ts +153 -17
  17. package/dist/generic/baseEntity.d.ts.map +1 -1
  18. package/dist/generic/baseEntity.js +345 -46
  19. package/dist/generic/baseEntity.js.map +1 -1
  20. package/dist/generic/contextTokens.d.ts +136 -0
  21. package/dist/generic/contextTokens.d.ts.map +1 -0
  22. package/dist/generic/contextTokens.js +319 -0
  23. package/dist/generic/contextTokens.js.map +1 -0
  24. package/dist/generic/databaseProviderBase.d.ts +66 -5
  25. package/dist/generic/databaseProviderBase.d.ts.map +1 -1
  26. package/dist/generic/databaseProviderBase.js +159 -12
  27. package/dist/generic/databaseProviderBase.js.map +1 -1
  28. package/dist/generic/embeddedRecord.d.ts +6 -0
  29. package/dist/generic/embeddedRecord.d.ts.map +1 -1
  30. package/dist/generic/embeddedRecord.js +15 -1
  31. package/dist/generic/embeddedRecord.js.map +1 -1
  32. package/dist/generic/entityCompanion.d.ts +7 -0
  33. package/dist/generic/entityCompanion.d.ts.map +1 -1
  34. package/dist/generic/entityCompanion.js +8 -0
  35. package/dist/generic/entityCompanion.js.map +1 -1
  36. package/dist/generic/entityInfo.d.ts +228 -9
  37. package/dist/generic/entityInfo.d.ts.map +1 -1
  38. package/dist/generic/entityInfo.js +574 -65
  39. package/dist/generic/entityInfo.js.map +1 -1
  40. package/dist/generic/entityValueFieldSecurity.d.ts +139 -0
  41. package/dist/generic/entityValueFieldSecurity.d.ts.map +1 -0
  42. package/dist/generic/entityValueFieldSecurity.js +250 -0
  43. package/dist/generic/entityValueFieldSecurity.js.map +1 -0
  44. package/dist/generic/fieldSecuritySQLGate.d.ts +350 -0
  45. package/dist/generic/fieldSecuritySQLGate.d.ts.map +1 -0
  46. package/dist/generic/fieldSecuritySQLGate.js +898 -0
  47. package/dist/generic/fieldSecuritySQLGate.js.map +1 -0
  48. package/dist/generic/indexRestrictedFields.d.ts +47 -0
  49. package/dist/generic/indexRestrictedFields.d.ts.map +1 -0
  50. package/dist/generic/indexRestrictedFields.js +129 -0
  51. package/dist/generic/indexRestrictedFields.js.map +1 -0
  52. package/dist/generic/interfaces.d.ts +14 -1
  53. package/dist/generic/interfaces.d.ts.map +1 -1
  54. package/dist/generic/interfaces.js.map +1 -1
  55. package/dist/generic/localCacheManager.d.ts +80 -11
  56. package/dist/generic/localCacheManager.d.ts.map +1 -1
  57. package/dist/generic/localCacheManager.js +209 -38
  58. package/dist/generic/localCacheManager.js.map +1 -1
  59. package/dist/generic/logging.d.ts.map +1 -1
  60. package/dist/generic/logging.js +7 -1
  61. package/dist/generic/logging.js.map +1 -1
  62. package/dist/generic/metadata.d.ts +3 -2
  63. package/dist/generic/metadata.d.ts.map +1 -1
  64. package/dist/generic/metadata.js +5 -2
  65. package/dist/generic/metadata.js.map +1 -1
  66. package/dist/generic/platformSQL.d.ts +54 -0
  67. package/dist/generic/platformSQL.d.ts.map +1 -1
  68. package/dist/generic/platformSQL.js +55 -0
  69. package/dist/generic/platformSQL.js.map +1 -1
  70. package/dist/generic/providerBase.d.ts +254 -56
  71. package/dist/generic/providerBase.d.ts.map +1 -1
  72. package/dist/generic/providerBase.js +698 -195
  73. package/dist/generic/providerBase.js.map +1 -1
  74. package/dist/generic/queryInfo.d.ts +13 -0
  75. package/dist/generic/queryInfo.d.ts.map +1 -1
  76. package/dist/generic/queryInfo.js +13 -0
  77. package/dist/generic/queryInfo.js.map +1 -1
  78. package/dist/generic/queryInfoInterfaces.d.ts +8 -0
  79. package/dist/generic/queryInfoInterfaces.d.ts.map +1 -1
  80. package/dist/generic/queryTemplateContext.d.ts +49 -0
  81. package/dist/generic/queryTemplateContext.d.ts.map +1 -0
  82. package/dist/generic/queryTemplateContext.js +113 -0
  83. package/dist/generic/queryTemplateContext.js.map +1 -0
  84. package/dist/generic/recordChangeFieldSecurity.d.ts.map +1 -1
  85. package/dist/generic/recordChangeFieldSecurity.js +13 -2
  86. package/dist/generic/recordChangeFieldSecurity.js.map +1 -1
  87. package/dist/generic/relatedRecordCollection.d.ts +13 -0
  88. package/dist/generic/relatedRecordCollection.d.ts.map +1 -1
  89. package/dist/generic/relatedRecordCollection.js +44 -5
  90. package/dist/generic/relatedRecordCollection.js.map +1 -1
  91. package/dist/generic/runQuery.d.ts +42 -0
  92. package/dist/generic/runQuery.d.ts.map +1 -1
  93. package/dist/generic/runQuery.js +14 -0
  94. package/dist/generic/runQuery.js.map +1 -1
  95. package/dist/generic/runQuerySQLFilterImplementations.d.ts.map +1 -1
  96. package/dist/generic/runQuerySQLFilterImplementations.js +38 -2
  97. package/dist/generic/runQuerySQLFilterImplementations.js.map +1 -1
  98. package/dist/generic/saveEntityGraphOperation.d.ts.map +1 -1
  99. package/dist/generic/saveEntityGraphOperation.js +3 -0
  100. package/dist/generic/saveEntityGraphOperation.js.map +1 -1
  101. package/dist/generic/securityInfo.d.ts +11 -0
  102. package/dist/generic/securityInfo.d.ts.map +1 -1
  103. package/dist/generic/securityInfo.js +15 -0
  104. package/dist/generic/securityInfo.js.map +1 -1
  105. package/dist/generic/telemetryManager.d.ts +9 -0
  106. package/dist/generic/telemetryManager.d.ts.map +1 -1
  107. package/dist/generic/telemetryManager.js +5 -1
  108. package/dist/generic/telemetryManager.js.map +1 -1
  109. package/dist/index.d.ts +7 -0
  110. package/dist/index.d.ts.map +1 -1
  111. package/dist/index.js +7 -0
  112. package/dist/index.js.map +1 -1
  113. package/dist/views/runView.d.ts +89 -0
  114. package/dist/views/runView.d.ts.map +1 -1
  115. package/dist/views/runView.js +36 -0
  116. package/dist/views/runView.js.map +1 -1
  117. package/dist/views/viewProperties.d.ts +55 -0
  118. package/dist/views/viewProperties.d.ts.map +1 -0
  119. package/dist/views/viewProperties.js +258 -0
  120. package/dist/views/viewProperties.js.map +1 -0
  121. package/package.json +3 -3
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Context tokens and property defaults.
3
+ *
4
+ * A property (a User View property, a dashboard property, a query's server-set variable) can
5
+ * default to a fixed value or to a context token: a name from a closed list, worked out from the
6
+ * context user and the clock alone. The same resolver runs in the browser and on the server, so
7
+ * the two can differ only in the time zone they are given.
8
+ *
9
+ * - User tokens (`Context.UserID`, `Context.UserEmail`, `Context.UserName`) need a context user;
10
+ * without one they throw rather than resolve to a blank.
11
+ * - **WARNING — SQL template escaping (`| sqlString`):** `Context.UserEmail` and `Context.UserName`
12
+ * resolve to raw, unescaped strings (for example `O'Brien`) and reach Nunjucks query templates with
13
+ * `autoescape: false`. Query templates **must** pipe them through `| sqlString`
14
+ * (e.g. `WHERE Email = {{ Context.UserEmail | sqlString }}` or
15
+ * `WHERE Name = {{ Context.UserName | sqlString }}`). Rendering `{{ Context.UserEmail }}` or
16
+ * `{{ Context.UserName }}` bare produces broken SQL on apostrophes and opens SQL injection.
17
+ * (User View properties are escaped automatically by `UserViewPropertyWhereClause`.)
18
+ * - Date tokens give a `YYYY-MM-DD` date in the given zone (`Context.Today`, `Context.StartOf*`),
19
+ * or an ISO 8601 instant (`Context.Now`). Only date tokens take an offset.
20
+ * - The zone is an IANA name, `'UTC'` when none is given. Weeks start on Monday (ISO 8601) unless
21
+ * the context says Sunday.
22
+ */
23
+ /** Every context token. The list is closed: an app's own context is a property value, never a token. */
24
+ export declare const CONTEXT_TOKENS: readonly ["Context.UserID", "Context.UserEmail", "Context.UserName", "Context.Now", "Context.Today", "Context.StartOfWeek", "Context.StartOfMonth", "Context.StartOfQuarter", "Context.StartOfYear"];
25
+ /** A context token: one of {@link CONTEXT_TOKENS}. */
26
+ export type ContextToken = typeof CONTEXT_TOKENS[number];
27
+ /**
28
+ * The version of what {@link CONTEXT_TOKENS} means. Approval fingerprints include it, so an approval
29
+ * given under one meaning is stale under another. Bump it whenever a token is added, removed or
30
+ * worked out differently (a new week start, a different date format, a different user field).
31
+ */
32
+ export declare const CONTEXT_TOKEN_CONTRACT_VERSION = 1;
33
+ /** The value types a property can declare. */
34
+ export declare const PROPERTY_VALUE_TYPES: readonly ["string", "number", "boolean", "date", "uuid"];
35
+ /** A property's value type: one of {@link PROPERTY_VALUE_TYPES}. */
36
+ export type PropertyValueType = typeof PROPERTY_VALUE_TYPES[number];
37
+ /** The units an offset can move a date token by. */
38
+ export declare const PROPERTY_OFFSET_UNITS: readonly ["day", "week", "month", "quarter", "year"];
39
+ /** An offset unit: one of {@link PROPERTY_OFFSET_UNITS}. */
40
+ export type PropertyOffsetUnit = typeof PROPERTY_OFFSET_UNITS[number];
41
+ /** Moves a date token: `{ Amount: -30, Unit: 'day' }` is thirty days earlier. */
42
+ export interface PropertyDefaultOffset {
43
+ /** A whole number; negative moves back. */
44
+ Amount: number;
45
+ Unit: PropertyOffsetUnit;
46
+ }
47
+ /** A property value, fixed or resolved. */
48
+ export type PropertyValue = string | number | boolean | null;
49
+ /**
50
+ * A property's default: a fixed value, or a token worked out when the value is used. Set exactly
51
+ * one of `Value` and `Token`. This is the shape the `MJ: User Views.Properties` JSON stores.
52
+ */
53
+ export interface PropertyDefault {
54
+ /** A fixed value. Set this or Token, not both. */
55
+ Value?: PropertyValue;
56
+ /** A context token. Set this or Value, not both. */
57
+ Token?: ContextToken;
58
+ /** Moves a date token; refused on a user token and on a fixed value. */
59
+ Offset?: PropertyDefaultOffset;
60
+ }
61
+ /** The comparison a User View property's value drives. */
62
+ export type UserViewPropertyOperator = '=' | '<>' | 'IN' | '>' | '>=' | '<' | '<=';
63
+ /** The field a User View property filters, and how. */
64
+ export interface UserViewPropertyTarget {
65
+ /** A field of the view's entity. */
66
+ Field: string;
67
+ Operator: UserViewPropertyOperator;
68
+ }
69
+ /**
70
+ * One declared property of a User View: a named, typed input that adds one predicate on its
71
+ * target field when a run gives it a value or it has a default. Stored as a JSON array in the
72
+ * `Properties` column of `MJ: User Views`.
73
+ */
74
+ export interface UserViewProperty {
75
+ /** Unique within the view. */
76
+ Name: string;
77
+ /** The value's type. A value of another type is refused. */
78
+ Type: PropertyValueType;
79
+ /** Shown to whoever sets the property. */
80
+ Description?: string;
81
+ /** Used when a run gives no value: a fixed value or a context token. */
82
+ Default?: PropertyDefault;
83
+ /** True: a run with no value and no default is refused. */
84
+ IsRequired?: boolean;
85
+ /** False: only server code may set it, and a client value is refused. Default true. */
86
+ AllowOverride?: boolean;
87
+ /** The predicate the value drives. */
88
+ Target: UserViewPropertyTarget;
89
+ }
90
+ /** What a token is worked out from. */
91
+ export interface PropertyResolutionContext {
92
+ /** The context user. Required by the user tokens. `UserInfo` fits. */
93
+ User?: {
94
+ ID: string;
95
+ Email?: string;
96
+ Name?: string;
97
+ };
98
+ /** The clock. Defaults to the current time. */
99
+ Now?: Date;
100
+ /** IANA time zone the date tokens are worked out in. Defaults to `'UTC'`. */
101
+ TimeZone?: string;
102
+ /** First day of the week for `Context.StartOfWeek`: 1 = Monday (default, ISO 8601), 0 = Sunday. */
103
+ WeekStartsOn?: 0 | 1;
104
+ }
105
+ /**
106
+ * The request header that carries the caller's IANA time zone. `GraphQLDataProvider` sends it;
107
+ * MJServer reads it into `UserPayload.TimeZone`.
108
+ */
109
+ export declare const TIME_ZONE_HEADER = "x-mj-timezone";
110
+ /** True when `name` is a time zone this runtime's `Intl` accepts (an IANA name such as `'Europe/Paris'`). */
111
+ export declare function IsValidTimeZone(name: string | null | undefined): boolean;
112
+ /** This runtime's own IANA time zone, or undefined where `Intl` gives none. */
113
+ export declare function GetLocalTimeZone(): string | undefined;
114
+ /** True when `token` is one of {@link CONTEXT_TOKENS}. */
115
+ export declare function IsContextToken(token: string | null | undefined): token is ContextToken;
116
+ /**
117
+ * Works out a property default: the fixed value, or the token resolved by {@link ResolveContextToken}.
118
+ * @throws when the default is malformed (see {@link ValidatePropertyDefault}) or the token cannot be resolved
119
+ */
120
+ export declare function ResolvePropertyDefault(def: PropertyDefault, ctx: PropertyResolutionContext): PropertyValue;
121
+ /**
122
+ * Works out one context token.
123
+ * @returns the user's ID, email or name; a `YYYY-MM-DD` date in the context's zone; or, for
124
+ * `Context.Now`, an ISO 8601 instant
125
+ * @throws on an unknown token, a bad offset, an offset on a user token, a user token with no
126
+ * context user, or an invalid time zone
127
+ */
128
+ export declare function ResolveContextToken(token: ContextToken, offset: PropertyDefaultOffset | undefined, ctx: PropertyResolutionContext): string;
129
+ /**
130
+ * Checks a property default against the property's type, as when the definition is saved.
131
+ * @returns the problems found; empty when the default is valid
132
+ */
133
+ export declare function ValidatePropertyDefault(def: PropertyDefault, type: PropertyValueType): string[];
134
+ /** True when a value fits the property type: a finite number, a boolean, a valid UUID or ISO date, or a string. Null fits every type. */
135
+ export declare function IsPropertyValueOfType(value: PropertyValue, type: PropertyValueType): boolean;
136
+ //# sourceMappingURL=contextTokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextTokens.d.ts","sourceRoot":"","sources":["../../src/generic/contextTokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,319 @@
1
+ /**
2
+ * Context tokens and property defaults.
3
+ *
4
+ * A property (a User View property, a dashboard property, a query's server-set variable) can
5
+ * default to a fixed value or to a context token: a name from a closed list, worked out from the
6
+ * context user and the clock alone. The same resolver runs in the browser and on the server, so
7
+ * the two can differ only in the time zone they are given.
8
+ *
9
+ * - User tokens (`Context.UserID`, `Context.UserEmail`, `Context.UserName`) need a context user;
10
+ * without one they throw rather than resolve to a blank.
11
+ * - **WARNING — SQL template escaping (`| sqlString`):** `Context.UserEmail` and `Context.UserName`
12
+ * resolve to raw, unescaped strings (for example `O'Brien`) and reach Nunjucks query templates with
13
+ * `autoescape: false`. Query templates **must** pipe them through `| sqlString`
14
+ * (e.g. `WHERE Email = {{ Context.UserEmail | sqlString }}` or
15
+ * `WHERE Name = {{ Context.UserName | sqlString }}`). Rendering `{{ Context.UserEmail }}` or
16
+ * `{{ Context.UserName }}` bare produces broken SQL on apostrophes and opens SQL injection.
17
+ * (User View properties are escaped automatically by `UserViewPropertyWhereClause`.)
18
+ * - Date tokens give a `YYYY-MM-DD` date in the given zone (`Context.Today`, `Context.StartOf*`),
19
+ * or an ISO 8601 instant (`Context.Now`). Only date tokens take an offset.
20
+ * - The zone is an IANA name, `'UTC'` when none is given. Weeks start on Monday (ISO 8601) unless
21
+ * the context says Sunday.
22
+ */
23
+ import { IsValidUUID } from '@memberjunction/global';
24
+ /** Every context token. The list is closed: an app's own context is a property value, never a token. */
25
+ export const CONTEXT_TOKENS = [
26
+ 'Context.UserID',
27
+ 'Context.UserEmail',
28
+ 'Context.UserName',
29
+ 'Context.Now',
30
+ 'Context.Today',
31
+ 'Context.StartOfWeek',
32
+ 'Context.StartOfMonth',
33
+ 'Context.StartOfQuarter',
34
+ 'Context.StartOfYear',
35
+ ];
36
+ /**
37
+ * The version of what {@link CONTEXT_TOKENS} means. Approval fingerprints include it, so an approval
38
+ * given under one meaning is stale under another. Bump it whenever a token is added, removed or
39
+ * worked out differently (a new week start, a different date format, a different user field).
40
+ */
41
+ export const CONTEXT_TOKEN_CONTRACT_VERSION = 1;
42
+ /** The value types a property can declare. */
43
+ export const PROPERTY_VALUE_TYPES = ['string', 'number', 'boolean', 'date', 'uuid'];
44
+ /** The units an offset can move a date token by. */
45
+ export const PROPERTY_OFFSET_UNITS = ['day', 'week', 'month', 'quarter', 'year'];
46
+ /**
47
+ * The request header that carries the caller's IANA time zone. `GraphQLDataProvider` sends it;
48
+ * MJServer reads it into `UserPayload.TimeZone`.
49
+ */
50
+ export const TIME_ZONE_HEADER = 'x-mj-timezone';
51
+ /** Longer than any IANA name; a longer header value is refused without asking `Intl`. */
52
+ const MAX_TIME_ZONE_LENGTH = 64;
53
+ const USER_TOKENS = ['Context.UserID', 'Context.UserEmail', 'Context.UserName'];
54
+ /** The property types each token's value can fill. */
55
+ const TOKEN_VALUE_TYPES = {
56
+ 'Context.UserID': ['uuid', 'string'],
57
+ 'Context.UserEmail': ['string'],
58
+ 'Context.UserName': ['string'],
59
+ 'Context.Now': ['date', 'string'],
60
+ 'Context.Today': ['date', 'string'],
61
+ 'Context.StartOfWeek': ['date', 'string'],
62
+ 'Context.StartOfMonth': ['date', 'string'],
63
+ 'Context.StartOfQuarter': ['date', 'string'],
64
+ 'Context.StartOfYear': ['date', 'string'],
65
+ };
66
+ /** `YYYY-MM-DD`, optionally followed by an ISO 8601 time and zone. */
67
+ const ISO_DATE_VALUE = /^(\d{4})-(\d{2})-(\d{2})(?:T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:\d{2})?)?$/;
68
+ /** True when `name` is a time zone this runtime's `Intl` accepts (an IANA name such as `'Europe/Paris'`). */
69
+ export function IsValidTimeZone(name) {
70
+ if (typeof name !== 'string' || name.length === 0 || name.length > MAX_TIME_ZONE_LENGTH) {
71
+ return false;
72
+ }
73
+ try {
74
+ new Intl.DateTimeFormat('en-US', { timeZone: name });
75
+ return true;
76
+ }
77
+ catch {
78
+ return false;
79
+ }
80
+ }
81
+ /** This runtime's own IANA time zone, or undefined where `Intl` gives none. */
82
+ export function GetLocalTimeZone() {
83
+ try {
84
+ const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
85
+ return IsValidTimeZone(zone) ? zone : undefined;
86
+ }
87
+ catch {
88
+ return undefined;
89
+ }
90
+ }
91
+ /** True when `token` is one of {@link CONTEXT_TOKENS}. */
92
+ export function IsContextToken(token) {
93
+ return typeof token === 'string' && CONTEXT_TOKENS.includes(token);
94
+ }
95
+ /**
96
+ * Works out a property default: the fixed value, or the token resolved by {@link ResolveContextToken}.
97
+ * @throws when the default is malformed (see {@link ValidatePropertyDefault}) or the token cannot be resolved
98
+ */
99
+ export function ResolvePropertyDefault(def, ctx) {
100
+ const errors = shapeErrors(def);
101
+ if (errors.length > 0) {
102
+ throw new Error(`Invalid property default: ${errors.join(' ')}`);
103
+ }
104
+ return def.Token !== undefined ? ResolveContextToken(def.Token, def.Offset, ctx) : (def.Value ?? null);
105
+ }
106
+ /**
107
+ * Works out one context token.
108
+ * @returns the user's ID, email or name; a `YYYY-MM-DD` date in the context's zone; or, for
109
+ * `Context.Now`, an ISO 8601 instant
110
+ * @throws on an unknown token, a bad offset, an offset on a user token, a user token with no
111
+ * context user, or an invalid time zone
112
+ */
113
+ export function ResolveContextToken(token, offset, ctx) {
114
+ const errors = tokenErrors(token, offset);
115
+ if (errors.length > 0) {
116
+ throw new Error(errors.join(' '));
117
+ }
118
+ if (USER_TOKENS.includes(token)) {
119
+ return resolveUserToken(token, ctx);
120
+ }
121
+ const timeZone = ctx.TimeZone ?? 'UTC';
122
+ if (!IsValidTimeZone(timeZone)) {
123
+ throw new Error(`Invalid time zone "${timeZone}".`);
124
+ }
125
+ const now = ctx.Now ?? new Date();
126
+ if (isNaN(now.getTime())) {
127
+ throw new Error('The context clock (Now) is not a valid date.');
128
+ }
129
+ const local = wallClockIn(now, timeZone);
130
+ if (token === 'Context.Now') {
131
+ return offset ? wallClockToInstant({ ...local, ...addOffset(local, offset) }, timeZone).toISOString() : now.toISOString();
132
+ }
133
+ const start = startOfToken(token, local, ctx.WeekStartsOn === 0 ? 0 : 1);
134
+ return formatCalendarDate(offset ? addOffset(start, offset) : start);
135
+ }
136
+ /**
137
+ * Checks a property default against the property's type, as when the definition is saved.
138
+ * @returns the problems found; empty when the default is valid
139
+ */
140
+ export function ValidatePropertyDefault(def, type) {
141
+ if (!PROPERTY_VALUE_TYPES.includes(type)) {
142
+ return [`Unknown property type "${type}". Allowed: ${PROPERTY_VALUE_TYPES.join(', ')}.`];
143
+ }
144
+ const errors = shapeErrors(def);
145
+ if (errors.length > 0) {
146
+ return errors;
147
+ }
148
+ if (def.Token !== undefined) {
149
+ return TOKEN_VALUE_TYPES[def.Token].includes(type) ? [] : [`${def.Token} cannot default a ${type} property.`];
150
+ }
151
+ return IsPropertyValueOfType(def.Value ?? null, type) ? [] : [`Value ${JSON.stringify(def.Value)} is not a valid ${type}.`];
152
+ }
153
+ /** Problems with a default's shape that need no property type: Value vs Token, the token, the offset. */
154
+ function shapeErrors(def) {
155
+ if (def === null || typeof def !== 'object' || Array.isArray(def)) {
156
+ return ['A default must be an object with Value or Token.'];
157
+ }
158
+ const hasValue = def.Value !== undefined;
159
+ const hasToken = def.Token !== undefined;
160
+ if (hasValue && hasToken) {
161
+ return ['Set Value or Token, not both.'];
162
+ }
163
+ if (!hasValue && !hasToken) {
164
+ return ['Set Value or Token.'];
165
+ }
166
+ if (hasValue) {
167
+ return def.Offset !== undefined ? ['Offset applies only to a token.'] : [];
168
+ }
169
+ return tokenErrors(def.Token, def.Offset);
170
+ }
171
+ /** Problems with a token and its offset. */
172
+ function tokenErrors(token, offset) {
173
+ if (!IsContextToken(token)) {
174
+ return [`Unknown token "${token}". Allowed: ${CONTEXT_TOKENS.join(', ')}.`];
175
+ }
176
+ if (offset === undefined) {
177
+ return [];
178
+ }
179
+ if (USER_TOKENS.includes(token)) {
180
+ return [`${token} cannot take an offset; offsets apply to date tokens only.`];
181
+ }
182
+ if (offset === null || typeof offset !== 'object') {
183
+ return ['Offset must be an object with Amount and Unit.'];
184
+ }
185
+ const errors = [];
186
+ if (!PROPERTY_OFFSET_UNITS.includes(offset.Unit)) {
187
+ errors.push(`Unknown offset unit "${offset.Unit}". Allowed: ${PROPERTY_OFFSET_UNITS.join(', ')}.`);
188
+ }
189
+ if (!Number.isInteger(offset.Amount)) {
190
+ errors.push(`Offset Amount must be a whole number; got ${JSON.stringify(offset.Amount)}.`);
191
+ }
192
+ return errors;
193
+ }
194
+ function resolveUserToken(token, ctx) {
195
+ const user = ctx.User;
196
+ if (!user?.ID) {
197
+ throw new Error(`${token} needs a context user, and none was given.`);
198
+ }
199
+ const value = token === 'Context.UserID' ? user.ID : token === 'Context.UserEmail' ? user.Email : user.Name;
200
+ if (!value) {
201
+ throw new Error(`${token}: the context user has no value for it.`);
202
+ }
203
+ return value;
204
+ }
205
+ /** True when a value fits the property type: a finite number, a boolean, a valid UUID or ISO date, or a string. Null fits every type. */
206
+ export function IsPropertyValueOfType(value, type) {
207
+ if (value === null) {
208
+ return true;
209
+ }
210
+ switch (type) {
211
+ case 'string':
212
+ return typeof value === 'string';
213
+ case 'number':
214
+ return typeof value === 'number' && Number.isFinite(value);
215
+ case 'boolean':
216
+ return typeof value === 'boolean';
217
+ case 'uuid':
218
+ return typeof value === 'string' && IsValidUUID(value);
219
+ case 'date':
220
+ return typeof value === 'string' && isValidDateValue(value);
221
+ default:
222
+ return false;
223
+ }
224
+ }
225
+ /** An ISO 8601 date or date-time whose date part is a real calendar day (no 30 February). */
226
+ function isValidDateValue(value) {
227
+ const match = ISO_DATE_VALUE.exec(value);
228
+ if (!match || isNaN(Date.parse(value))) {
229
+ return false;
230
+ }
231
+ const date = { year: Number(match[1]), month: Number(match[2]), day: Number(match[3]) };
232
+ return date.month >= 1 && date.month <= 12 && date.day >= 1 && date.day <= daysInMonth(date.year, date.month);
233
+ }
234
+ /** The first day of the period a date token names, from today's date in the zone. */
235
+ function startOfToken(token, today, weekStartsOn) {
236
+ switch (token) {
237
+ case 'Context.StartOfWeek': {
238
+ const dayOfWeek = new Date(Date.UTC(today.year, today.month - 1, today.day)).getUTCDay();
239
+ return addDays(today, -((dayOfWeek - weekStartsOn + 7) % 7));
240
+ }
241
+ case 'Context.StartOfMonth':
242
+ return { year: today.year, month: today.month, day: 1 };
243
+ case 'Context.StartOfQuarter':
244
+ return { year: today.year, month: Math.floor((today.month - 1) / 3) * 3 + 1, day: 1 };
245
+ case 'Context.StartOfYear':
246
+ return { year: today.year, month: 1, day: 1 };
247
+ default:
248
+ return { year: today.year, month: today.month, day: today.day };
249
+ }
250
+ }
251
+ /** Moves a date by an offset. Month-based units land on the target month's last day when it is shorter. */
252
+ function addOffset(date, offset) {
253
+ switch (offset.Unit) {
254
+ case 'day':
255
+ return addDays(date, offset.Amount);
256
+ case 'week':
257
+ return addDays(date, offset.Amount * 7);
258
+ case 'month':
259
+ return addMonths(date, offset.Amount);
260
+ case 'quarter':
261
+ return addMonths(date, offset.Amount * 3);
262
+ case 'year':
263
+ return addMonths(date, offset.Amount * 12);
264
+ default:
265
+ throw new Error(`Unknown offset unit "${offset.Unit}".`);
266
+ }
267
+ }
268
+ function addDays(date, days) {
269
+ const moved = new Date(Date.UTC(date.year, date.month - 1, date.day + days));
270
+ return { year: moved.getUTCFullYear(), month: moved.getUTCMonth() + 1, day: moved.getUTCDate() };
271
+ }
272
+ function addMonths(date, months) {
273
+ const index = date.year * 12 + (date.month - 1) + months;
274
+ const year = Math.floor(index / 12);
275
+ const month = index - year * 12 + 1;
276
+ return { year, month, day: Math.min(date.day, daysInMonth(year, month)) };
277
+ }
278
+ function daysInMonth(year, month) {
279
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
280
+ }
281
+ function formatCalendarDate(date) {
282
+ const pad = (n, width) => String(n).padStart(width, '0');
283
+ return `${pad(date.year, 4)}-${pad(date.month, 2)}-${pad(date.day, 2)}`;
284
+ }
285
+ /** The calendar date and wall-clock time of an instant in a zone. */
286
+ function wallClockIn(instant, timeZone) {
287
+ const parts = new Intl.DateTimeFormat('en-US', {
288
+ timeZone,
289
+ hourCycle: 'h23',
290
+ year: 'numeric',
291
+ month: 'numeric',
292
+ day: 'numeric',
293
+ hour: 'numeric',
294
+ minute: 'numeric',
295
+ second: 'numeric',
296
+ }).formatToParts(instant);
297
+ const part = (type) => Number(parts.find((p) => p.type === type)?.value);
298
+ return {
299
+ year: part('year'),
300
+ month: part('month'),
301
+ day: part('day'),
302
+ hour: part('hour') % 24, // some engines write midnight as 24 even with h23
303
+ minute: part('minute'),
304
+ second: part('second'),
305
+ millisecond: instant.getUTCMilliseconds(),
306
+ };
307
+ }
308
+ /** The instant a wall-clock time in a zone names. Two passes settle the zone offset across a DST change. */
309
+ function wallClockToInstant(local, timeZone) {
310
+ const asUTC = Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second, local.millisecond);
311
+ const firstGuess = asUTC - zoneOffsetMs(asUTC, timeZone);
312
+ return new Date(asUTC - zoneOffsetMs(firstGuess, timeZone));
313
+ }
314
+ /** How far the zone's wall clock is ahead of UTC at an instant, in milliseconds. */
315
+ function zoneOffsetMs(instantMs, timeZone) {
316
+ const local = wallClockIn(new Date(instantMs), timeZone);
317
+ return Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute, local.second, local.millisecond) - instantMs;
318
+ }
319
+ //# sourceMappingURL=contextTokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contextTokens.js","sourceRoot":"","sources":["../../src/generic/contextTokens.ts"],"names":[],"mappings":"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"}
@@ -18,6 +18,29 @@ export type FieldChange = {
18
18
  oldValue: unknown;
19
19
  newValue: unknown;
20
20
  };
21
+ /**
22
+ * Options controlling how {@link Metadata.GetRecordDependencies} discovers dependent records.
23
+ */
24
+ export interface GetRecordDependenciesOptions {
25
+ /**
26
+ * Which category of foreign-key links to inspect:
27
+ * - `'both'` (default): Both hard database foreign keys (`EntityField.RelatedEntityID`) and
28
+ * polymorphic / soft foreign keys (`EntityField.EntityIDFieldName`).
29
+ * - `'hard'`: Only direct foreign-key relationships (`RelatedEntityID` is set and `EntityIDFieldName` is empty).
30
+ * - `'soft'`: Only polymorphic foreign-key relationships (`EntityIDFieldName` is set).
31
+ */
32
+ LinkType?: 'both' | 'hard' | 'soft';
33
+ /**
34
+ * Whether to include high-volume system audit/telemetry entities (`MJ: Record Changes`,
35
+ * `MJ: Audit Logs`, `MJ: User Record Logs`, `MJ: User RecordAccess`).
36
+ * Defaults to `true` for delete/merge safety checks; UI record-link viewers pass `false`.
37
+ */
38
+ IncludeSystemEntities?: boolean;
39
+ /**
40
+ * Optional allow-list of entity names to restrict the dependency scan to.
41
+ */
42
+ EntityNames?: string[];
43
+ }
21
44
  /**
22
45
  * Result of save SQL generation. Subclasses populate this from their dialect-specific
23
46
  * SQL generators (stored procedure calls, function calls, etc.).
@@ -340,17 +363,21 @@ export declare abstract class DatabaseProviderBase extends ProviderBase {
340
363
  /**
341
364
  * Builds SQL for hard-link (foreign key) dependency queries.
342
365
  * Returns a UNION ALL query across all dependent entities.
343
- * @param entityDependencies The entity-level dependency metadata
366
+ * @param entityDependencies The entity-level dependency metadata (or entity name to resolve dependencies for)
344
367
  * @param compositeKey The primary key of the record being checked
368
+ * @param options Optional filtering options for dependency discovery
369
+ * @param contextUser Optional user context for permission filtering
345
370
  */
346
- protected abstract BuildHardLinkDependencySQL(entityDependencies: EntityDependency[], compositeKey: CompositeKey): string;
371
+ protected abstract BuildHardLinkDependencySQL(entityDependencies: EntityDependency[] | string, compositeKey: CompositeKey, options?: GetRecordDependenciesOptions, contextUser?: UserInfo): string;
347
372
  /**
348
373
  * Builds SQL for soft-link dependency queries (entities using EntityIDFieldName pattern).
349
374
  * Returns a UNION ALL query across all soft-linked entities.
350
375
  * @param entityName The entity name being checked for dependencies
351
376
  * @param compositeKey The primary key of the record
377
+ * @param options Optional filtering options for dependency discovery
378
+ * @param contextUser Optional user context for permission filtering
352
379
  */
353
- protected abstract BuildSoftLinkDependencySQL(entityName: string, compositeKey: CompositeKey): string;
380
+ protected abstract BuildSoftLinkDependencySQL(entityName: string, compositeKey: CompositeKey, options?: GetRecordDependenciesOptions, contextUser?: UserInfo): string;
354
381
  /**
355
382
  * Generates the SQL (and optional parameters) for a Save (Create or Update) operation.
356
383
  * Each provider produces its own dialect: SQL Server generates T-SQL EXEC statements,
@@ -556,6 +583,39 @@ export declare abstract class DatabaseProviderBase extends ProviderBase {
556
583
  /**************************************************************************/
557
584
  /**************************************************************************/
558
585
  /**************************************************************************/
586
+ /**
587
+ * High-volume system audit/telemetry entities excluded when `options.IncludeSystemEntities === false`.
588
+ */
589
+ private static readonly _systemDependencyEntityNames;
590
+ /**
591
+ * Normalizes `(contextUserOrOptions, options)` so callers can invoke `GetRecordDependencies`
592
+ * with either `(entityName, key, options)` or `(entityName, key, contextUser, options)`.
593
+ */
594
+ protected resolveRecordDependencyArgs(contextUserOrOptions?: UserInfo | GetRecordDependenciesOptions, options?: GetRecordDependenciesOptions): {
595
+ contextUser?: UserInfo;
596
+ options?: GetRecordDependenciesOptions;
597
+ };
598
+ /**
599
+ * Determines whether `relatedEntity` should be included in a record dependency scan
600
+ * based on `options` (`IncludeSystemEntities`, `EntityNames`) and `contextUser` read permissions.
601
+ */
602
+ protected shouldIncludeDependencyEntity(relatedEntity: EntityInfo, options?: GetRecordDependenciesOptions, contextUser?: UserInfo): boolean;
603
+ /**
604
+ * Checks name-based dependency filters (`IncludeSystemEntities` and `EntityNames`)
605
+ * when only the entity name is available.
606
+ */
607
+ protected shouldIncludeDependencyEntityName(relatedEntityName: string, options?: GetRecordDependenciesOptions): boolean;
608
+ /**
609
+ * Resolves an `EntityDependency[] | string` argument to an `EntityDependency[]` array.
610
+ * Supports passing either a pre-resolved `EntityDependency[]` list or an `entityName` string.
611
+ */
612
+ protected resolveEntityDependencies(entityDependenciesOrName: EntityDependency[] | string): EntityDependency[];
613
+ /**
614
+ * Selects `relatedEntity.BaseTable` when `BaseTable` is defined, the entity is not virtual,
615
+ * and all referenced columns (`PrimaryKeys` plus `referencedFieldNames`) are physical (`!f.IsVirtual`).
616
+ * Falls back to `relatedEntity.BaseView` when any referenced column is virtual or `BaseTable` is absent.
617
+ */
618
+ protected resolveDependencySourceObject(relatedEntity: EntityInfo, referencedFieldNames: string[]): string;
559
619
  /**
560
620
  * Returns a list of record-level dependencies — records in other entities linked to
561
621
  * the specified entity/record via foreign keys (hard links) or EntityIDFieldName
@@ -563,9 +623,10 @@ export declare abstract class DatabaseProviderBase extends ProviderBase {
563
623
  *
564
624
  * @param entityName The entity name to check
565
625
  * @param compositeKey The primary key(s) of the record
566
- * @param contextUser Optional context user
626
+ * @param contextUser Optional context user (or options when called with 3 args)
627
+ * @param options Optional filtering options (`LinkType`, `IncludeSystemEntities`, `EntityNames`)
567
628
  */
568
- GetRecordDependencies(entityName: string, compositeKey: CompositeKey, contextUser?: UserInfo): Promise<RecordDependency[]>;
629
+ GetRecordDependencies(entityName: string, compositeKey: CompositeKey, contextUser?: UserInfo | GetRecordDependenciesOptions, options?: GetRecordDependenciesOptions): Promise<RecordDependency[]>;
569
630
  /**
570
631
  * The value to write into a dependent record's link column so it points at the surviving record
571
632
  * of a merge.