@lowdefy/operators-js 6.1.0 → 7.0.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.
Files changed (81) hide show
  1. package/dist/checks.js +24 -0
  2. package/dist/metas.js +26 -0
  3. package/dist/operators/build/authConfig.js +62 -0
  4. package/dist/operators/build/authConfig.schema.js +37 -0
  5. package/dist/operators/client/_index.js +6 -0
  6. package/dist/operators/client/actions.js +4 -0
  7. package/dist/operators/client/api.js +9 -0
  8. package/dist/operators/client/base64.js +3 -0
  9. package/dist/operators/client/event.js +4 -0
  10. package/dist/operators/client/event_log.js +4 -0
  11. package/dist/operators/client/global.js +9 -1
  12. package/dist/operators/client/input.js +9 -1
  13. package/dist/operators/client/js.js +15 -1
  14. package/dist/operators/client/location.js +13 -0
  15. package/dist/operators/client/media.js +17 -33
  16. package/dist/operators/client/menu.js +6 -0
  17. package/dist/operators/client/path_params.js +31 -0
  18. package/dist/operators/client/path_params.schema.js +49 -0
  19. package/dist/operators/client/request.js +9 -0
  20. package/dist/operators/client/request_details.js +10 -1
  21. package/dist/operators/client/theme.js +7 -0
  22. package/dist/operators/client/url_query.js +4 -0
  23. package/dist/operators/client/websocket.js +4 -0
  24. package/dist/operators/server/agent.js +29 -0
  25. package/dist/operators/server/agent.schema.js +61 -0
  26. package/dist/operators/server/credential.js +22 -0
  27. package/dist/operators/server/credential.schema.js +20 -0
  28. package/dist/operators/server/hmac.js +72 -0
  29. package/dist/operators/server/hmac.schema.js +35 -0
  30. package/dist/operators/server/js.js +1 -1
  31. package/dist/operators/server/organization.js +40 -0
  32. package/dist/operators/server/organization.schema.js +59 -0
  33. package/dist/operators/shared/and.js +3 -0
  34. package/dist/operators/shared/app.js +3 -0
  35. package/dist/operators/shared/args.js +4 -0
  36. package/dist/operators/shared/array.js +116 -1
  37. package/dist/operators/shared/boolean.js +3 -0
  38. package/dist/operators/shared/date.js +16 -0
  39. package/dist/operators/shared/divide.js +3 -0
  40. package/dist/operators/shared/eq.js +3 -0
  41. package/dist/operators/shared/error.js +4 -0
  42. package/dist/operators/shared/function.js +4 -0
  43. package/dist/operators/shared/get.js +3 -0
  44. package/dist/operators/shared/gt.js +3 -0
  45. package/dist/operators/shared/gte.js +3 -0
  46. package/dist/operators/shared/if.check.js +25 -0
  47. package/dist/operators/shared/if.js +3 -0
  48. package/dist/operators/shared/if_none.js +3 -0
  49. package/dist/operators/shared/intl.js +14 -1
  50. package/dist/operators/shared/json.js +3 -0
  51. package/dist/operators/shared/locale.js +7 -0
  52. package/dist/operators/shared/log.js +4 -0
  53. package/dist/operators/shared/lt.js +3 -0
  54. package/dist/operators/shared/lte.js +3 -0
  55. package/dist/operators/shared/math.js +6 -0
  56. package/dist/operators/shared/ne.js +3 -0
  57. package/dist/operators/shared/not.js +3 -0
  58. package/dist/operators/shared/number.js +3 -0
  59. package/dist/operators/shared/object.js +3 -0
  60. package/dist/operators/shared/operator.js +17 -2
  61. package/dist/operators/shared/operator.schema.js +7 -0
  62. package/dist/operators/shared/or.js +3 -0
  63. package/dist/operators/shared/product.js +3 -0
  64. package/dist/operators/shared/random.js +3 -0
  65. package/dist/operators/shared/regex.js +28 -0
  66. package/dist/operators/shared/state.js +9 -1
  67. package/dist/operators/shared/string.js +3 -0
  68. package/dist/operators/shared/subtract.js +3 -0
  69. package/dist/operators/shared/sum.js +3 -0
  70. package/dist/operators/shared/switch.js +3 -0
  71. package/dist/operators/shared/t.js +7 -0
  72. package/dist/operators/shared/type.js +23 -0
  73. package/dist/operators/shared/type.schema.js +3 -1
  74. package/dist/operators/shared/uri.js +3 -0
  75. package/dist/operators/shared/user.js +19 -1
  76. package/dist/operatorsBuild.js +4 -0
  77. package/dist/operatorsClient.js +1 -0
  78. package/dist/operatorsServer.js +4 -0
  79. package/dist/schemas.js +6 -0
  80. package/dist/types.js +5 -0
  81. package/package.json +11 -6
