@docupace/ihub-config 1.1.29 → 1.1.30

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 (37) hide show
  1. package/README.md +182 -182
  2. package/dist/config-service.d.ts.map +1 -1
  3. package/dist/config-service.js +30 -21
  4. package/dist/config-service.js.map +1 -1
  5. package/dist/model/graphs/config/common.graphql +7 -7
  6. package/dist/model/graphs/config/fields.graphql +454 -454
  7. package/dist/model/graphs/config/menu.graphql +60 -60
  8. package/dist/model/graphs/config/mutation.graphql +30 -30
  9. package/dist/model/graphs/config/page.graphql +283 -283
  10. package/dist/model/graphs/config/panel.graphql +43 -43
  11. package/dist/model/graphs/config/query.graphql +93 -93
  12. package/dist/model/graphs/config/rules.graphql +116 -116
  13. package/dist/model/graphs/config/selectOptions.graphql +48 -48
  14. package/dist/model/graphs/config/table.graphql +231 -231
  15. package/dist/model/graphs/config/tests.graphql +16 -16
  16. package/dist/model/graphs/config/theme.graphql +41 -41
  17. package/dist/model/graphs/config/ui-components.graphql +11 -11
  18. package/dist/model/graphs/domains/scalars.graphql +3 -3
  19. package/dist/model/graphs/filter.graphql +5 -5
  20. package/dist/model/graphs/schema.graphql +7 -7
  21. package/model/graphs/config/common.graphql +7 -7
  22. package/model/graphs/config/fields.graphql +454 -454
  23. package/model/graphs/config/menu.graphql +60 -60
  24. package/model/graphs/config/mutation.graphql +30 -30
  25. package/model/graphs/config/page.graphql +283 -283
  26. package/model/graphs/config/panel.graphql +43 -43
  27. package/model/graphs/config/query.graphql +93 -93
  28. package/model/graphs/config/rules.graphql +116 -116
  29. package/model/graphs/config/selectOptions.graphql +48 -48
  30. package/model/graphs/config/table.graphql +231 -231
  31. package/model/graphs/config/tests.graphql +16 -16
  32. package/model/graphs/config/theme.graphql +41 -41
  33. package/model/graphs/config/ui-components.graphql +11 -11
  34. package/model/graphs/domains/scalars.graphql +3 -3
  35. package/model/graphs/filter.graphql +5 -5
  36. package/model/graphs/schema.graphql +7 -7
  37. package/package.json +83 -81
