@lowdefy/operators-js 6.1.0 → 7.1.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
package/dist/checks.js ADDED
@@ -0,0 +1,24 @@
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 ifTest from './operators/shared/if.check.js';
16
+ // Build check rules, run by the Lowdefy build on each config node of these
17
+ // types. Import only what the rules need, never operator runtime code.
18
+ export default {
19
+ operators: {
20
+ _if: [
21
+ ifTest
22
+ ]
23
+ }
24
+ };
package/dist/metas.js ADDED
@@ -0,0 +1,26 @@
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
+ */ // Operator metas carry only `hazards`: behaviours of an operator that its
16
+ // schema cannot express. The build writes them to plugins/operatorMetas.json
17
+ // for the dev MCP; operators without hazards need no entry here.
18
+ export const _js = {
19
+ hazards: [
20
+ {
21
+ id: 'js-two-prototypes',
22
+ message: 'A _js body in a page receives { actions, args, event, input, location, lowdefyApp, lowdefyGlobal, pathParams, request, state, urlQuery, user }, while the same body in a request, connection or endpoint receives { args, item, lowdefyApp, payload, secret, state, step, user }. Only where the operator sits in the config decides which, so a body written for one place fails silently in the other.',
23
+ see: 'operators/_js'
24
+ }
25
+ ]
26
+ };
@@ -0,0 +1,62 @@
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 } from '@lowdefy/errors';
16
+ import { get, type } from '@lowdefy/helpers';
17
+ // The curated catalog of readable projection paths. Extending it is a
18
+ // deliberate addition to this list — never a fall-through.
19
+ const readablePaths = [
20
+ 'emailAndPassword.enabled',
21
+ 'magicLink.enabled',
22
+ 'emailOTP.enabled',
23
+ 'twoFactor.enabled',
24
+ 'twoFactor.required',
25
+ 'twoFactor.trustDevice',
26
+ 'passkey.enabled',
27
+ 'phoneNumber.enabled',
28
+ 'phoneNumber.signUpOnVerification',
29
+ 'captcha.enabled',
30
+ 'captcha.provider',
31
+ 'captcha.siteKey',
32
+ 'providers',
33
+ 'organizations.policy',
34
+ 'organizations.signup',
35
+ 'roles'
36
+ ];
37
+ // Build-only operator, addressed as { _build.authConfig: '<path>' }. Reads the
38
+ // auth config projection the build computes in a scoped pre-pass before
39
+ // buildRefs. It deliberately has no runtime sibling — none of this data ships
40
+ // to the client or server at runtime.
41
+ function _authConfig({ authConfig, params }) {
42
+ if (type.isUndefined(authConfig)) {
43
+ // The projection is present on the build context after the pre-pass, so an
44
+ // undefined projection means the operator ran somewhere it can never
45
+ // exist: inside the auth: block during the pre-pass (self-reference), or
46
+ // in app metadata (app:), which resolves earlier and is never re-walked.
47
+ // Walks whose output IS re-walked post-projection (module entry vars,
48
+ // deferred-record bodies) defer the fold instead of reaching this throw.
49
+ throw new ConfigError("_build.authConfig is not available here. The auth config projection is computed from the app's auth: block, so the operator can not resolve inside that block itself (a self-reference), nor in app metadata (app:), which resolves earlier.");
50
+ }
51
+ if (!readablePaths.includes(params)) {
52
+ throw new ConfigError(`_build.authConfig received an unreadable path ${JSON.stringify(params)}. Readable paths are: ${readablePaths.map((path)=>`"${path}"`).join(', ')}.`);
53
+ }
54
+ return get(authConfig, params, {
55
+ copy: true
56
+ });
57
+ }
58
+ // dynamic true keeps the bare _authConfig spelling out of build-time static
59
+ // evaluation — the only supported address is the explicit _build.authConfig,
60
+ // which evaluates regardless of dynamic (matching _build.app).
61
+ _authConfig.dynamic = true;
62
+ export default _authConfig;
@@ -0,0 +1,37 @@
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: 'string',
19
+ enum: [
20
+ 'emailAndPassword.enabled',
21
+ 'magicLink.enabled',
22
+ 'emailOTP.enabled',
23
+ 'twoFactor.enabled',
24
+ 'passkey.enabled',
25
+ 'phoneNumber.enabled',
26
+ 'phoneNumber.signUpOnVerification',
27
+ 'captcha.enabled',
28
+ 'captcha.provider',
29
+ 'captcha.siteKey',
30
+ 'providers',
31
+ 'organizations.policy',
32
+ 'organizations.signup',
33
+ 'roles'
34
+ ],
35
+ description: 'Curated auth config projection path to read at build time.'
36
+ }
37
+ };
@@ -23,4 +23,10 @@ function _index({ arrayIndices, location, params }) {
23
23
  });