@@ -0,0 +1,20 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export default {
16
+ type: 'object',
17
+ params: {
18
+ description: 'A value the routine makes at runtime, such as a new API key or a secret derived with _hmac. Every string in it is replaced with [REDACTED] in the server logs for the rest of the request. The value is returned unchanged.'
19
+ }
20
+ };
@@ -0,0 +1,72 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import crypto from 'crypto';
16
+ import { ConfigError } from '@lowdefy/errors';
17
+ import { type } from '@lowdefy/helpers';
18
+ import { runClass } from '@lowdefy/operators';
19
+ function createHmac(methodName) {
20
+ return function hmac(key, data) {
21
+ if (!type.isString(key)) {
22
+ throw new Error(`_hmac.${methodName} requires "key" to be a string.`);
23
+ }
24
+ if (!type.isString(data)) {
25
+ throw new Error(`_hmac.${methodName} requires "data" to be a string.`);
26
+ }
27
+ return crypto.createHmac(methodName, key).update(data, 'utf8').digest('hex');
28
+ };
29
+ }
30
+ const functions = {
31
+ sha256: createHmac('sha256'),
32
+ sha512: createHmac('sha512')
33
+ };
34
+ const meta = {
35
+ sha256: {
36
+ validTypes: [
37
+ 'object'
38
+ ],
39
+ namedArgs: [
40
+ 'key',
41
+ 'data'
42
+ ]
43
+ },
44
+ sha512: {
45
+ validTypes: [
46
+ 'object'
47
+ ],
48
+ namedArgs: [
49
+ 'key',
50
+ 'data'
51
+ ]
52
+ }
53
+ };
54
+ // Every refusal is thrown as a ConfigError, which the parser reports without the operator's
55
+ // params as received: `key` is often a key derived from a secret, which the secret scrub does
56
+ // not know.
57
+ function _hmac({ params, location, methodName }) {
58
+ try {
59
+ return runClass({
60
+ functions,
61
+ location,
62
+ meta,
63
+ methodName,
64
+ operator: '_hmac',
65
+ params
66
+ });
67
+ } catch (error) {
68
+ throw new ConfigError(error.message);
69
+ }
70
+ }
71
+ _hmac.dynamic = false;
72
+ export default _hmac;
@@ -0,0 +1,35 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export default {
16
+ type: 'object',
17
+ params: {
18
+ type: 'object',
19
+ required: [
20
+ 'key',
21
+ 'data'
22
+ ],
23
+ properties: {
24
+ key: {
25
+ type: 'string',
26
+ description: 'The secret key, as a UTF-8 string. Usually a _secret.'
27
+ },
28
+ data: {
29
+ type: 'string',
30
+ description: 'The UTF-8 string to sign.'
31
+ }
32
+ },
33
+ additionalProperties: false
34
+ }
35
+ };
@@ -53,7 +53,7 @@ function js(operatorContext) {
53
53
  })
54
54
  });
