@salesforce/b2c-tooling-sdk 2.3.0 → 2.5.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 (203) hide show
  1. package/data/guides/enrichment.json +291 -0
  2. package/data/guides/index.json +426 -37
  3. package/data/schemas/dw.schema.json +590 -0
  4. package/data/tooling/index.json +18 -9
  5. package/dist/esm/cli/base-command.d.ts +20 -1
  6. package/dist/esm/cli/base-command.js +61 -11
  7. package/dist/esm/cli/base-command.js.map +1 -1
  8. package/dist/esm/cli/cartridge-command.js +2 -1
  9. package/dist/esm/cli/cartridge-command.js.map +1 -1
  10. package/dist/esm/cli/command-search.d.ts +85 -0
  11. package/dist/esm/cli/command-search.js +147 -0
  12. package/dist/esm/cli/command-search.js.map +1 -0
  13. package/dist/esm/cli/config.d.ts +10 -1
  14. package/dist/esm/cli/config.js +18 -9
  15. package/dist/esm/cli/config.js.map +1 -1
  16. package/dist/esm/cli/hooks.d.ts +13 -0
  17. package/dist/esm/cli/hooks.js +11 -0
  18. package/dist/esm/cli/hooks.js.map +1 -1
  19. package/dist/esm/cli/index.d.ts +2 -0
  20. package/dist/esm/cli/index.js +2 -0
  21. package/dist/esm/cli/index.js.map +1 -1
  22. package/dist/esm/cli/instance-command.d.ts +1 -0
  23. package/dist/esm/cli/instance-command.js +2 -1
  24. package/dist/esm/cli/instance-command.js.map +1 -1
  25. package/dist/esm/cli/mrt-command.d.ts +3 -2
  26. package/dist/esm/cli/mrt-command.js +4 -4
  27. package/dist/esm/cli/mrt-command.js.map +1 -1
  28. package/dist/esm/cli/oauth-command.d.ts +1 -0
  29. package/dist/esm/cli/ods-command.d.ts +1 -0
  30. package/dist/esm/cli/webdav-command.d.ts +1 -0
  31. package/dist/esm/clients/custom-apis.d.ts +36 -2
  32. package/dist/esm/clients/custom-apis.js +57 -4
  33. package/dist/esm/clients/custom-apis.js.map +1 -1
  34. package/dist/esm/clients/index.d.ts +1 -1
  35. package/dist/esm/clients/index.js +1 -1
  36. package/dist/esm/clients/index.js.map +1 -1
  37. package/dist/esm/clients/scapi-backend-utils.d.ts +15 -0
  38. package/dist/esm/clients/scapi-backend-utils.js +28 -1
  39. package/dist/esm/clients/scapi-backend-utils.js.map +1 -1
  40. package/dist/esm/clients/scapi-fallback-backend.js +2 -2
  41. package/dist/esm/clients/scapi-fallback-backend.js.map +1 -1
  42. package/dist/esm/clients/scapi-schemas.generated.d.ts +2 -2
  43. package/dist/esm/compat/dispatcher.js +2 -2
  44. package/dist/esm/compat/dispatcher.js.map +1 -1
  45. package/dist/esm/config/config-origins.d.ts +19 -0
  46. package/dist/esm/config/config-origins.js +11 -0
  47. package/dist/esm/config/config-origins.js.map +1 -0
  48. package/dist/esm/config/config-write.d.ts +86 -0
  49. package/dist/esm/config/config-write.js +296 -0
  50. package/dist/esm/config/config-write.js.map +1 -0
  51. package/dist/esm/config/dw-json-schema.d.ts +14 -0
  52. package/dist/esm/config/dw-json-schema.js +269 -0
  53. package/dist/esm/config/dw-json-schema.js.map +1 -0
  54. package/dist/esm/config/dw-json.d.ts +2 -0
  55. package/dist/esm/config/dw-json.js +10 -6
  56. package/dist/esm/config/dw-json.js.map +1 -1
  57. package/dist/esm/config/index.d.ts +13 -4
  58. package/dist/esm/config/index.js +8 -3
  59. package/dist/esm/config/index.js.map +1 -1
  60. package/dist/esm/config/instance-manager.d.ts +64 -28
  61. package/dist/esm/config/instance-manager.js +145 -63
  62. package/dist/esm/config/instance-manager.js.map +1 -1
  63. package/dist/esm/config/mapping.d.ts +5 -0
  64. package/dist/esm/config/mapping.js +20 -1
  65. package/dist/esm/config/mapping.js.map +1 -1
  66. package/dist/esm/config/project-environment.d.ts +62 -0
  67. package/dist/esm/config/project-environment.js +113 -0
  68. package/dist/esm/config/project-environment.js.map +1 -1
  69. package/dist/esm/config/resolver.d.ts +22 -0
  70. package/dist/esm/config/resolver.js +106 -37
  71. package/dist/esm/config/resolver.js.map +1 -1
  72. package/dist/esm/config/sources/dw-json-source.d.ts +9 -1
  73. package/dist/esm/config/sources/dw-json-source.js +59 -23
  74. package/dist/esm/config/sources/dw-json-source.js.map +1 -1
  75. package/dist/esm/config/sources/env-source.d.ts +70 -9
  76. package/dist/esm/config/sources/env-source.js +205 -47
  77. package/dist/esm/config/sources/env-source.js.map +1 -1
  78. package/dist/esm/config/sources/index.d.ts +1 -1
  79. package/dist/esm/config/sources/index.js +1 -1
  80. package/dist/esm/config/sources/index.js.map +1 -1
  81. package/dist/esm/config/types.d.ts +53 -3
  82. package/dist/esm/docs/search.js +3 -1
  83. package/dist/esm/docs/search.js.map +1 -1
  84. package/dist/esm/docs/types.d.ts +3 -1
  85. package/dist/esm/guidance/bundle.d.ts +33 -0
  86. package/dist/esm/guidance/bundle.js +268 -0
  87. package/dist/esm/guidance/bundle.js.map +1 -0
  88. package/dist/esm/guidance/catalog.d.ts +8 -1
  89. package/dist/esm/guidance/catalog.js +48 -6
  90. package/dist/esm/guidance/catalog.js.map +1 -1
  91. package/dist/esm/guidance/index.d.ts +1 -0
  92. package/dist/esm/guidance/index.js +1 -0
  93. package/dist/esm/guidance/index.js.map +1 -1
  94. package/dist/esm/guidance/types.d.ts +17 -1
  95. package/dist/esm/guidance/types.js.map +1 -1
  96. package/dist/esm/index.d.ts +1 -1
  97. package/dist/esm/index.js +1 -1
  98. package/dist/esm/index.js.map +1 -1
  99. package/dist/esm/operations/jobs/run-system-job.js +2 -2
  100. package/dist/esm/operations/jobs/run-system-job.js.map +1 -1
  101. package/dist/esm/plugins/discovery.js +2 -1
  102. package/dist/esm/plugins/discovery.js.map +1 -1
  103. package/dist/esm/scapi/catalog.d.ts +5 -2
  104. package/dist/esm/scapi/catalog.js.map +1 -1
  105. package/dist/esm/scapi/index.d.ts +6 -2
  106. package/dist/esm/scapi/index.js +4 -2
  107. package/dist/esm/scapi/index.js.map +1 -1
  108. package/dist/esm/scapi/live.d.ts +14 -3
  109. package/dist/esm/scapi/live.js +33 -5
  110. package/dist/esm/scapi/live.js.map +1 -1
  111. package/dist/esm/scapi/local.d.ts +26 -0
  112. package/dist/esm/scapi/local.js +143 -0
  113. package/dist/esm/scapi/local.js.map +1 -0
  114. package/dist/esm/scapi/request.d.ts +2 -2
  115. package/dist/esm/scapi/request.js +4 -2
  116. package/dist/esm/scapi/request.js.map +1 -1
  117. package/dist/esm/scapi/runtime.d.ts +5 -0
  118. package/dist/esm/scapi/runtime.js.map +1 -1
  119. package/dist/esm/scapi/schema-source.d.ts +90 -0
  120. package/dist/esm/scapi/schema-source.js +146 -0
  121. package/dist/esm/scapi/schema-source.js.map +1 -0
  122. package/dist/esm/scapi/worker-source.js +31 -7
  123. package/dist/esm/scapi/worker-source.js.map +1 -1
  124. package/dist/esm/telemetry/telemetry.d.ts +1 -0
  125. package/dist/esm/telemetry/telemetry.js +18 -1
  126. package/dist/esm/telemetry/telemetry.js.map +1 -1
  127. package/dist/esm/telemetry/types.d.ts +9 -0
  128. package/dist/esm/test-utils/config-isolation.js +21 -15
  129. package/dist/esm/test-utils/config-isolation.js.map +1 -1
  130. package/dist/esm/ux/agent-context.d.ts +69 -0
  131. package/dist/esm/ux/agent-context.js +133 -0
  132. package/dist/esm/ux/agent-context.js.map +1 -0
  133. package/dist/esm/ux/confirm.d.ts +27 -0
  134. package/dist/esm/ux/confirm.js +32 -0
  135. package/dist/esm/ux/confirm.js.map +1 -1
  136. package/dist/esm/ux/index.d.ts +2 -1
  137. package/dist/esm/ux/index.js +2 -1
  138. package/dist/esm/ux/index.js.map +1 -1
  139. package/node_modules/@salesforce/b2c-api-schemas/manifest.json +83 -42
  140. package/node_modules/@salesforce/b2c-api-schemas/package.json +1 -1
  141. package/node_modules/@salesforce/b2c-api-schemas/scapi/cdn/zones/v1.json +6798 -238
  142. package/node_modules/@salesforce/b2c-api-schemas/scapi/checkout/orders/v1.json +2296 -205
  143. package/node_modules/@salesforce/b2c-api-schemas/scapi/checkout/shopper-baskets/v1.json +5571 -666
  144. package/node_modules/@salesforce/b2c-api-schemas/scapi/checkout/shopper-baskets/v2.json +6062 -371
  145. package/node_modules/@salesforce/b2c-api-schemas/scapi/checkout/shopper-orders/v1.json +3426 -360
  146. package/node_modules/@salesforce/b2c-api-schemas/scapi/checkout/shopper-payments/v1.json +351 -99
  147. package/node_modules/@salesforce/b2c-api-schemas/scapi/configuration/cors/v1.json +172 -12
  148. package/node_modules/@salesforce/b2c-api-schemas/scapi/configuration/preferences/v1.json +1497 -111
  149. package/node_modules/@salesforce/b2c-api-schemas/scapi/configuration/shopper-configurations/v1.json +202 -36
  150. package/node_modules/@salesforce/b2c-api-schemas/scapi/configuration/timeouts/v1.json +79 -10
  151. package/node_modules/@salesforce/b2c-api-schemas/scapi/custom-object/custom-objects/v1.json +785 -49
  152. package/node_modules/@salesforce/b2c-api-schemas/scapi/custom-object/shopper-custom-objects/v1.json +191 -40
  153. package/node_modules/@salesforce/b2c-api-schemas/scapi/customer/customers/v1.json +1483 -107
  154. package/node_modules/@salesforce/b2c-api-schemas/scapi/customer/shopper-customers/v1.json +4854 -787
  155. package/node_modules/@salesforce/b2c-api-schemas/scapi/dx/custom-apis/v1.json +119 -15
  156. package/node_modules/@salesforce/b2c-api-schemas/scapi/dx/object-definitions/v1.json +1699 -80
  157. package/node_modules/@salesforce/b2c-api-schemas/scapi/dx/scapi-schemas/v1.json +252 -18
  158. package/node_modules/@salesforce/b2c-api-schemas/scapi/dx/scripts/v1.json +329 -23
  159. package/node_modules/@salesforce/b2c-api-schemas/scapi/experience/experiences/v1.json +4208 -234
  160. package/node_modules/@salesforce/b2c-api-schemas/scapi/experience/shopper-experience/v1.json +1591 -247
  161. package/node_modules/@salesforce/b2c-api-schemas/scapi/intelligence/analytics/v1.json +396 -8
  162. package/node_modules/@salesforce/b2c-api-schemas/scapi/inventory/availability/v1.json +1242 -69
  163. package/node_modules/@salesforce/b2c-api-schemas/scapi/inventory/impex/v1.json +2354 -248
  164. package/node_modules/@salesforce/b2c-api-schemas/scapi/inventory/reservation/v1.json +1550 -45
  165. package/node_modules/@salesforce/b2c-api-schemas/scapi/inventory/segmentation/v1.json +6615 -0
  166. package/node_modules/@salesforce/b2c-api-schemas/scapi/merchant/roles/v1.json +1520 -59
  167. package/node_modules/@salesforce/b2c-api-schemas/scapi/merchant/users/v1.json +397 -17
  168. package/node_modules/@salesforce/b2c-api-schemas/scapi/observability/metrics/v1.json +1241 -27
  169. package/node_modules/@salesforce/b2c-api-schemas/scapi/operation/jobs/v1.json +1069 -68
  170. package/node_modules/@salesforce/b2c-api-schemas/scapi/operation/replications/v1.json +410 -23
  171. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/assignments/v1.json +502 -102
  172. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/campaigns/v1.json +1112 -94
  173. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/coupons/v1.json +820 -93
  174. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/gift-certificates/v1.json +845 -92
  175. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/promotions/v1.json +2716 -674
  176. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/shopper-gift-certificates/v1.json +130 -47
  177. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/shopper-promotions/v1.json +233 -63
  178. package/node_modules/@salesforce/b2c-api-schemas/scapi/pricing/source-code-groups/v1.json +630 -70
  179. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/catalogs/v1.json +2886 -348
  180. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/inventory-lists/v1.json +520 -19
  181. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/price-books/v1.json +3115 -293
  182. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/products/v1.json +3313 -138
  183. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/shopper-availability/v1.json +266 -52
  184. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/shopper-delivery-estimates/v1.json +256 -48
  185. package/node_modules/@salesforce/b2c-api-schemas/scapi/product/shopper-products/v1.json +1744 -306
  186. package/node_modules/@salesforce/b2c-api-schemas/scapi/search/shopper-search/v1.json +1661 -120
  187. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/auth/v1.json +2174 -118
  188. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/auth-admin/v1.json +1373 -24
  189. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/consents/v1.json +531 -20
  190. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/shopper-agents/v1.json +154 -6
  191. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/shopper-consents/v1.json +596 -79
  192. package/node_modules/@salesforce/b2c-api-schemas/scapi/shopper/shopper-context/v1.json +456 -42
  193. package/node_modules/@salesforce/b2c-api-schemas/scapi/site/seo/v1.json +101 -23
  194. package/node_modules/@salesforce/b2c-api-schemas/scapi/site/shopper-seo/v1.json +184 -41
  195. package/node_modules/@salesforce/b2c-api-schemas/scapi/site/sites/v1.json +995 -47
  196. package/node_modules/@salesforce/b2c-api-schemas/scapi/store/shopper-stores/v1.json +370 -67
  197. package/node_modules/@salesforce/b2c-api-schemas/scapi/store/store-redirect-mappings/v1.json +319 -11
  198. package/node_modules/@salesforce/b2c-api-schemas/scapi/store/stores/v1.json +1109 -64
  199. package/node_modules/@salesforce/b2c-api-schemas/scapi/storefront/deployments/v1.json +1442 -0
  200. package/node_modules/@salesforce/b2c-api-schemas/scapi/storefront/environments/v1.json +4293 -0
  201. package/node_modules/@salesforce/b2c-api-schemas/scapi/storefront/storefronts/v1.json +1371 -0
  202. package/package.json +5 -2
  203. package/specs/scapi-schemas-v1.yaml +4 -1