24
24
  }
25
25
  _index.dynamic = true;
26
+ _index.tracking = {
27
+ kind: 'read',
28
+ keys: ()=>[
29
+ 'index'
30
+ ]
31
+ };
26
32
  export default _index;
@@ -23,4 +23,8 @@ function _actions({ actions, arrayIndices, location, params }) {
23
23
  });
24
24
  }
25
25
  _actions.dynamic = true;
26
+ // Reads only the action results of its own parse frame, which no update changes.
27
+ _actions.tracking = {
28
+ kind: 'pure'
29
+ };
26
30
  export default _actions;
@@ -41,4 +41,13 @@ function _api({ params, apiResponses }) {
41
41
  return null;
42
42
  }
43
43
  _api.dynamic = true;
44
+ // Keyed by endpoint id, the first path segment, which is what an API call update reports.
45
+ _api.tracking = {
46
+ kind: 'read',
47
+ keys: ({ params })=>type.isString(params) ? [
48
+ `api:${params.split('.')[0]}`
49
+ ] : [
50
+ 'api:*'
51
+ ]
52
+ };
44
53
  export default _api;
@@ -48,4 +48,7 @@ function _base64({ params, location, methodName }) {
48
48
  });
49
49
  }
50
50
  _base64.dynamic = true;
51
+ _base64.tracking = {
52
+ kind: 'pure'
53
+ };
51
54
  export default _base64;
@@ -23,4 +23,8 @@ function _event({ arrayIndices, event, location, params }) {
23
23
  });
24
24
  }
25
25
  _event.dynamic = true;
26
+ // Reads only the event of its own parse frame, which no update changes.
27
+ _event.tracking = {
28
+ kind: 'pure'
29
+ };
26
30
  export default _event;
@@ -23,4 +23,8 @@ function _event_log({ arrayIndices, eventLog, location, params }) {
23
23
  });
24
24
  }
25
25
  _event_log.dynamic = true;
26
+ // The event log is written with no change reported.
27
+ _event_log.tracking = {
28
+ kind: 'untracked'
29
+ };
26
30
  export default _event_log;
@@ -12,7 +12,7 @@
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 { getFromObject } from '@lowdefy/operators';
15
+ */ import { getFromObject, getObjectReadKeys } from '@lowdefy/operators';
16
16
  function _global({ arrayIndices, location, lowdefyGlobal, params }) {
17
17
  return getFromObject({
18
18
  arrayIndices,
@@ -23,4 +23,12 @@ function _global({ arrayIndices, location, lowdefyGlobal, params }) {
23
23
  });
24
24
  }
25
25
  _global.dynamic = true;
26
+ _global.tracking = {
27
+ kind: 'read',
28
+ keys: ({ arrayIndices, params })=>getObjectReadKeys({
29
+ arrayIndices,
30
+ namespace: 'global',
31
+ params
32
+ })
33
+ };
26
34
  export default _global;
@@ -12,7 +12,7 @@
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 { getFromObject } from '@lowdefy/operators';
15
+ */ import { getFromObject, getObjectReadKeys } from '@lowdefy/operators';
16
16
  function _input({ arrayIndices, input, location, params }) {
17
17
  return getFromObject({
18
18
  arrayIndices,
@@ -23,4 +23,12 @@ function _input({ arrayIndices, input, location, params }) {
23
23
  });
24
24
  }
25
25
  _input.dynamic = true;
26
+ _input.tracking = {
27
+ kind: 'read',
28
+ keys: ({ arrayIndices, params })=>getObjectReadKeys({
29
+ arrayIndices,
30
+ namespace: 'input',
31
+ params
32
+ })
33
+ };
26
34
  export default _input;
@@ -47,6 +47,10 @@ function js(operatorContext) {
47
47
  ...operatorContext,
48
48
  params: p
49
49
  }),
50
+ pathParams: (p)=>operators._path_params({
51
+ ...operatorContext,
52
+ params: p
53
+ }),
50
54
  request: (p)=>operators._request({
51
55
  ...operatorContext,
52
56
  params: p
@@ -65,10 +69,20 @@ function js(operatorContext) {
65
69
  })
66
70
  });