package/README.md CHANGED
@@ -1,182 +1,182 @@
1
- # @docupace/ihub-config
2
-
3
- Reusable GraphQL config extension and standalone server extracted from the
4
- Docupace GraphQL server.
5
-
6
- ## Run locally
7
-
8
- ```bash
9
- pnpm install
10
- ```
11
-
12
- To run the package as a standalone GraphQL server, copy
13
- `.env.example` to `.env`, fill in the required values, and start the dev
14
- server:
15
-
16
- ```bash
17
- cp .env.example .env
18
- pnpm start:dev
19
- ```
20
-
21
- The standalone server listens on `http://localhost:4000/api/graphql`.
22
-
23
- ## Use as an extension in another server
24
-
25
- ```ts
26
- import { getConfigExtension } from '@docupace/ihub-config';
27
- ```
28
-
29
- Then add the returned extension to the host server's extensions array:
30
-
31
- ```ts
32
- const configExtension = await getConfigExtension();
33
-
34
- const serverInfo: ServerConfig = {
35
- instanceConfig: instanceConfig,
36
- extensions: [docupaceExtension, configExtension],
37
- port: 4000,
38
- createContext,
39
- };
40
- ```
41
-
42
- Extend the config extension with domain-specific providers, resolvers, etc.
43
-
44
- ```ts
45
- import { getConfigExtension } from '@docupace/ihub-config';
46
- import {
47
- DashboardPageConfigProvider,
48
- TablePageConfigProvider,
49
- AnyPageConfigProvider,
50
- DetailsPageConfigProvider,
51
- } from './your-host-config-providers.js';
52
- import { configResolvers } from './your-host-config-resolvers.js';
53
-
54
- const APPLICATION_PREFERENCE_PREFIX = 'applicationPreference';
55
-
56
- const applicationPreferenceResolver = async (keys, context) => {
57
- const data = await loadApplicationPreferences(keys, context);
58
-
59
- const result: Record<string, string | undefined> = {};
60
- keys.forEach((key) => (result[key] = undefined));
61
- data.records.forEach((record: { name: string; value: string }) => {
62
- result[record.name] = record.value;
63
- });
64
-
65
- return result;
66
- };
67
-
68
- const configExtension = await getConfigExtension({
69
- configInjectorResolvers: {
70
- [APPLICATION_PREFERENCE_PREFIX]: applicationPreferenceResolver,
71
- },
72
- providers: {
73
- DashboardPage: DashboardPageConfigProvider,
74
- TablePage: TablePageConfigProvider,
75
- AnyPage: AnyPageConfigProvider,
76
- DetailsPage: DetailsPageConfigProvider,
77
- },
78
- resolvers: configResolvers,
79
- });
80
- ```
81
-
82
- ### `configInjectorResolvers`
83
-
84
- Use `configInjectorResolvers` to resolve template expressions embedded in config
85
- values, for example:
86
-
87
- ```ts
88
- $${applicationPreference:timezone}
89
- ```
90
-
91
- Each key in `configInjectorResolvers` is a template prefix, and each value is an
92
- async resolver function with this shape:
93
-
94
- ```ts
95
- type ResolverFunction = (
96
- keys: string[],
97
- context: any,
98
- ) => Promise<Record<string, any>>;
99
- ```
100
-
101
- When config processing encounters `$${prefix:key}`, it looks up the resolver for
102
- that `prefix`, batches the requested keys, and replaces the template with the
103
- resolved value. This is the right place to connect host-specific data sources
104
- such as application preferences, tenant settings, or user-scoped values.
105
-
106
- ### `providers`
107
-
108
- Use `providers` to register config processors by `__typename`. A provider runs
109
- after nested config values have been loaded and template expressions have been
110
- resolved, and can reshape or enrich the final config object before it is
111
- returned.
112
-
113
- ```ts
114
- providers: {
115
- DashboardPage: DashboardPageConfigProvider,
116
- TablePage: TablePageConfigProvider,
117
- AnyPage: AnyPageConfigProvider,
118
- DetailsPage: DetailsPageConfigProvider,
119
- }
120
- ```
121
-
122
- Each provider must be a class with a `processConfig` method:
123
-
124
- ```ts
125
- interface ConfigProvider {
126
- processConfig(config: any, configService: ConfigService, context: any): any;
127
- }
128
- ```
129
-
130
- This is useful for page-specific post-processing such as normalizing fragments,
131
- rewriting references, or deriving extra fields for a particular page type.
132
- Built-in providers are preserved and host providers are merged in on top.
133
-
134
- ### `resolvers`
135
-
136
- Use `resolvers` to extend the GraphQL API exposed by the config extension.
137
- Resolvers are provided as factories so they can receive the initialized
138
- `configService` instance:
139
-
140
- ```ts
141
- const configResolvers = {
142
- query: ({ configService }) => ({
143
- pages: () => ({
144
- myCustomPage: async (obj: { path: string }, context: any) => {
145
- return await configService.getDirectConfig(obj.path, context);
146
- },
147
- }),
148
- }),
149
- mutation: ({ configService }) => ({
150
- pages: () => ({
151
- refreshCustomConfig: async () => {
152
- await configService.init();
153
- return true;
154
- },
155
- }),
156
- }),
157
- };
158
- ```
159
-
160
- Host query and mutation resolvers are deep-merged with the built-in config
161
- resolvers, so you can add new fields without re-declaring the entire resolver
162
- tree. If the same field exists in both places, the host resolver wins.
163
-
164
- If you want to pass config stores programmatically instead of through
165
- environment variables, `getConfigExtension` also accepts `configStores` (usually used for tests only).
166
-
167
- ## Environment variables
168
-
169
- Config stores are discovered from environment variables grouped by prefix such
170
- as `STANDARD` or `SITE`:
171
-
172
- - `<PREFIX>_CONFIG_LOCAL_PATH`
173
- - `<PREFIX>_CONFIG_REMOTE_PATH`
174
- - `<PREFIX>_CONFIG_REMOTE_BRANCH`
175
- - `<PREFIX>_CONFIG_PRIORITY`
176
- - `<PREFIX>_CONFIG_NAME`
177
-
178
- `<PREFIX>_CONFIG_PRIORITY` is required for every configured store.
179
-
180
- `CONFIG_LOCAL_PATH_ROOT` can be used as a fallback base path when
181
- `<PREFIX>_CONFIG_LOCAL_PATH` is omitted, but the store still needs enough
182
- configuration to be discovered.
1
+ # @docupace/ihub-config
2
+
3
+ Reusable GraphQL config extension and standalone server extracted from the
4
+ Docupace GraphQL server.
5
+
6
+ ## Run locally
7
+
8
+ ```bash
9
+ pnpm install
10
+ ```
11
+
12
+ To run the package as a standalone GraphQL server, copy
13
+ `.env.example` to `.env`, fill in the required values, and start the dev
14
+ server:
15
+
16
+ ```bash
17
+ cp .env.example .env
18
+ pnpm start:dev
19
+ ```
20
+
21
+ The standalone server listens on `http://localhost:4000/api/graphql`.
22
+
23
+ ## Use as an extension in another server
24
+
25
+ ```ts
26
+ import { getConfigExtension } from '@docupace/ihub-config';
27
+ ```
28
+
29
+ Then add the returned extension to the host server's extensions array:
30
+
31
+ ```ts
32
+ const configExtension = await getConfigExtension();
33
+
34
+ const serverInfo: ServerConfig = {
35
+ instanceConfig: instanceConfig,
36
+ extensions: [docupaceExtension, configExtension],
37
+ port: 4000,
38
+ createContext,
39
+ };
40
+ ```
41
+
42
+ Extend the config extension with domain-specific providers, resolvers, etc.
43
+
44
+ ```ts
45
+ import { getConfigExtension } from '@docupace/ihub-config';
46
+ import {
47
+ DashboardPageConfigProvider,
48
+ TablePageConfigProvider,
49
+ AnyPageConfigProvider,
50
+ DetailsPageConfigProvider,
51
+ } from './your-host-config-providers.js';
52
+ import { configResolvers } from './your-host-config-resolvers.js';
53
+
54
+ const APPLICATION_PREFERENCE_PREFIX = 'applicationPreference';
55
+
56
+ const applicationPreferenceResolver = async (keys, context) => {
57
+ const data = await loadApplicationPreferences(keys, context);
58
+
59
+ const result: Record<string, string | undefined> = {};
60
+ keys.forEach((key) => (result[key] = undefined));
61
+ data.records.forEach((record: { name: string; value: string }) => {
62
+ result[record.name] = record.value;
63
+ });
64
+
65
+ return result;
66
+ };
67
+
68
+ const configExtension = await getConfigExtension({
69
+ configInjectorResolvers: {
70
+ [APPLICATION_PREFERENCE_PREFIX]: applicationPreferenceResolver,
71
+ },
72
+ providers: {
73
+ DashboardPage: DashboardPageConfigProvider,
74
+ TablePage: TablePageConfigProvider,
75
+ AnyPage: AnyPageConfigProvider,
76
+ DetailsPage: DetailsPageConfigProvider,
77
+ },
78
+ resolvers: configResolvers,
79
+ });
80
+ ```
81
+
82
+ ### `configInjectorResolvers`
83
+
84
+ Use `configInjectorResolvers` to resolve template expressions embedded in config
85
+ values, for example:
86
+
87
+ ```ts
88
+ $${applicationPreference:timezone}
89
+ ```
90
+
91
+ Each key in `configInjectorResolvers` is a template prefix, and each value is an
92
+ async resolver function with this shape:
93
+
94
+ ```ts
95
+ type ResolverFunction = (
96
+ keys: string[],
97
+ context: any,
98
+ ) => Promise<Record<string, any>>;
99
+ ```
100
+
101
+ When config processing encounters `$${prefix:key}`, it looks up the resolver for
102
+ that `prefix`, batches the requested keys, and replaces the template with the
103
+ resolved value. This is the right place to connect host-specific data sources
104
+ such as application preferences, tenant settings, or user-scoped values.
105
+
106
+ ### `providers`
107
+
108
+ Use `providers` to register config processors by `__typename`. A provider runs
109
+ after nested config values have been loaded and template expressions have been
110
+ resolved, and can reshape or enrich the final config object before it is
111
+ returned.
112
+
113
+ ```ts
114
+ providers: {
115
+ DashboardPage: DashboardPageConfigProvider,
116
+ TablePage: TablePageConfigProvider,
117
+ AnyPage: AnyPageConfigProvider,
118
+ DetailsPage: DetailsPageConfigProvider,
119
+ }
120
+ ```
121
+
122
+ Each provider must be a class with a `processConfig` method:
123
+
124
+ ```ts
125
+ interface ConfigProvider {
126
+ processConfig(config: any, configService: ConfigService, context: any): any;
127
+ }
128
+ ```
129
+
130
+ This is useful for page-specific post-processing such as normalizing fragments,
131
+ rewriting references, or deriving extra fields for a particular page type.
132
+ Built-in providers are preserved and host providers are merged in on top.
133
+
134
+ ### `resolvers`
135
+
136
+ Use `resolvers` to extend the GraphQL API exposed by the config extension.
137
+ Resolvers are provided as factories so they can receive the initialized
138
+ `configService` instance:
139
+
140
+ ```ts
141
+ const configResolvers = {
142
+ query: ({ configService }) => ({
143
+ pages: () => ({
144
+ myCustomPage: async (obj: { path: string }, context: any) => {
145
+ return await configService.getDirectConfig(obj.path, context);
146
+ },
147
+ }),
148
+ }),
149
+ mutation: ({ configService }) => ({
150
+ pages: () => ({
151
+ refreshCustomConfig: async () => {
152
+ await configService.init();
153
+ return true;
154
+ },
155
+ }),
156
+ }),
157
+ };
158
+ ```
159
+
160
+ Host query and mutation resolvers are deep-merged with the built-in config
161
+ resolvers, so you can add new fields without re-declaring the entire resolver
162
+ tree. If the same field exists in both places, the host resolver wins.
163
+
164
+ If you want to pass config stores programmatically instead of through
165
+ environment variables, `getConfigExtension` also accepts `configStores` (usually used for tests only).
166
+
167
+ ## Environment variables
168
+
169
+ Config stores are discovered from environment variables grouped by prefix such
170
+ as `STANDARD` or `SITE`:
171
+
172
+ - `<PREFIX>_CONFIG_LOCAL_PATH`
173
+ - `<PREFIX>_CONFIG_REMOTE_PATH`
174
+ - `<PREFIX>_CONFIG_REMOTE_BRANCH`
175
+ - `<PREFIX>_CONFIG_PRIORITY`
176
+ - `<PREFIX>_CONFIG_NAME`
177
+
178
+ `<PREFIX>_CONFIG_PRIORITY` is required for every configured store.
179
+
180
+ `CONFIG_LOCAL_PATH_ROOT` can be used as a fallback base path when
181
+ `<PREFIX>_CONFIG_LOCAL_PATH` is omitted, but the store still needs enough
182
+ configuration to be discovered.
@@ -1 +1 @@
1
- {"version":3,"file":"config-service.d.ts","sourceRoot":"","sources":["../src/config-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-service.d.ts","sourceRoot":"","sources":["../src/config-service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EAErB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AA8X5C,MAAM,WAAW,kBAAkB;IACjC;;8CAE0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;qDACiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,MAAM,EAClB,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAE,kBAAuB,GAC7C,MAAM,CAOR;AAED,MAAM,WAAW,WAAW;IAC1B,eAAe,IAAI,OAAO,CAAC;IAC3B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACxC,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IACtD,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,0BAA0B;IACzC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,YAAY,EAAE,iBAAiB,EAAE,CAAC;IAClC,uBAAuB,EAAE,sBAAsB,CAAC,yBAAyB,CAAC,CAAC;IAC3E,SAAS,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,sBAAsB,CAAC,mBAAmB,CAAC,CAAC;IAChE,SAAS,EAAE,sBAAsB,CAAC,WAAW,CAAC,CAAC;IAC/C,6BAA6B,EAAE,sBAAsB,CAAC,+BAA+B,CAAC,CAAC;CACxF;AAED,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAS;gBAE3B,MAAM,EAAE,iBAAiB;IAM9B,YAAY,IAAI,MAAM;IAItB,eAAe,IAAI,OAAO;YAInB,6BAA6B;YAkB7B,WAAW;IAcnB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB/C,YAAY,CAAC,QAAQ,EAAE,MAAM;IAO7B,SAAS,CAAC,UAAU,EAAE,MAAM;IAK5B,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAa/C,WAAW,CAAC,UAAU,EAAE,MAAM;IAS9B,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAgB5C,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,kBAAuB,GAC9B,OAAO,CAAC,OAAO,CAAC;IAYb,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,kBAAuB,GAC9B,OAAO,CAAC,GAAG,CAAC;IAeT,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,GAAG,EACX,MAAM,GAAE,kBAAuB,GAC9B,OAAO,CAAC,IAAI,CAAC;IAIV,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAW/B;AAED,cAAM,aAAa;IACjB,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAA0B;IAClE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkB;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IACtD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwB;IAClD,OAAO,CAAC,QAAQ,CAAC,6BAA6B,CAA0D;gBAGtG,KAAK,EAAE,KAAK,GAAG,SAAS,EACxB,YAAY,EAAE,WAAW,EAAE,EAC3B,gBAAgB,GAAE,sBAA2B;IAuB/C,OAAO,CAAC,qBAAqB;IAkB7B,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,MAAM;YAIA,kBAAkB;YAkBlB,uBAAuB;IAkBrC,OAAO,CAAC,uBAAuB;IAgB/B,OAAO,CAAC,wBAAwB;YAmClB,uBAAuB;YA6CvB,iBAAiB;IAQ/B,iBAAiB;IAwMX,aAAa,CACjB,MAAM,EAAE,GAAG,EACX,OAAO,EAAE,GAAG,EACZ,gBAAgB,CAAC,EAAE,OAAO,EAC1B,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,IAAI,GAClD,OAAO,CAAC,GAAG,CAAC;YAUD,iBAAiB;YAqDjB,uBAAuB;YA+CvB,4BAA4B;YAmB5B,qBAAqB;IAkB7B,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,GAAG,EACZ,MAAM,CAAC,EAAE,GAAG;IAYd,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,GAAG;IAuBlD,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;IAYzB,wBAAwB,CAC5B,MAAM,EAAE,GAAG,EACX,WAAW,EAAE,GAAG,EAChB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,GAAG,CAAC;YAkDD,qBAAqB;IA6D7B,aAAa,CACjB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,GAAG,EACZ,MAAM,GAAE,GAAQ,GACf,OAAO,CAAC,GAAG,CAAC;IAkBf,OAAO,CAAC,eAAe;IAsBjB,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,GAAG,GACZ,OAAO,CAAC;QACT,MAAM,EAAE,GAAG,CAAC;QACZ,gBAAgB,EAAE,qBAAqB,GAAG,IAAI,CAAC;QAC/C,KAAK,EAAE,qBAAqB,GAAG,IAAI,CAAC;KACrC,CAAC;IAiCI,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU/C,SAAS,CACb,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,GAAG,EACZ,MAAM,CAAC,EAAE,GAAG,EACZ,gBAAgB,CAAC,EAAE,OAAO;IAMtB,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,GAAG,EACZ,MAAM,CAAC,EAAE,GAAG,EACZ,gBAAgB,CAAC,EAAE,OAAO;IAiC5B,OAAO,CAAC,wBAAwB;IAqB1B,iBAAiB,CAAC,UAAU,EAAE,MAAM;IASpC,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,GAAG,EACX,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,GAAG,CAAC;IAMf,OAAO,CAAC,wBAAwB;IAOhC,OAAO,CAAC,uBAAuB;IA2B/B,OAAO,CAAC,sBAAsB;YAiChB,yBAAyB;YA6DzB,wBAAwB;IAiCtC,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,uBAAuB;IAkD/B,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,sBAAsB;IAuB9B,OAAO,CAAC,sBAAsB;IAyB9B,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,sBAAsB;IAc9B,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,sBAAsB;IAmB9B,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,6BAA6B;IAcrC,OAAO,CAAC,qBAAqB;IAOvB,aAAa,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAoC9D,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,GAAG,EACZ,aAAa,CAAC,EAAE,OAAO,EACvB,YAAY,CAAC,EAAE,GAAG;IA8Bd,IAAI;CAKX;AAED,eAAO,MAAM,oBAAoB,GAAI,2HAQlC,0BAA0B,KAAG,aAc/B,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -160,19 +160,28 @@ function expandRefOverrideElements(value, refRoot) {
160
160
  // *ordered* array of layers per jsonPath
161
161
  // (broadest to narrowest — see `ConfigurationOverrideResult.subPaths`), not
162
162
  // a single already-resolved value. The overlay uses only the narrowest
163
- // (last) layer, same approximation as before cascading existed: a catalog
164
- // like `$.predefinedColumns`/`$.predefinedFilters` is always saved as a full
165
- // replacement at a single scope in practice (never a partial patch spread
166
- // across tiers), so the narrowest present layer already *is* effectively
167
- // the whole value — exactly what this overlay used before this function
168
- // took an array at all.
163
+ // (last) layer — folded onto `config`'s own base value for that key, not
164
+ // substituted outright. That layer is a snapshot from whenever the catalog
165
+ // (e.g. `$.predefinedColumns`) was last fully replaced; a catalog entry
166
+ // added to the template afterward exists on `config` but not in the
167
+ // snapshot, so a plain substitution left any `$ref` into it unresolvable —
168
+ // dropped silently, same as a `$ref` to an actually-deleted entry. Folding
169
+ // gives it the same base fallback `$.predefinedColumns`'s own resolution
170
+ // already gets via `mergeSubPathOverrideValue`.
169
171
  function buildRefResolutionRoot(config, subPathPatch) {
170
172
  const overlay = {};
171
173
  for (const [jsonPath, layers] of Object.entries(subPathPatch)) {
172
174
  const topLevelMatch = /^\$\.([^.[]+)$/.exec(jsonPath);
173
- if (topLevelMatch && layers.length) {
174
- overlay[topLevelMatch[1]] = layers[layers.length - 1];
175
+ if (!topLevelMatch || !layers.length) {
176
+ continue;
175
177
  }
178
+ const key = topLevelMatch[1];
179
+ const narrowestLayer = layers.at(-1);
180
+ const baseValue = config[key];
181
+ overlay[key] =
182
+ isNamedObjectArray(baseValue) && isNamedObjectArray(narrowestLayer)
183
+ ? mergeNamedObjectArray(baseValue, narrowestLayer, isSelfContainedOverrideElement)
184
+ : narrowestLayer;
176
185
  }
177
186
  return { ...config, ...overlay };
178
187
  }
@@ -510,7 +519,7 @@ class ConfigService {
510
519
  appendTestConfigPaths(tests, basePath) {
511
520
  return tests.map((test) => ({
512
521
  ...test,
513
- configPath: path.join(basePath, test.configPath),
522
+ configPath: path.posix.join(basePath, test.configPath),
514
523
  }));
515
524
  }
516
525
  mapDataRecords(config) {
@@ -646,38 +655,38 @@ class ConfigService {
646
655
  ]);
647
656
  },
648
657
  get: async (_obj, context) => {
649
- return await this.getConfig(path.join('widgets/widgetA', 'widgets'), context, null, true);
658
+ return await this.getConfig(path.posix.join('widgets/widgetA', 'widgets'), context, null, true);
650
659
  },
651
660
  }),
652
661
  tests: () => ({
653
662
  list: async (obj, context) => {
654
- const tests = await this.getConfig(path.join('tests', obj.path), context, null, true);
663
+ const tests = await this.getConfig(path.posix.join('tests', obj.path), context, null, true);
655
664
  const filteredTests = this.filterConfigsBySearch(tests, obj.search, ['name', 'description']);
656
665
  const processedTests = this.appendTestConfigPaths(filteredTests, obj.path);
657
666
  return { items: processedTests };
658
667
  },
659
668
  getConfig: async (obj, context) => {
660
- return await this.getConfig(path.join('tests', obj.path), context, null, true);
669
+ return await this.getConfig(path.posix.join('tests', obj.path), context, null, true);
661
670
  },
662
671
  }),
663
672
  themes: () => ({
664
673
  get: async (obj, context) => {
665
- return await this.getConfig(path.join('themes', obj.path), context, null, true);
674
+ return await this.getConfig(path.posix.join('themes', obj.path), context, null, true);
666
675
  },
667
676
  }),
668
677
  data: () => ({
669
678
  list: async (obj) => {
670
- return await this.listDirectConfigs(path.join('data', obj.path));
679
+ return await this.listDirectConfigs(path.posix.join('data', obj.path));
671
680
  },
672
681
  get: async (obj, context) => {
673
- const config = await this.getDirectConfig(path.join('data', obj.path), context, null, true);
682
+ const config = await this.getDirectConfig(path.posix.join('data', obj.path), context, null, true);
674
683
  if (!Array.isArray(config)) {
675
684
  return null;
676
685
  }
677
686
  return this.mapDataRecords(config);
678
687
  },
679
688
  getSeedConfig: async (obj, context) => {
680
- return await this.getDirectConfig(path.join('data', obj.path), context, null, true);
689
+ return await this.getDirectConfig(path.posix.join('data', obj.path), context, null, true);
681
690
  },
682
691
  }),
683
692
  };
@@ -695,7 +704,7 @@ class ConfigService {
695
704
  },
696
705
  pages: () => ({
697
706
  updateDashboard: async (obj, context) => {
698
- const configPath = path.join('pages', 'dashboard');
707
+ const configPath = path.posix.join('pages', 'dashboard');
699
708
  return await this.updateConfig(configPath, {
700
709
  __typename: 'DashboardPage',
701
710
  ...obj.input,
@@ -990,7 +999,7 @@ class ConfigService {
990
999
  return (await Promise.all(this.configStores.map((configStore) => configStore.hasConfig(configPath)))).some(Boolean);
991
1000
  }
992
1001
  async getConfig(configPath, context, values, processProviders) {
993
- const globalPath = path.join('global', configPath);
1002
+ const globalPath = path.posix.join('global', configPath);
994
1003
  return this.getDirectConfig(globalPath, context, values, processProviders);
995
1004
  }
996
1005
  async getDirectConfig(configPath, context, values, processProviders) {
@@ -1034,7 +1043,7 @@ class ConfigService {
1034
1043
  return [...new Set(configs.flat())];
1035
1044
  }
1036
1045
  async updateConfig(configPath, config, context) {
1037
- const globalPath = path.join('global', configPath);
1046
+ const globalPath = path.posix.join('global', configPath);
1038
1047
  await this.configStores[0].updateConfig(globalPath, config);
1039
1048
  return await this.getConfig(configPath, context, null, true);
1040
1049
  }
@@ -1354,7 +1363,7 @@ class ConfigService {
1354
1363
  const allRuleGroups = [];
1355
1364
  for (const ruleFile of ruleFiles) {
1356
1365
  try {
1357
- const ruleGroups = await this.getDirectConfig(path.join('global', 'rules', ruleFile), context, null, false);
1366
+ const ruleGroups = await this.getDirectConfig(path.posix.join('global', 'rules', ruleFile), context, null, false);
1358
1367
  if (Array.isArray(ruleGroups)) {
1359
1368
  allRuleGroups.push(...ruleGroups);
1360
1369
  }
@@ -1376,7 +1385,7 @@ class ConfigService {
1376
1385
  });
1377
1386
  }
1378
1387
  async getPageConfig(pagePath, context, processConfig, rulesContext) {
1379
- const globalPath = path.join('global', 'pages', pagePath);
1388
+ const globalPath = path.posix.join('global', 'pages', pagePath);
1380
1389
  const { config: obj, subPathOverrides, whole, } = await this.getConfigFromStore(globalPath, context);
1381
1390
  const fullObj = await this.processObject(globalPath, obj, context, null);
1382
1391
  const matchingRuleGroups = await this.getRuleGroups(rulesContext, context);