@@ -0,0 +1,296 @@
1
+ /*
2
+ * Copyright (c) 2025, Salesforce, Inc.
3
+ * SPDX-License-Identifier: Apache-2
4
+ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+ /**
7
+ * Read and write individual configuration fields at the source that supplies them.
8
+ *
9
+ * Writes go to the highest-priority source currently supplying a field, so the
10
+ * new value always takes effect. A field no source supplies goes to the entry
11
+ * that selected the instance (for example the active dw.json config). Sources
12
+ * that don't implement {@link ConfigSource.updateConfig} (shell environment,
13
+ * ~/.mobify, package.json) are never written; credential stores are written
14
+ * through {@link ConfigSource.storeCredential} for their declared fields.
15
+ *
16
+ * @module config/config-write
17
+ */
18
+ import { getConfigOrigins } from './config-origins.js';
19
+ import { DW_JSON_FIELDS } from './dw-json-schema.js';
20
+ import { CONFIG_KEY_ALIASES, kebabToCamelCase } from './mapping.js';
21
+ import { CREDENTIAL_GROUPS } from './resolver.js';
22
+ /** dw.json keys whose normalized field has a different name. */
23
+ const FIELD_RENAMES = { oauthScopes: 'scopes' };
24
+ /** dw.json keys managed by other commands (`setup instance ...`) or shorthands of another key. */
25
+ const UNSETTABLE_KEYS = new Set(['name', 'active', 'user-auth']);
26
+ /** Error raised when a configuration field can't be read or written safely. */
27
+ export class ConfigWriteError extends Error {
28
+ code;
29
+ constructor(code, message) {
30
+ super(message);
31
+ this.code = code;
32
+ this.name = 'ConfigWriteError';
33
+ }
34
+ }
35
+ function camelToKebabCase(value) {
36
+ return value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
37
+ }
38
+ /** All keys `setup set` accepts, in dw.json order. */
39
+ export function listConfigKeys() {
40
+ return Object.entries(DW_JSON_FIELDS)
41
+ .filter(([key]) => !UNSETTABLE_KEYS.has(key))
42
+ .map(([key, schema]) => {
43
+ const dwKey = kebabToCamelCase(key);
44
+ return { key, field: (FIELD_RENAMES[dwKey] ?? dwKey), schema };
45
+ });
46
+ }
47
+ /**
48
+ * Resolve a user-supplied key (dw.json kebab-case, camelCase, a legacy alias,
49
+ * or the normalized field name) to a settable configuration key.
50
+ *
51
+ * @throws ConfigWriteError for unknown or unsettable keys
52
+ */
53
+ export function resolveConfigKey(input) {
54
+ const trimmed = input.trim();
55
+ const canonical = CONFIG_KEY_ALIASES[trimmed] ?? kebabToCamelCase(trimmed);
56
+ const key = camelToKebabCase(canonical);
57
+ if (UNSETTABLE_KEYS.has(key)) {
58
+ throw new ConfigWriteError('CONFIG_KEY_UNKNOWN', key === 'user-auth'
59
+ ? '`user-auth` is shorthand for `auth-methods`; set `auth-methods` instead.'
60
+ : `\`${key}\` is managed by \`b2c setup instance\` commands.`);
61
+ }
62
+ const found = listConfigKeys().find((entry) => entry.key === key || entry.field === canonical);
63
+ if (!found) {
64
+ throw new ConfigWriteError('CONFIG_KEY_UNKNOWN', `Unknown configuration key "${input}". Keys use dw.json names, for example: ${listConfigKeys()
65
+ .slice(0, 6)
66
+ .map((entry) => entry.key)
67
+ .join(', ')}.`);
68
+ }
69
+ return found;
70
+ }
71
+ function describeSchema(schema) {
72
+ if (Array.isArray(schema.oneOf))
73
+ return schema.oneOf.map(describeSchema).join(' or ');
74
+ if (Array.isArray(schema.enum))
75
+ return `one of ${schema.enum.join(', ')}`;
76
+ if (schema.type === 'array' && schema.items)
77
+ return `array of ${describeSchema(schema.items)}`;
78
+ return String(schema.type ?? 'value');
79
+ }
80
+ /** Validate a value against the JSON Schema subset used by the dw.json schema. */
81
+ function validate(schema, value, path) {
82
+ if (Array.isArray(schema.oneOf)) {
83
+ const options = schema.oneOf;
84
+ return options.some((option) => validate(option, value, path) === undefined)
85
+ ? undefined
86
+ : `${path} must be ${describeSchema(schema)}`;
87
+ }
88
+ switch (schema.type) {
89
+ case 'array': {
90
+ if (!Array.isArray(value))
91
+ return `${path} must be an array`;
92
+ for (const [index, item] of value.entries()) {
93
+ const error = schema.items ? validate(schema.items, item, `${path}[${index}]`) : undefined;
94
+ if (error)
95
+ return error;
96
+ }
97
+ break;
98
+ }
99
+ case 'boolean': {
100
+ if (typeof value !== 'boolean')
101
+ return `${path} must be true or false`;
102
+ break;
103
+ }
104
+ case 'object': {
105
+ if (!value || typeof value !== 'object' || Array.isArray(value))
106
+ return `${path} must be a JSON object`;
107
+ const record = value;
108
+ const properties = (schema.properties ?? {});
109
+ for (const required of schema.required ?? []) {
110
+ if (record[required] === undefined)
111
+ return `${path}.${required} is required`;
112
+ }
113
+ for (const [name, item] of Object.entries(record)) {
114
+ if (!properties[name]) {
115
+ if (schema.additionalProperties === false)
116
+ return `${path}.${name} is not a known property`;
117
+ continue;
118
+ }
119
+ const error = validate(properties[name], item, `${path}.${name}`);
120
+ if (error)
121
+ return error;
122
+ }
123
+ break;
124
+ }
125
+ case 'string': {
126
+ if (typeof value !== 'string')
127
+ return `${path} must be a string`;
128
+ break;
129
+ }
130
+ }
131
+ if (Array.isArray(schema.enum) && !schema.enum.includes(value)) {
132
+ return `${path} must be ${describeSchema(schema)}`;
133
+ }
134
+ return undefined;
135
+ }
136
+ function acceptsStringList(schema) {
137
+ if (Array.isArray(schema.oneOf))
138
+ return schema.oneOf.some(acceptsStringList);
139
+ return schema.type === 'array' && schema.items?.type === 'string';
140
+ }
141
+ /**
142
+ * Coerce a command-line value to the key's type.
143
+ *
144
+ * String keys keep the text as given. Other keys accept JSON (`true`,
145
+ * `["a","b"]`, `{"level":"NO_DELETE"}`); string-list keys also accept a
146
+ * plain or comma-separated value (`./schemas` becomes `["./schemas"]`).
147
+ *
148
+ * @throws ConfigWriteError when the value doesn't match the key's schema
149
+ */
150
+ export function parseConfigValue(key, raw) {
151
+ const candidates = [];
152
+ if (key.schema.type === 'string') {
153
+ candidates.push(raw);
154
+ }
155
+ else {
156
+ try {
157
+ candidates.push(JSON.parse(raw));
158
+ }
159
+ catch {
160
+ // Not JSON; fall through to the plain-text forms below.
161
+ }
162
+ if (acceptsStringList(key.schema)) {
163
+ candidates.push(raw
164
+ .split(',')
165
+ .map((item) => item.trim())
166
+ .filter(Boolean));
167
+ }
168
+ }
169
+ let error;
170
+ for (const candidate of candidates) {
171
+ error = validate(key.schema, candidate, key.key);
172
+ if (!error)
173
+ return candidate;
174
+ }
175
+ throw new ConfigWriteError('CONFIG_VALUE_INVALID', `Invalid value for ${key.key}: ${error ?? `expected ${describeSchema(key.schema)}`}.`);
176
+ }
177
+ function describeSource(info) {
178
+ return info.location ? `${info.name} (${info.location})` : info.name;
179
+ }
180
+ /**
181
+ * Whether a source can persist `field`: through {@link ConfigSource.updateConfig},
182
+ * or for a credential store, {@link ConfigSource.storeCredential} for a declared
183
+ * credential field.
184
+ */
185
+ function canWrite(origin, field) {
186
+ const { source } = origin;
187
+ return Boolean(source.updateConfig || (source.storeCredential && source.credentialFields?.includes(field)));
188
+ }
189
+ /**
190
+ * Locate a field in a resolved configuration: which source supplies it and
191
+ * which source a write should update.
192
+ *
193
+ * The target is, in order: the source supplying the field; the source
194
+ * supplying the other half of its credential pair; or, for a field nothing
195
+ * sets, the source that supplied the instance itself (its `instanceName`, else
196
+ * its `hostname`). A derived value (a sandbox hostname worked out from its
197
+ * tenant ID) counts as supplied by the source of the field it came from. Every
198
+ * rule uses only {@link ConfigSourceInfo} and the optional write methods, so
199
+ * plugin sources take part the same way dw.json does.
200
+ */
201
+ export function locateConfigField(config, field) {
202
+ const origins = getConfigOrigins(config) ?? [];
203
+ const supplies = (info, name) => info.fields.includes(name) && !info.fieldsIgnored?.includes(name);
204
+ /** The origin supplying `name`, following a derived value back to the origin of its base field. */
205
+ const originOf = (name) => {
206
+ const direct = origins.find((origin) => supplies(origin.info, name));
207
+ if (direct)
208
+ return direct;
209
+ const base = config.sources.find((info) => info.derivedFrom && supplies(info, name))?.derivedFrom?.field;
210
+ return base ? origins.find((origin) => supplies(origin.info, base)) : undefined;
211
+ };
212
+ const supplier = config.sources.find((info) => supplies(info, field));
213
+ // A credential pair (client ID + secret) must come from one source, so the
214
+ // other half of a supplied pair decides where this field goes.
215
+ const partners = CREDENTIAL_GROUPS.find((group) => group.includes(field)) ?? [field];
216
+ const own = originOf(field);
217
+ const supplying = own ?? partners.map(originOf).find(Boolean);
218
+ if (supplying) {
219
+ if (!canWrite(supplying, field)) {
220
+ return {
221
+ supplier: own?.info,
222
+ error: new ConfigWriteError('CONFIG_SOURCE_READ_ONLY', own
223
+ ? `${field} comes from ${describeSource(supplying.info)}, which can't be written. Change or remove it there.`
224
+ : `${field} pairs with ${partners.filter((partner) => partner !== field).join(', ')} from ${describeSource(supplying.info)}, which can't be written. Set both there.`),
225
+ };
226
+ }
227
+ return { supplier, target: supplying };
228
+ }
229
+ if (supplier || config.values[field] !== undefined) {
230
+ const base = supplier?.derivedFrom;
231
+ return {
232
+ supplier,
233
+ error: new ConfigWriteError('CONFIG_SOURCE_READ_ONLY', base
234
+ ? `${field} is derived from ${base.field}${base.source ? '' : ' given as a flag'}, so it can't be written here.`
235
+ : `${field} comes from ${supplier ? describeSource(supplier) : 'a command-line flag'}, which can't be written.`),
236
+ };
237
+ }
238
+ // Nothing supplies the field: write it where the instance itself is defined.
239
+ const instanceOrigin = originOf('instanceName') ?? originOf('hostname');
240
+ if (instanceOrigin && canWrite(instanceOrigin, field))
241
+ return { target: instanceOrigin };
242
+ return {
243
+ error: new ConfigWriteError('CONFIG_NO_WRITE_TARGET', instanceOrigin
244
+ ? `${field} isn't set, and ${describeSource(instanceOrigin.info)} can't store it.`
245
+ : `${field} isn't set and no instance is selected to write it to. Select one with --instance, mark one active with \`b2c setup instance set-active\`, or create one with \`b2c setup instance create\`.`),
246
+ };
247
+ }
248
+ /** Persist one field through whichever write method the target source implements. */
249
+ async function persist(config, { source, info, options }, field, value) {
250
+ if (source.updateConfig)
251
+ return source.updateConfig({ [field]: value }, options);
252
+ const instance = config.values.instanceName ?? options.instance;
253
+ if (!instance) {
254
+ throw new ConfigWriteError('CONFIG_NO_WRITE_TARGET', `${source.name} stores credentials per instance, and no instance name is selected. Use --instance.`);
255
+ }
256
+ if (value === undefined) {
257
+ if (!source.removeCredential) {
258
+ throw new ConfigWriteError('CONFIG_SOURCE_READ_ONLY', `${source.name} can't remove ${field}.`);
259
+ }
260
+ await source.removeCredential(instance, field, options);
261
+ }
262
+ else {
263
+ if (typeof value !== 'string')
264
+ throw new ConfigWriteError('CONFIG_VALUE_INVALID', `${field} must be a string.`);
265
+ await source.storeCredential(instance, field, value, options);
266
+ }
267
+ return { location: info.location ?? source.name, instance };
268
+ }
269
+ /**
270
+ * Set or remove (`value === undefined`) a field at the source that supplies it.
271
+ *
272
+ * @throws ConfigWriteError when the field has no writable target
273
+ */
274
+ export async function writeConfigField(config, field, value) {
275
+ const location = locateConfigField(config, field);
276
+ if (value === undefined && !location.supplier) {
277
+ throw new ConfigWriteError('CONFIG_NOT_SET', `${field} isn't set.`);
278
+ }
279
+ const base = value === undefined ? location.supplier?.derivedFrom : undefined;
280
+ if (base) {
281
+ throw new ConfigWriteError('CONFIG_NOT_SET', `${field} isn't set; it's derived from ${base.field}${base.source ? ` in ${base.source}` : ''}. Unset ${base.field} instead.`);
282
+ }
283
+ if (!location.target)
284
+ throw location.error;
285
+ const result = await persist(config, location.target, field, value);
286
+ return { ...result, source: location.target.source.name };
287
+ }
288
+ /**
289
+ * Remove a field from the source that supplies it.
290
+ *
291
+ * @throws ConfigWriteError when the field isn't set or its source can't be written
292
+ */
293
+ export async function removeConfigField(config, field) {
294
+ return writeConfigField(config, field, undefined);
295
+ }
296
+ //# sourceMappingURL=config-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-write.js","sourceRoot":"","sources":["../../../src/config/config-write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** A JSON Schema fragment (draft-07 subset). */
2
+ export type JsonSchema = Record<string, unknown>;
3
+ /** Public URL of the published schema (usable as `"$schema"` in dw.json). */
4
+ export declare const DW_JSON_SCHEMA_URL = "https://salesforcecommercecloud.github.io/b2c-developer-tooling/schemas/dw.schema.json";
5
+ /**
6
+ * Canonical instance-level fields keyed by kebab-case name (the on-disk spelling).
7
+ * Descriptions mirror the Settings Reference in the configuration guide.
8
+ */
9
+ export declare const DW_JSON_FIELDS: Record<string, JsonSchema>;
10
+ /**
11
+ * Builds the `dw.json` JSON Schema from {@link DW_JSON_FIELDS}, adding the
12
+ * camelCase spelling and legacy aliases for every field.
13
+ */
14
+ export declare function buildDwJsonSchema(): JsonSchema;
@@ -0,0 +1,269 @@
1
+ /*
2
+ * Copyright (c) 2025, Salesforce, Inc.
3
+ * SPDX-License-Identifier: Apache-2
4
+ * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+ /**
7
+ * JSON Schema for `dw.json` configuration files.
8
+ *
9
+ * This module is the single source of truth for the published schema at
10
+ * `data/schemas/dw.schema.json` (regenerate with `pnpm run generate:dw-json-schema`).
11
+ * Editors use it for validation, completion, and hover docs; the VS Code
12
+ * extension registers it for every `dw.json`.
13
+ *
14
+ * `dw.json` accepts both kebab-case (canonical) and camelCase spellings, plus a
15
+ * few legacy aliases (see {@link CONFIG_KEY_ALIASES}). The schema lists every
16
+ * accepted spelling so editors do not flag valid files. Unknown keys are allowed
17
+ * because other tools share `dw.json`.
18
+ *
19
+ * @module config/dw-json-schema
20
+ */
21
+ import { CLIENT_AUTH_METHODS } from '../auth/client-credentials.js';
22
+ import { CONFIG_KEY_ALIASES, kebabToCamelCase } from './mapping.js';
23
+ /** Public URL of the published schema (usable as `"$schema"` in dw.json). */
24
+ export const DW_JSON_SCHEMA_URL = 'https://salesforcecommercecloud.github.io/b2c-developer-tooling/schemas/dw.schema.json';
25
+ const DOCS_URL = 'https://salesforcecommercecloud.github.io/b2c-developer-tooling/guide/configuration.html';
26
+ const stringArray = { type: 'array', items: { type: 'string' } };
27
+ const AUTH_METHODS = ['client-credentials', 'jwt', 'user', 'implicit', 'basic', 'api-key'];
28
+ /**
29
+ * Canonical instance-level fields keyed by kebab-case name (the on-disk spelling).
30
+ * Descriptions mirror the Settings Reference in the configuration guide.
31
+ */
32
+ export const DW_JSON_FIELDS = {
33
+ // Instance and site
34
+ name: { type: 'string', description: 'Connection name for instance selection (`--instance` / `SFCC_INSTANCE`).' },
35
+ active: { type: 'boolean', description: 'Use this entry as the default instance.' },
36
+ hostname: {
37
+ type: 'string',
38
+ description: 'Instance hostname, without a URL path (e.g. `abcd-001.dx.commercecloud.salesforce.com`). Env: `SFCC_SERVER`.',
39
+ },
40
+ 'webdav-hostname': { type: 'string', description: 'Separate WebDAV hostname. Env: `SFCC_WEBDAV_SERVER`.' },
41
+ 'code-version': {
42
+ type: 'string',
43
+ description: 'Default code version for operations that accept one. Env: `SFCC_CODE_VERSION`.',
44
+ },
45
+ 'short-code': { type: 'string', description: 'SCAPI short code. Env: `SFCC_SHORTCODE`.' },
46
+ 'tenant-id': {
47
+ type: 'string',
48
+ description: 'Tenant or organization ID, such as `abcd_001` or `f_ecom_abcd_001`. Env: `SFCC_TENANT_ID`.',
49
+ },
50
+ 'site-id': {
51
+ type: 'string',
52
+ description: 'Default site/channel ID for supported site and shopper operations. Env: `SFCC_SITE_ID`.',
53
+ },
54
+ 'api-backend': {
55
+ type: 'string',
56
+ enum: ['auto', 'scapi', 'ocapi'],
57
+ description: 'API backend for operations supporting both SCAPI and OCAPI. `auto` (default) prefers SCAPI with OCAPI fallback. Env: `SFCC_API_BACKEND`.',
58
+ },
59
+ // Administrative authentication
60
+ 'client-id': { type: 'string', description: 'Account Manager API client ID. Env: `SFCC_CLIENT_ID`.' },
61
+ 'client-secret': { type: 'string', description: 'Account Manager client secret. Env: `SFCC_CLIENT_SECRET`.' },
62
+ 'oauth-scopes': {
63
+ ...stringArray,
64
+ description: 'Requested OAuth scopes. Scope grants must be configured on the API client. Env: `SFCC_OAUTH_SCOPES` (comma-separated).',
65
+ },
66
+ 'jwt-cert-path': {
67
+ type: 'string',
68
+ description: 'PEM certificate path for JWT authentication. Env: `SFCC_JWT_CERT`; flag: `--jwt-cert`.',
69
+ },
70
+ 'jwt-key-path': { type: 'string', description: 'PEM private key path for JWT authentication. Env: `SFCC_JWT_KEY`.' },
71
+ 'jwt-passphrase': {
72
+ type: 'string',
73
+ description: 'Passphrase for an encrypted JWT private key. Env: `SFCC_JWT_PASSPHRASE`.',
74
+ },
75
+ 'auth-methods': {
76
+ type: 'array',
77
+ items: { type: 'string', enum: AUTH_METHODS },
78
+ uniqueItems: true,
79
+ description: 'Ordered list of allowed authentication methods. Do not combine with `user-auth`. Env: `SFCC_AUTH_METHODS` (comma-separated).',
80
+ },
81
+ 'user-auth': {
82
+ type: 'boolean',
83
+ description: 'Shorthand for `"auth-methods": ["user"]` (browser login). Do not combine with `auth-methods`.',
84
+ },
85
+ 'account-manager-host': {
86
+ type: 'string',
87
+ description: 'Account Manager hostname override. Env: `SFCC_ACCOUNT_MANAGER_HOST`.',
88
+ },
89
+ 'client-auth-method': {
90
+ type: 'string',
91
+ enum: [...CLIENT_AUTH_METHODS],
92
+ description: 'How client credentials are sent to Account Manager (default `basic`). Env: `SFCC_CLIENT_AUTH_METHOD`; flag: `--client-auth-method`.',
93
+ },
94
+ // Shopper authentication
95
+ 'slas-client-id': {
96
+ type: 'string',
97
+ description: 'Shopper Login and API Access Service (SLAS) client ID. Env: `SFCC_SLAS_CLIENT_ID`.',
98
+ },
99
+ 'slas-client-secret': {
100
+ type: 'string',
101
+ description: 'Secret for a private SLAS client; omit for public clients. Env: `SFCC_SLAS_CLIENT_SECRET`.',
102
+ },
103
+ // WebDAV and certificates
104
+ username: {
105
+ type: 'string',
106
+ description: 'Business Manager username (typically an email address) for WebDAV. Env: `SFCC_USERNAME`.',
107
+ },
108
+ password: { type: 'string', description: 'WebDAV access key for `username`. Env: `SFCC_PASSWORD`.' },
109
+ certificate: {
110
+ type: 'string',
111
+ description: 'Path to a PKCS12 (`.p12` / `.pfx`) client certificate for mTLS. Env: `SFCC_CERTIFICATE`.',
112
+ },
113
+ 'certificate-passphrase': {
114
+ type: 'string',
115
+ description: 'Client certificate passphrase. Env: `SFCC_CERTIFICATE_PASSPHRASE`.',
116
+ },
117
+ 'self-signed': {
118
+ type: 'boolean',
119
+ description: 'Disable server certificate verification (default `false`). Not required just because you use mTLS. Env: `SFCC_SELFSIGNED`.',
120
+ },
121
+ // Code, content, and documentation
122
+ cartridges: {
123
+ oneOf: [stringArray, { type: 'string' }],
124
+ description: 'Cartridge names for deploy/watch filtering and IDE discovery. Array, or a colon/comma-separated string. Env: `SFCC_CARTRIDGES`.',
125
+ },
126
+ 'auto-upload': { type: 'boolean', description: 'Automatically upload code changes from the VS Code extension.' },
127
+ 'content-library': { type: 'string', description: 'Default library for content list/export.' },
128
+ catalogs: { ...stringArray, description: 'Catalog IDs for WebDAV browsing. Env: `SFCC_CATALOGS`.' },
129
+ libraries: {
130
+ type: 'array',
131
+ items: {
132
+ oneOf: [
133
+ { type: 'string' },
134
+ {
135
+ type: 'object',
136
+ required: ['id'],
137
+ properties: {
138
+ id: { type: 'string', description: 'Library ID.' },
139
+ siteLibrary: { type: 'boolean', description: 'Whether this is a site-private library.' },
140
+ },
141
+ },
142
+ ],
143
+ },
144
+ description: 'Content library IDs, as strings or `{"id": "RefArch", "siteLibrary": true}` entries. Env: `SFCC_LIBRARIES`.',
145
+ },
146
+ 'asset-query': {
147
+ ...stringArray,
148
+ description: 'JSON dot-paths for finding static asset URLs in content (default `["image.path"]`). Env: `SFCC_ASSET_QUERY`.',
149
+ },
150
+ 'import-set-exclude': {
151
+ ...stringArray,
152
+ description: 'Project-relative directories to exclude recursively from import-set discovery. Env: `SFCC_IMPORT_SET_EXCLUDE`.',
153
+ },
154
+ 'docs-categories': {
155
+ ...stringArray,
156
+ description: 'Documentation category allowlist for supported searches. Env: `SFCC_DOCS_CATEGORIES`.',
157
+ },
158
+ 'scapi-schemas': {
159
+ ...stringArray,
160
+ description: 'Local SCAPI OpenAPI JSON files or directories (relative to the project directory), or http(s) URLs, for MCP code mode. Env: `SFCC_SCAPI_SCHEMAS`.',
161
+ },
162
+ // Sandboxes and analytics
163
+ realm: { type: 'string', description: 'Default realm for sandbox operations.' },
164
+ 'sandbox-api-host': {
165
+ type: 'string',
166
+ description: 'On-Demand Sandbox API hostname override. Env: `SFCC_SANDBOX_API_HOST`.',
167
+ },
168
+ 'cip-host': { type: 'string', description: 'CIP analytics host override. Env: `SFCC_CIP_HOST`.' },
169
+ safety: {
170
+ type: 'object',
171
+ description: 'Per-instance safety restrictions and confirmation rules. See the Safety Mode guide.',
172
+ additionalProperties: false,
173
+ properties: {
174
+ level: {
175
+ type: 'string',
176
+ enum: ['NONE', 'NO_DELETE', 'NO_UPDATE', 'READ_ONLY'],
177
+ description: 'Baseline restriction level. Env: `SFCC_SAFETY_LEVEL`.',
178
+ },
179
+ confirm: {
180
+ type: 'boolean',
181
+ description: 'Require interactive confirmation for blocked operations instead of refusing them.',
182
+ },
183
+ rules: {
184
+ type: 'array',
185
+ description: 'Ordered rules; the first match wins.',
186
+ items: {
187
+ type: 'object',
188
+ required: ['action'],
189
+ additionalProperties: false,
190
+ properties: {
191
+ method: { type: 'string', description: 'HTTP method pattern (e.g. `POST`, `DELETE`).' },
192
+ path: { type: 'string', description: 'URL path glob (e.g. `/jobs/*/executions`).' },
193
+ job: { type: 'string', description: 'Job ID glob.' },
194
+ command: { type: 'string', description: 'CLI command ID glob (e.g. `sandbox:*`, `ecdn:cache:purge`).' },
195
+ action: { type: 'string', enum: ['allow', 'block', 'confirm'], description: 'Action when the rule matches.' },
196
+ },
197
+ },
198
+ },
199
+ },
200
+ },
201
+ // Managed Runtime
202
+ 'mrt-api-key': { type: 'string', description: 'Managed Runtime API key. Env: `MRT_API_KEY`.' },
203
+ 'mrt-project': {
204
+ type: 'string',
205
+ description: 'Managed Runtime project slug (storefront ID for SCAPI MRT operations). Env: `MRT_PROJECT`.',
206
+ },
207
+ 'mrt-environment': { type: 'string', description: 'Managed Runtime target environment. Env: `MRT_ENVIRONMENT`.' },
208
+ 'mrt-origin': { type: 'string', description: 'Managed Runtime API origin override. Env: `MRT_CLOUD_ORIGIN`.' },
209
+ 'mrt-backend': {
210
+ type: 'string',
211
+ enum: ['auto', 'legacy', 'scapi'],
212
+ description: 'Managed Runtime backend for supported operations (default `auto`). Env: `MRT_BACKEND`.',
213
+ },
214
+ };
215
+ /** Legacy and alternate spellings, excluding simple camelCase forms. */
216
+ function aliasesFor(camelKey) {
217
+ return Object.entries(CONFIG_KEY_ALIASES)
218
+ .filter(([, canonical]) => canonical === camelKey)
219
+ .map(([alias]) => alias);
220
+ }
221
+ /**
222
+ * Builds the `dw.json` JSON Schema from {@link DW_JSON_FIELDS}, adding the
223
+ * camelCase spelling and legacy aliases for every field.
224
+ */
225
+ export function buildDwJsonSchema() {
226
+ const instanceProperties = {};
227
+ for (const [kebab, schema] of Object.entries(DW_JSON_FIELDS)) {
228
+ instanceProperties[kebab] = schema;
229
+ const camel = kebabToCamelCase(kebab);
230
+ const alternates = [camel, ...aliasesFor(camel)].filter((k) => k !== kebab);
231
+ for (const alternate of alternates) {
232
+ instanceProperties[alternate] ??= {
233
+ ...schema,
234
+ description: `Alternate spelling of \`${kebab}\`. ${String(schema.description ?? '')}`.trim(),
235
+ };
236
+ }
237
+ }
238
+ const instanceSchema = {
239
+ type: 'object',
240
+ properties: instanceProperties,
241
+ additionalProperties: true,
242
+ not: {
243
+ anyOf: [
244
+ { required: ['user-auth', 'auth-methods'] },
245
+ { required: ['userAuth', 'authMethods'] },
246
+ { required: ['user-auth', 'authMethods'] },
247
+ { required: ['userAuth', 'auth-methods'] },
248
+ ],
249
+ },
250
+ };
251
+ return {
252
+ $schema: 'http://json-schema.org/draft-07/schema#',
253
+ $id: DW_JSON_SCHEMA_URL,
254
+ title: 'B2C Commerce dw.json',
255
+ description: `Connection and project configuration for B2C Commerce tooling. See ${DOCS_URL}`,
256
+ definitions: { instance: instanceSchema },
257
+ allOf: [{ $ref: '#/definitions/instance' }],
258
+ type: 'object',
259
+ properties: {
260
+ $schema: { type: 'string', description: 'JSON Schema reference for editor support.' },
261
+ configs: {
262
+ type: 'array',
263
+ description: 'Named instance entries. Select one with `--instance` / `SFCC_INSTANCE`, or mark one `active`.',
264
+ items: { $ref: '#/definitions/instance' },
265
+ },
266
+ },
267
+ };
268
+ }
269
+ //# sourceMappingURL=dw-json-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dw-json-schema.js","sourceRoot":"","sources":["../../../src/config/dw-json-schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAC,mBAAmB,EAAC,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAC,kBAAkB,EAAE,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAKlE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,kBAAkB,GAC7B,wFAAwF,CAAC;AAE3F,MAAM,QAAQ,GAAG,0FAA0F,CAAC;AAE5G,MAAM,WAAW,GAAe,EAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,EAAC,CAAC;AAEzE,MAAM,YAAY,GAAG,CAAC,oBAAoB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;AAE3F;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAA+B;IACxD,oBAAoB;IACpB,IAAI,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0EAA0E,EAAC;IAC/G,MAAM,EAAE,EAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,yCAAyC,EAAC;IACjF,QAAQ,EAAE;QACR,IAAI,EAAE,QAAQ;QACd,WAAW,EACT,8GAA8G;KACjH;IACD,iBAAiB,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sDAAsD,EAAC;IACxG,cAAc,EAAE;QACd,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,gFAAgF;KAC9F;IACD,YAAY,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0CAA0C,EAAC;IACvF,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,4FAA4F;KAC1G;IACD,SAAS,EAAE;QACT,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,yFAAyF;KACvG;IACD,aAAa,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;QAChC,WAAW,EACT,0IAA0I;KAC7I;IAED,gCAAgC;IAChC,WAAW,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uDAAuD,EAAC;IACnG,eAAe,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2DAA2D,EAAC;IAC3G,cAAc,EAAE;QACd,GAAG,WAAW;QACd,WAAW,EACT,wHAAwH;KAC3H;IACD,eAAe,EAAE;QACf,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,wFAAwF;KACtG;IACD,cAAc,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mEAAmE,EAAC;IAClH,gBAAgB,EAAE;QAChB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,0EAA0E;KACxF;IACD,cAAc,EAAE;QACd,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAC;QAC3C,WAAW,EAAE,IAAI;QACjB,WAAW,EACT,8HAA8H;KACjI;IACD,WAAW,EAAE;QACX,IAAI,EAAE,SAAS;QACf,WAAW,EAAE,+FAA+F;KAC7G;IACD,sBAAsB,EAAE;QACtB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,sEAAsE;KACpF;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,CAAC,GAAG,mBAAmB,CAAC;QAC9B,WAAW,EACT,qIAAqI;KACxI;IAED,yBAAyB;IACzB,gBAAgB,EAAE;QAChB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,oFAAoF;KAClG;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,4FAA4F;KAC1G;IAED,0BAA0B;IAC1B,QAAQ,EAAE;QACR,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,0FAA0F;KACxG;IACD,QAAQ,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yDAAyD,EAAC;IAClG,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,0FAA0F;KACxG;IACD,wBAAwB,EAAE;QACxB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,oEAAoE;KAClF;IACD,aAAa,EAAE;QACb,IAAI,EAAE,SAAS;QACf,WAAW,EACT,4HAA4H;KAC/H;IAED,mCAAmC;IACnC,UAAU,EAAE;QACV,KAAK,EAAE,CAAC,WAAW,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAC,CAAC;QACtC,WAAW,EACT,iIAAiI;KACpI;IACD,aAAa,EAAE,EAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,+DAA+D,EAAC;IAC9G,iBAAiB,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0CAA0C,EAAC;IAC5F,QAAQ,EAAE,EAAC,GAAG,WAAW,EAAE,WAAW,EAAE,wDAAwD,EAAC;IACjG,SAAS,EAAE;QACT,IAAI,EAAE,OAAO;QACb,KAAK,EAAE;YACL,KAAK,EAAE;gBACL,EAAC,IAAI,EAAE,QAAQ,EAAC;gBAChB;oBACE,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,CAAC,IAAI,CAAC;oBAChB,UAAU,EAAE;wBACV,EAAE,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAC;wBAChD,WAAW,EAAE,EAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,yCAAyC,EAAC;qBACvF;iBACF;aACF;SACF;QACD,WAAW,EACT,6GAA6G;KAChH;IACD,aAAa,EAAE;QACb,GAAG,WAAW;QACd,WAAW,EACT,8GAA8G;KACjH;IACD,oBAAoB,EAAE;QACpB,GAAG,WAAW;QACd,WAAW,EACT,gHAAgH;KACnH;IACD,iBAAiB,EAAE;QACjB,GAAG,WAAW;QACd,WAAW,EAAE,uFAAuF;KACrG;IACD,eAAe,EAAE;QACf,GAAG,WAAW;QACd,WAAW,EACT,mJAAmJ;KACtJ;IAED,0BAA0B;IAC1B,KAAK,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAC;IAC7E,kBAAkB,EAAE;QAClB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,wEAAwE;KACtF;IACD,UAAU,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oDAAoD,EAAC;IAC/F,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,qFAAqF;QAClG,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE;YACV,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,CAAC;gBACrD,WAAW,EAAE,uDAAuD;aACrE;YACD,OAAO,EAAE;gBACP,IAAI,EAAE,SAAS;gBACf,WAAW,EAAE,mFAAmF;aACjG;YACD,KAAK,EAAE;gBACL,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,sCAAsC;gBACnD,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,QAAQ,EAAE,CAAC,QAAQ,CAAC;oBACpB,oBAAoB,EAAE,KAAK;oBAC3B,UAAU,EAAE;wBACV,MAAM,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAC;wBACrF,IAAI,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4CAA4C,EAAC;wBACjF,GAAG,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAC;wBAClD,OAAO,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6DAA6D,EAAC;wBACrG,MAAM,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,WAAW,EAAE,+BAA+B,EAAC;qBAC5G;iBACF;aACF;SACF;KACF;IAED,kBAAkB;IAClB,aAAa,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAC;IAC5F,aAAa,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,4FAA4F;KAC1G;IACD,iBAAiB,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6DAA6D,EAAC;IAC/G,YAAY,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+DAA+D,EAAC;IAC5G,aAAa,EAAE;QACb,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC;QACjC,WAAW,EAAE,wFAAwF;KACtG;CACF,CAAC;AAEF,wEAAwE;AACxE,SAAS,UAAU,CAAC,QAAgB;IAClC,OAAO,MAAM,CAAC,OAAO,CAAC,kBAAkB,CAAC;SACtC,MAAM,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,SAAS,KAAK,QAAQ,CAAC;SACjD,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,kBAAkB,GAA+B,EAAE,CAAC;IAC1D,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC;QAC7D,kBAAkB,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;QACnC,MAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;QAC5E,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACnC,kBAAkB,CAAC,SAAS,CAAC,KAAK;gBAChC,GAAG,MAAM;gBACT,WAAW,EAAE,2BAA2B,KAAK,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE;aAC9F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,cAAc,GAAe;QACjC,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,kBAAkB;QAC9B,oBAAoB,EAAE,IAAI;QAC1B,GAAG,EAAE;YACH,KAAK,EAAE;gBACL,EAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC,EAAC;gBACzC,EAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,EAAC;gBACvC,EAAC,QAAQ,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC,EAAC;gBACxC,EAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,cAAc,CAAC,EAAC;aACzC;SACF;KACF,CAAC;IAEF,OAAO;QACL,OAAO,EAAE,yCAAyC;QAClD,GAAG,EAAE,kBAAkB;QACvB,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,sEAAsE,QAAQ,EAAE;QAC7F,WAAW,EAAE,EAAC,QAAQ,EAAE,cAAc,EAAC;QACvC,KAAK,EAAE,CAAC,EAAC,IAAI,EAAE,wBAAwB,EAAC,CAAC;QACzC,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,OAAO,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2CAA2C,EAAC;YACnF,OAAO,EAAE;gBACP,IAAI,EAAE,OAAO;gBACb,WAAW,EAAE,+FAA+F;gBAC5G,KAAK,EAAE,EAAC,IAAI,EAAE,wBAAwB,EAAC;aACxC;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -93,6 +93,8 @@ export interface DwJsonConfig {
93
93
  cipHost?: string;