67
71
  } catch (error) {
68
- throw new Error(`_js function execution error. Function: ${jsMap[hash].toString()}`, {
72
+ throw new Error(`_js function execution error. ${error.name}: ${error.message}`, {
69
73
  cause: error
70
74
  });
71
75
  }
72
76
  }
73
77
  js.dynamic = true;
78
+ // The accessors call operators through the tracked registry view, so the function's reads record
79
+ // themselves. The build marks a function volatile when its source references a browser or clock
80
+ // global. A returned closure, even nested in an object, reads context only when it is called.
81
+ js.tracking = ({ jsMap, params })=>{
82
+ const hash = type.isString(params) ? params : params?.fn;
83
+ return {
84
+ kind: jsMap?.[hash]?.volatile === true ? 'volatile' : 'pure',
85
+ resultMayContainFunctions: true
86
+ };
87
+ };
74
88
  export default js;
@@ -58,4 +58,17 @@ function _location({ arrayIndices, basePath, home, location, pageId, params, glo
58
58
  });
59
59
  }
60
60
  _location.dynamic = true;
61
+ // pageId, basePath and homePageId come from the page's context, which never changes them while
62
+ // it lives (navigation runs a full pass). Everything else reads window.location live, which
63
+ // changes (a hash link, navigation) with no update to report it.
64
+ const contextProperties = [
65
+ 'pageId',
66
+ 'basePath',
67
+ 'homePageId'
68
+ ];
69
+ _location.tracking = ({ params })=>contextProperties.includes(params) ? {
70
+ kind: 'pure'
71
+ } : {
72
+ kind: 'volatile'
73
+ };
61
74
  export default _location;
@@ -12,50 +12,23 @@
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 { getFromObject } from '@lowdefy/operators';
15
+ */ import { getFromObject, getMediaViewport, getObjectReadKeys } from '@lowdefy/operators';
16
+ // The client keeps the preference it reads from storage, under the app's key.
16
17
  function getDarkModePreference(window) {
17
- return window.localStorage?.getItem('lowdefy_darkMode') ?? 'system';
18
+ return window.__lowdefy_darkModePreference ?? 'system';
18
19
  }
19
20
  function getDarkMode(window) {
20
21
  return window.__lowdefy_isDark ?? false;
21
22
  }
22
- const breakpoints = {
23
- xs: 640,
24
- sm: 768,
25
- md: 1024,
26
- lg: 1280,
27
- xl: 1536
28
- };
29
23
  function _media({ arrayIndices, location, params, globals }) {
30
24
  const { window } = globals;
31
25
  if (!window?.innerWidth) {
32
26
  throw new Error(`device window width not available for _media.`);
33
27
  }
34
- let size;
35
- switch(true){
36
- case window.innerWidth < breakpoints.xs:
37
- size = 'xs';
38
- break;
39
- case window.innerWidth < breakpoints.sm:
40
- size = 'sm';
41
- break;
42
- case window.innerWidth < breakpoints.md:
43
- size = 'md';
44
- break;
45
- case window.innerWidth < breakpoints.lg:
46
- size = 'lg';
47
- break;
48
- case window.innerWidth < breakpoints.xl:
49
- size = 'xl';
50
- break;
51
- default:
52
- size = '2xl';
53
- break;
54
- }
55
28
  const media = {
56
- size,
57
- width: window.innerWidth,
58
- height: window.innerHeight,
29
+ ...getMediaViewport({
30
+ window
31
+ }),
59
32
  darkMode: getDarkMode(window),
60
33
  darkModePreference: getDarkModePreference(window)
61
34
  };
@@ -68,4 +41,15 @@ function _media({ arrayIndices, location, params, globals }) {
68
41
  });