55
55
  } catch (error) {
56
- throw new Error(`_js function execution error. Function: ${jsMap[hash].toString()}`, {
56
+ throw new Error(`_js function execution error. ${error.name}: ${error.message}`, {
57
57
  cause: error
58
58
  });
59
59
  }
@@ -0,0 +1,40 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { ConfigError, LowdefyInternalError } from '@lowdefy/errors';
16
+ import { getFromObject } from '@lowdefy/operators';
17
+ import { type } from '@lowdefy/helpers';
18
+ // Reads the resolved pinned organization ({ id, slug, name }) the engine
19
+ // retained from the startup ensure-by-slug. Evaluated at request time like
20
+ // _secret / _payload - the org id is minted at creation and known only after
21
+ // startup, so no build-time operator or config var can carry it.
22
+ function _organization({ location, organization, params }) {
23
+ if (type.isNone(organization)) {
24
+ throw new ConfigError('_organization requires auth organizations to be configured - no organizations state is available.');
25
+ }
26
+ if (organization.policy === 'tenant') {
27
+ throw new ConfigError('_organization cannot resolve under the "tenant" organizations policy - there is no single pinned organization. Pass an explicit organization id instead.');
28
+ }
29
+ if (type.isNone(organization.pinned)) {
30
+ throw new LowdefyInternalError('The pinned organization has not been resolved - the startup ensure has not completed or failed.');
31
+ }
32
+ return getFromObject({
33
+ location,
34
+ object: organization.pinned,
35
+ operator: '_organization',
36
+ params
37
+ });
38
+ }
39
+ _organization.dynamic = true;
40
+ export default _organization;
@@ -0,0 +1,59 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ export default {
16
+ type: 'object',
17
+ params: {
18
+ oneOf: [
19
+ {
20
+ type: 'string',
21
+ enum: [
22
+ 'id',
23
+ 'slug',
24
+ 'name'
25
+ ],
26
+ description: 'Field of the resolved pinned organization to return.'
27
+ },
28
+ {
29
+ type: 'boolean',
30
+ enum: [
31
+ true
32
+ ],
33
+ description: 'Return the resolved pinned organization.'
34
+ },
35
+ {
36
+ type: 'object',
37
+ properties: {
38
+ key: {
39
+ type: 'string',
40
+ enum: [
41
+ 'id',
42
+ 'slug',
43
+ 'name'
44
+ ],
45
+ description: 'Field of the resolved pinned organization to return.'
46
+ },
47
+ default: {
48
+ description: 'Default value if key does not exist.'
49
+ },
50
+ all: {
51
+ type: 'boolean',
52
+ description: 'Return the resolved pinned organization.'
53
+ }
54
+ },
55
+ additionalProperties: false
56
+ }
57
+ ]
58
+ }
59
+ };
@@ -20,4 +20,7 @@ function _and({ params }) {
20
20
  return !!params.reduce((acc, el)=>acc && el, true);
21
21
  }
22
22
  _and.dynamic = false;
23
+ _and.tracking = {
24
+ kind: 'pure'
25
+ };
23
26
  export default _and;
@@ -33,4 +33,7 @@ function _app({ arrayIndices, location, lowdefyApp, params }) {
33
33
  return value;
34
34
  }
35
35
  _app.dynamic = false;
36
+ _app.tracking = {
37
+ kind: 'pure'
38
+ };
36
39
  export default _app;
@@ -23,4 +23,8 @@ function _args({ args, arrayIndices, location, params }) {
23
23
  });
24
24
  }
25
25
  _args.dynamic = false;
26
+ // Reads only the args of its own parse frame, which no update changes.
27
+ _args.tracking = {
28
+ kind: 'pure'
29
+ };
26
30
  export default _args;