94
94
  /** Documentation categories to expose (allowlist); dw.json key `docs-categories` */
95
95
  docsCategories?: string[];
96
+ /** Local SCAPI OpenAPI contracts (files, directories or http(s) URLs) for MCP code mode; dw.json key `scapi-schemas` */
97
+ scapiSchemas?: string[];
96
98
  /** Path to PKCS12 certificate file for mTLS (two-factor auth) */
97
99
  certificate?: string;
98
100
  /** Passphrase for the certificate */
@@ -297,16 +297,20 @@ export async function updateInstanceConfig(patch, options = {}) {
297
297
  if (!target) {
298
298
  throw new Error(`Instance "${options.instance}" not found`);
299
299
  }
300
+ // Rebuild the entry so a replaced key keeps its position in the file.
301
+ const entries = Object.entries(target);
300
302
  for (const [field, value] of Object.entries(patch)) {
301
- for (const key of Object.keys(target)) {
302
- if ((CONFIG_KEY_ALIASES[key] ?? kebabToCamelCase(key)) === field) {
303
- delete target[key];
304
- }
305
- }
303
+ const matches = (key) => (CONFIG_KEY_ALIASES[key] ?? kebabToCamelCase(key)) === field;
304
+ const position = entries.findIndex(([key]) => matches(key));
305
+ const remaining = entries.filter(([key]) => !matches(key));
306
306
  if (value !== undefined) {
307
- target[camelToKebabCase(field)] = value;
307
+ remaining.splice(position === -1 ? remaining.length : position, 0, [camelToKebabCase(field), value]);
308
308
  }
309
+ entries.splice(0, entries.length, ...remaining);
309
310
  }
311
+ for (const key of Object.keys(target))
312
+ delete target[key];
313
+ Object.assign(target, Object.fromEntries(entries));
310
314
  await saveDwJson(existing, dwJsonPath);
311
315
  return { name: target.name, path: dwJsonPath };
312
316
  }