69
42
  }
70
43
  _media.dynamic = true;
44
+ // The page's resize listener reports media:size, media:width and media:height when they change, so
45
+ // a block reading _media: size re-evaluates only when the breakpoint changes. Dark mode changes
46
+ // re-render the app, and that render-time full pass evaluates every block (as for _theme).
47
+ _media.tracking = {
48
+ kind: 'read',
49
+ keys: ({ arrayIndices, params })=>getObjectReadKeys({
50
+ arrayIndices,
51
+ namespace: 'media',
52
+ params
53
+ })
54
+ };
71
55
  export default _media;
@@ -46,4 +46,10 @@ function _menu({ params, arrayIndices, menus, location }) {
46
46
  return result;
47
47
  }
48
48
  _menu.dynamic = true;
49
+ _menu.tracking = {
50
+ kind: 'read',
51
+ keys: ()=>[
52
+ 'menu'
53
+ ]
54
+ };
49
55
  export default _menu;
@@ -0,0 +1,31 @@
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 { getFromObject } from '@lowdefy/operators';
16
+ function _path_params({ arrayIndices, location, params, pathParams }) {
17
+ return getFromObject({
18
+ arrayIndices,
19
+ location,
20
+ object: pathParams,
21
+ operator: '_path_params',
22
+ params
23
+ });
24
+ }
25
+ _path_params.dynamic = true;
26
+ // A page instance's path values are fixed for the instance's context: a different value is a
27
+ // different instance.
28
+ _path_params.tracking = {
29
+ kind: 'pure'
30
+ };
31
+ export default _path_params;
@@ -0,0 +1,49 @@
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
+ description: 'Name of the path placeholder to return, or a dot-notation path into the values.'
22
+ },
23
+ {
24
+ type: 'boolean',
25
+ enum: [
26
+ true
27
+ ],
28
+ description: 'Return all path params.'
29
+ },
30
+ {
31
+ type: 'object',
32
+ properties: {
33
+ key: {
34
+ type: 'string',
35
+ description: 'Name of the path placeholder to return, or a dot-notation path into the values.'
36
+ },
37
+ default: {
38
+ description: 'Default value if key does not exist.'
39
+ },
40
+ all: {
41
+ type: 'boolean',
42
+ description: 'Return all path params.'
43
+ }
44
+ },
45
+ additionalProperties: false
46
+ }
47
+ ]
48
+ }
49
+ };
@@ -41,4 +41,13 @@ function _request({ arrayIndices, params, requests }) {
41
41
  return null;
42
42
  }
43
43
  _request.dynamic = true;
44
+ // Keyed by request id, the first path segment, which is what a request update reports.
45
+ _request.tracking = {
46
+ kind: 'read',
47
+ keys: ({ params })=>type.isString(params) ? [
48
+ `request:${params.split('.')[0]}`
49
+ ] : [
50
+ 'request:*'
51
+ ]
52
+ };
44
53
  export default _request;