@@ -13,7 +13,7 @@
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  */ import { type } from '@lowdefy/helpers';
16
- import { runInstance } from '@lowdefy/operators';
16
+ import { runClass, runInstance } from '@lowdefy/operators';
17
17
  const prep = (args)=>{
18
18
  if (type.isNone(args[0])) {
19
19
  args[0] = [];
@@ -21,6 +21,17 @@ const prep = (args)=>{
21
21
  return args;
22
22
  };
23
23
  const meta = {
24
+ at: {
25
+ namedArgs: [
26
+ 'on',
27
+ 'index'
28
+ ],
29
+ prep,
30
+ validTypes: [
31
+ 'array',
32
+ 'object'
33
+ ]
34
+ },
24
35
  concat: {
25
36
  prep,
26
37
  validTypes: [
@@ -97,6 +108,28 @@ const meta = {
97
108
  'object'
98
109
  ]
99
110
  },
111
+ findLast: {
112
+ namedArgs: [
113
+ 'on',
114
+ 'callback'
115
+ ],
116
+ prep,
117
+ validTypes: [
118
+ 'array',
119
+ 'object'
120
+ ]
121
+ },
122
+ findLastIndex: {
123
+ namedArgs: [
124
+ 'on',
125
+ 'callback'
126
+ ],
127
+ prep,
128
+ validTypes: [
129
+ 'array',
130
+ 'object'
131
+ ]
132
+ },
100
133
  flat: {
101
134
  namedArgs: [
102
135
  'on',
@@ -108,6 +141,28 @@ const meta = {
108
141
  'object'
109
142
  ]
110
143
  },
144
+ flatMap: {
145
+ namedArgs: [
146
+ 'on',
147
+ 'callback'
148
+ ],
149
+ prep,
150
+ validTypes: [
151
+ 'array',
152
+ 'object'
153
+ ]
154
+ },
155
+ // Array.from is static; it builds a new array, e.g. of length n from { length: n }.
156
+ from: {
157
+ namedArgs: [
158
+ 'on',
159
+ 'callback'
160
+ ],
161
+ validTypes: [
162
+ 'array',
163
+ 'object'
164
+ ]
165
+ },
111
166
  includes: {
112
167
  namedArgs: [
113
168
  'on',
@@ -163,6 +218,29 @@ const meta = {
163
218
  'object'
164
219
  ]
165
220
  },
221
+ // Methods that change the array in place return the changed array, like splice, since the
222
+ // native return values (the new length, or the removed item) are rarely useful in config.
223
+ pop: {
224
+ prep,
225
+ validTypes: [
226
+ 'array',
227
+ 'null'
228
+ ],
229
+ singleArg: true,
230
+ returnInstance: true
231
+ },
232
+ push: {
233
+ namedArgs: [
234
+ 'on'
235
+ ],
236
+ spreadArgs: 'items',
237
+ returnInstance: true,
238
+ prep,
239
+ validTypes: [
240
+ 'array',
241
+ 'object'
242
+ ]
243
+ },
166
244
  reduce: {
167
245
  namedArgs: [
168
246
  'on',
@@ -195,6 +273,15 @@ const meta = {
195
273
  ],
196
274
  singleArg: true
197
275
  },
276
+ shift: {
277
+ prep,
278
+ validTypes: [
279
+ 'array',
280
+ 'null'
281
+ ],
282
+ singleArg: true,
283
+ returnInstance: true
284
+ },
198
285
  slice: {
199
286
  namedArgs: [
200
287
  'on',
@@ -241,6 +328,18 @@ const meta = {
241
328
  'object'
242
329
  ]
243
330
  },
331
+ unshift: {
332
+ namedArgs: [
333
+ 'on'
334
+ ],
335
+ spreadArgs: 'items',
336
+ returnInstance: true,
337
+ prep,
338
+ validTypes: [
339
+ 'array',
340
+ 'object'
341
+ ]
342
+ },
244
343
  length: {
245
344
  validTypes: [
246
345
  'array',
@@ -250,7 +349,20 @@ const meta = {
250
349
  property: true
251
350
  }
252
351
  };
352
+ const functions = {
353
+ from: (arrayLike, callback)=>Array.from(arrayLike, callback)
354
+ };
253
355
  function _array({ params, location, methodName }) {
356
+ if (methodName === 'from') {
357
+ return runClass({
358
+ functions,
359
+ location,
360
+ meta,
361
+ methodName,
362
+ operator: '_array',
363
+ params
364
+ });
365
+ }
254
366
  return runInstance({
255
367
  location,
256
368
  meta,
@@ -261,4 +373,7 @@ function _array({ params, location, methodName }) {
261
373
  });
262
374
  }
263
375
  _array.dynamic = false;
376
+ _array.tracking = {
377
+ kind: 'pure'
378
+ };
264
379
  export default _array;
@@ -16,4 +16,7 @@
16
16
  return !!params;
17
17
  }
18
18
  _boolean.dynamic = false;
19
+ _boolean.tracking = {
20
+ kind: 'pure'
21
+ };
19
22
  export default _boolean;
@@ -449,4 +449,20 @@ function _date({ params, location, methodName }) {
449
449
  });
450
450
  }
451
451
  _date.dynamic = true;
452
+ // "now", and every instance method given no date (prep substitutes the current date), read the clock.
453
+ _date.tracking = ({ methodName, params })=>{
454
+ if (type.isUndefined(methodName)) {
455
+ return {
456
+ kind: params === 'now' ? 'volatile' : 'pure'
457
+ };
458
+ }
459
+ if (methodName === 'now' || type.isNone(params)) {
460
+ return {
461
+ kind: 'volatile'
462
+ };
463
+ }
464
+ return {
465
+ kind: 'pure'
466
+ };
467
+ };
452
468
  export default _date;
@@ -29,4 +29,7 @@ function _divide({ params }) {
29
29
  return params[0] / params[1];
30
30
  }
31
31
  _divide.dynamic = false;
32
+ _divide.tracking = {
33
+ kind: 'pure'
34
+ };
32
35
  export default _divide;
@@ -23,4 +23,7 @@ function _eq({ params }) {
23
23
  return params[0] === params[1];
24
24
  }
25
25
  _eq.dynamic = false;
26
+ _eq.tracking = {
27
+ kind: 'pure'
28
+ };
26
29
  export default _eq;
@@ -34,4 +34,8 @@ function _error({ arrayIndices, error, location, params }) {
34
34
  });
35
35
  }
36
36
  _error.dynamic = true;
37
+ // Reads only the caught error of its own parse frame, which no update changes.
38
+ _error.tracking = {
39
+ kind: 'pure'
40
+ };
37
41
  export default _error;
@@ -29,4 +29,8 @@ function _function({ operatorPrefix, params, parser }) {
29
29
  };
30
30
  }
31
31
  _function.dynamic = true;
32
+ // What the body reads is only known when it is called, often at render time.
33
+ _function.tracking = {
34
+ kind: 'untracked'
35
+ };
32
36
  export default _function;
@@ -34,4 +34,7 @@ function _get({ arrayIndices, location, params }) {
34
34
  });
35
35
  }
36
36
  _get.dynamic = false;
37
+ _get.tracking = {
38
+ kind: 'pure'
39
+ };
37
40
  export default _get;
@@ -23,4 +23,7 @@ function _gt({ params }) {
23
23
  return params[0] > params[1];
24
24
  }
25
25
  _gt.dynamic = false;
26
+ _gt.tracking = {
27
+ kind: 'pure'
28
+ };
26
29
  export default _gt;
@@ -23,4 +23,7 @@ function _gte({ params }) {
23
23
  return params[0] >= params[1];
24
24
  }
25
25
  _gte.dynamic = false;
26
+ _gte.tracking = {
27
+ kind: 'pure'
28
+ };
26
29
  export default _gte;
@@ -0,0 +1,25 @@
1
+ /*
2
+ Copyright 2020-2026 Lowdefy, Inc
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */ import { getOperatorType, type } from '@lowdefy/helpers';
16
+ // _if is not dynamic, so params that are one operator ({ _state: ifParams })
17
+ // are evaluated first and may give a valid object. Array and primitive params
18
+ // are left to the runtime error.
19
+ const ifTest = {
20
+ id: 'if-test',
21
+ level: 'error',
22
+ description: '_if needs its condition under test.',
23
+ check: ({ params })=>type.isObject(params) && !('test' in params) && getOperatorType(params) === null ? '_if has no test key. Put the condition under test:.' : null
24
+ };
25
+ export default ifTest;
@@ -22,4 +22,7 @@
22
22
  throw new Error(`_if takes a boolean type for parameter test.`);
23
23
  }
24
24
  _if.dynamic = false;
25
+ _if.tracking = {
26
+ kind: 'pure'
27
+ };
25
28
  export default _if;
@@ -26,4 +26,7 @@ function _if_none({ params }) {
26
26
  return params[0];
27
27
  }
28
28
  _if_none.dynamic = false;
29
+ _if_none.tracking = {
30
+ kind: 'pure'
31
+ };
29
32
  export default _if_none;
@@ -12,7 +12,8 @@
12
12
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
- */ import { runClass } from '@lowdefy/operators';
15
+ */ import { type } from '@lowdefy/helpers';
16
+ import { runClass } from '@lowdefy/operators';
16
17
  function createFormatter({ IntlClass }) {
17
18
  const formatter = (on, options, locale)=>{
18
19
  return new IntlClass(locale, options).format(on);
@@ -92,4 +93,16 @@ function intl({ params, location, methodName }) {
92
93
  });
93
94
  }
94
95
  intl.dynamic = true;
96
+ // Intl.DateTimeFormat formats the current time when given no date.
97
+ intl.tracking = ({ methodName, params })=>{
98
+ if (methodName !== 'dateTimeFormat') {
99
+ return {
100
+ kind: 'pure'
101
+ };
102
+ }
103
+ const on = type.isArray(params) ? params[0] : params?.on;
104
+ return {
105
+ kind: type.isUndefined(on) ? 'volatile' : 'pure'
106
+ };
107
+ };
95
108
  export default intl;
@@ -59,4 +59,7 @@ function _json({ params, location, methodName }) {
59
59
  });