@@ -12,7 +12,7 @@
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 { getFromObject } from '@lowdefy/operators';
15
+ */ import { getFromObject, getObjectReadKeys } from '@lowdefy/operators';
16
16
  function _request_details({ params, requests, arrayIndices, location }) {
17
17
  return getFromObject({
18
18
  arrayIndices,
@@ -23,4 +23,13 @@ function _request_details({ params, requests, arrayIndices, location }) {
23
23
  });
24
24
  }
25
25
  _request_details.dynamic = true;
26
+ // Keyed by request id, the first path segment, which is what a request update reports.
27
+ _request_details.tracking = {
28
+ kind: 'read',
29
+ keys: ({ arrayIndices, params })=>getObjectReadKeys({
30
+ arrayIndices,
31
+ namespace: 'request',
32
+ params
33
+ }).map((key)=>key.split('.')[0])
34
+ };
26
35
  export default _request_details;
@@ -23,4 +23,11 @@ function _theme({ arrayIndices, location, theme, params }) {
23
23
  });
24
24
  }
25
25
  _theme.dynamic = true;
26
+ // Theme changes reach the engine through the full render-time pass, which evaluates every block.
27
+ _theme.tracking = {
28
+ kind: 'read',
29
+ keys: ()=>[
30
+ 'theme'
31
+ ]
32
+ };
26
33
  export default _theme;
@@ -28,4 +28,8 @@ function _url_query({ arrayIndices, globals, location, params }) {
28
28
  });
29
29
  }
30
30
  _url_query.dynamic = true;
31
+ // Reads window.location.search live, which changes with no update to report it.
32
+ _url_query.tracking = {
33
+ kind: 'volatile'
34
+ };
31
35
  export default _url_query;
@@ -44,4 +44,8 @@ function _websocket({ arrayIndices, params, websockets }) {
44
44
  }
45
45
  }
46
46
  _websocket.dynamic = true;
47
+ // No change key is reported for websocket channels yet.
48
+ _websocket.tracking = {
49
+ kind: 'untracked'
50
+ };
47
51
  export default _websocket;
@@ -0,0 +1,29 @@
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 { getFromObject } from '@lowdefy/operators';
16
+ // Reads the agent ({ id, conversationId, files, sharedState }) the engine put on the routine when an agent
17
+ // called the endpoint as a tool or hook. On any other call there is no agent, and every read
18
+ // resolves to null or its default, the way `_error` does outside a catch.
19
+ function _agent({ agent, arrayIndices, location, params }) {
20
+ return getFromObject({
21
+ arrayIndices,
22
+ location,
23
+ object: agent ?? null,
24
+ operator: '_agent',
25
+ params
26
+ });
27
+ }
28
+ _agent.dynamic = true;
29
+ export default _agent;
@@ -0,0 +1,61 @@
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
+ 'conversationId',
24
+ 'files',
25
+ 'sharedState'
26
+ ],
27
+ description: 'Field of the calling agent to return: its id in agents, the id of the conversation it runs in, the files attached in that conversation, or the shared state of the chat.'
28
+ },
29
+ {
30
+ type: 'boolean',
31
+ enum: [
32
+ true
33
+ ],
34
+ description: 'Return the calling agent as { id, conversationId, files, sharedState }, or null.'
35
+ },
36
+ {
37
+ type: 'object',
38
+ properties: {
39
+ key: {
40
+ type: 'string',
41
+ enum: [
42
+ 'id',
43
+ 'conversationId',
44
+ 'files',
45
+ 'sharedState'
46
+ ],
47
+ description: 'Field of the calling agent to return.'
48
+ },
49
+ default: {
50
+ description: 'Value to return when the endpoint was not called by an agent.'
51
+ },
52
+ all: {
53
+ type: 'boolean',
54
+ description: 'Return the calling agent as { id, conversationId, files, sharedState }, or null.'
55
+ }
56
+ },
57
+ additionalProperties: false
58
+ }
59
+ ]
60
+ }
61
+ };
@@ -0,0 +1,22 @@
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
+ */ // Marks every string in its value as a credential: the server writes [REDACTED] in its place in
16
+ // every log line for the rest of the request. The value itself is returned unchanged.
17
+ function _credential({ markCredential, params }) {
18
+ markCredential(params);
19
+ return params;
20
+ }
21
+ _credential.dynamic = true;
22
+ export default _credential;