60
60
  }
61
61
  _json.dynamic = false;
62
+ _json.tracking = {
63
+ kind: 'pure'
64
+ };
62
65
  export default _json;
@@ -29,4 +29,11 @@ function _locale({ arrayIndices, location, params, i18n }) {
29
29
  });
30
30
  }
31
31
  _locale.dynamic = true;
32
+ // i18n changes reach the engine through the full render-time pass, which evaluates every block.
33
+ _locale.tracking = {
34
+ kind: 'read',
35
+ keys: ()=>[
36
+ 'i18n'
37
+ ]
38
+ };
32
39
  export default _locale;
@@ -18,4 +18,8 @@
18
18
  return params;
19
19
  }
20
20
  _log.dynamic = true;
21
+ // Pure for its output. Its console output only happens on the passes that evaluate its block.
22
+ _log.tracking = {
23
+ kind: 'pure'
24
+ };
21
25
  export default _log;
@@ -23,4 +23,7 @@ function _lt({ params }) {
23
23
  return params[0] < params[1];
24
24
  }
25
25
  _lt.dynamic = false;
26
+ _lt.tracking = {
27
+ kind: 'pure'
28
+ };
26
29
  export default _lt;
@@ -23,4 +23,7 @@ function _lte({ params }) {
23
23
  return params[0] <= params[1];
24
24
  }
25
25
  _lte.dynamic = false;
26
+ _lte.tracking = {
27
+ kind: 'pure'
28
+ };
26
29
  export default _lte;
@@ -282,5 +282,11 @@ function _math({ params, location, methodName }) {
282
282
  });
283
283
  }
284
284
  _math.dynamic = false;
285
+ _math.tracking = ({ methodName, params })=>{
286
+ const method = methodName ?? params;
287
+ return {
288
+ kind: method === 'random' ? 'volatile' : 'pure'
289
+ };
290
+ };
285
291
  _math.meta = meta;
286
292
  export default _math;