openxiangda-devkit-core 2.0.0-alpha.12 → 2.0.0-alpha.121

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 (188) hide show
  1. package/README.md +3 -8
  2. package/dist/app-spec.d.ts +228 -0
  3. package/dist/app-spec.d.ts.map +1 -0
  4. package/dist/app-spec.js +1443 -0
  5. package/dist/app-spec.js.map +1 -0
  6. package/dist/application-services.d.ts +996 -49
  7. package/dist/application-services.d.ts.map +1 -1
  8. package/dist/application-services.js +1348 -197
  9. package/dist/application-services.js.map +1 -1
  10. package/dist/application-ui-contract.d.ts +5 -0
  11. package/dist/application-ui-contract.d.ts.map +1 -0
  12. package/dist/application-ui-contract.js +149 -0
  13. package/dist/application-ui-contract.js.map +1 -0
  14. package/dist/backend-image-build.d.ts +23 -0
  15. package/dist/backend-image-build.d.ts.map +1 -0
  16. package/dist/backend-image-build.js +204 -0
  17. package/dist/backend-image-build.js.map +1 -0
  18. package/dist/command-process.d.ts +14 -0
  19. package/dist/command-process.d.ts.map +1 -0
  20. package/dist/command-process.js +51 -0
  21. package/dist/command-process.js.map +1 -0
  22. package/dist/command-registry.d.ts +123 -366
  23. package/dist/command-registry.d.ts.map +1 -1
  24. package/dist/command-registry.js +26 -266
  25. package/dist/command-registry.js.map +1 -1
  26. package/dist/compiler/ai-catalog.d.ts +4 -0
  27. package/dist/compiler/ai-catalog.d.ts.map +1 -0
  28. package/dist/compiler/ai-catalog.js +354 -0
  29. package/dist/compiler/ai-catalog.js.map +1 -0
  30. package/dist/compiler/application-model.d.ts +60 -0
  31. package/dist/compiler/application-model.d.ts.map +1 -0
  32. package/dist/compiler/application-model.js +141 -0
  33. package/dist/compiler/application-model.js.map +1 -0
  34. package/dist/compiler/authorization-transition.d.ts +7 -0
  35. package/dist/compiler/authorization-transition.d.ts.map +1 -0
  36. package/dist/compiler/authorization-transition.js +27 -0
  37. package/dist/compiler/authorization-transition.js.map +1 -0
  38. package/dist/compiler/bundle.d.ts +34 -0
  39. package/dist/compiler/bundle.d.ts.map +1 -0
  40. package/dist/compiler/bundle.js +1910 -0
  41. package/dist/compiler/bundle.js.map +1 -0
  42. package/dist/compiler/config.d.ts +882 -0
  43. package/dist/compiler/config.d.ts.map +1 -0
  44. package/dist/compiler/config.js +4118 -0
  45. package/dist/compiler/config.js.map +1 -0
  46. package/dist/compiler/data-policy-expression.d.ts +12 -0
  47. package/dist/compiler/data-policy-expression.d.ts.map +1 -0
  48. package/dist/compiler/data-policy-expression.js +43 -0
  49. package/dist/compiler/data-policy-expression.js.map +1 -0
  50. package/dist/compiler/field-codec.d.ts +14 -0
  51. package/dist/compiler/field-codec.d.ts.map +1 -0
  52. package/dist/compiler/field-codec.js +131 -0
  53. package/dist/compiler/field-codec.js.map +1 -0
  54. package/dist/compiler/field-physical-plan.d.ts +10 -0
  55. package/dist/compiler/field-physical-plan.d.ts.map +1 -0
  56. package/dist/compiler/field-physical-plan.js +66 -0
  57. package/dist/compiler/field-physical-plan.js.map +1 -0
  58. package/dist/compiler/field-policy-path.d.ts +10 -0
  59. package/dist/compiler/field-policy-path.d.ts.map +1 -0
  60. package/dist/compiler/field-policy-path.js +283 -0
  61. package/dist/compiler/field-policy-path.js.map +1 -0
  62. package/dist/compiler/field-query-plan.d.ts +13 -0
  63. package/dist/compiler/field-query-plan.d.ts.map +1 -0
  64. package/dist/compiler/field-query-plan.js +122 -0
  65. package/dist/compiler/field-query-plan.js.map +1 -0
  66. package/dist/compiler/field-surface.d.ts +15 -0
  67. package/dist/compiler/field-surface.d.ts.map +1 -0
  68. package/dist/compiler/field-surface.js +51 -0
  69. package/dist/compiler/field-surface.js.map +1 -0
  70. package/dist/compiler/index.d.ts +6 -0
  71. package/dist/compiler/index.d.ts.map +1 -0
  72. package/dist/compiler/index.js +6 -0
  73. package/dist/compiler/index.js.map +1 -0
  74. package/dist/compiler/package-compiler.d.ts +22 -0
  75. package/dist/compiler/package-compiler.d.ts.map +1 -0
  76. package/dist/compiler/package-compiler.js +257 -0
  77. package/dist/compiler/package-compiler.js.map +1 -0
  78. package/dist/compiler/permission-review.d.ts +139 -0
  79. package/dist/compiler/permission-review.d.ts.map +1 -0
  80. package/dist/compiler/permission-review.js +131 -0
  81. package/dist/compiler/permission-review.js.map +1 -0
  82. package/dist/compiler/schema-composition.d.ts +21 -0
  83. package/dist/compiler/schema-composition.d.ts.map +1 -0
  84. package/dist/compiler/schema-composition.js +193 -0
  85. package/dist/compiler/schema-composition.js.map +1 -0
  86. package/dist/config.d.ts +1 -1
  87. package/dist/config.js +1 -1
  88. package/dist/configuration-preflight.d.ts +7 -0
  89. package/dist/configuration-preflight.d.ts.map +1 -0
  90. package/dist/configuration-preflight.js +13 -0
  91. package/dist/configuration-preflight.js.map +1 -0
  92. package/dist/connected-development.d.ts +62 -0
  93. package/dist/connected-development.d.ts.map +1 -0
  94. package/dist/connected-development.js +393 -0
  95. package/dist/connected-development.js.map +1 -0
  96. package/dist/control-plane-client.d.ts +353 -123
  97. package/dist/control-plane-client.d.ts.map +1 -1
  98. package/dist/control-plane-client.js +420 -141
  99. package/dist/control-plane-client.js.map +1 -1
  100. package/dist/delivery-cache.d.ts +34 -0
  101. package/dist/delivery-cache.d.ts.map +1 -0
  102. package/dist/delivery-cache.js +186 -0
  103. package/dist/delivery-cache.js.map +1 -0
  104. package/dist/delivery-source.d.ts +17 -0
  105. package/dist/delivery-source.d.ts.map +1 -0
  106. package/dist/delivery-source.js +85 -0
  107. package/dist/delivery-source.js.map +1 -0
  108. package/dist/deployment-observer.d.ts +14 -0
  109. package/dist/deployment-observer.d.ts.map +1 -0
  110. package/dist/deployment-observer.js +68 -0
  111. package/dist/deployment-observer.js.map +1 -0
  112. package/dist/deployment.d.ts +55 -3
  113. package/dist/deployment.d.ts.map +1 -1
  114. package/dist/deployment.js +182 -21
  115. package/dist/deployment.js.map +1 -1
  116. package/dist/design-readiness.d.ts +24 -0
  117. package/dist/design-readiness.d.ts.map +1 -0
  118. package/dist/design-readiness.js +102 -0
  119. package/dist/design-readiness.js.map +1 -0
  120. package/dist/developer-errors.d.ts +11 -0
  121. package/dist/developer-errors.d.ts.map +1 -0
  122. package/dist/developer-errors.js +16 -0
  123. package/dist/developer-errors.js.map +1 -0
  124. package/dist/developer-operations.d.ts +188 -0
  125. package/dist/developer-operations.d.ts.map +1 -0
  126. package/dist/developer-operations.js +58 -0
  127. package/dist/developer-operations.js.map +1 -0
  128. package/dist/development-lifecycle.d.ts +75 -0
  129. package/dist/development-lifecycle.d.ts.map +1 -0
  130. package/dist/development-lifecycle.js +189 -0
  131. package/dist/development-lifecycle.js.map +1 -0
  132. package/dist/documentation.d.ts +111 -0
  133. package/dist/documentation.d.ts.map +1 -0
  134. package/dist/documentation.js +112 -0
  135. package/dist/documentation.js.map +1 -0
  136. package/dist/index.d.ts +16 -0
  137. package/dist/index.d.ts.map +1 -1
  138. package/dist/index.js +16 -0
  139. package/dist/index.js.map +1 -1
  140. package/dist/internal/workflow.d.ts +83 -0
  141. package/dist/internal/workflow.d.ts.map +1 -0
  142. package/dist/internal/workflow.js +419 -0
  143. package/dist/internal/workflow.js.map +1 -0
  144. package/dist/nest-injection-contract.d.ts +4 -0
  145. package/dist/nest-injection-contract.d.ts.map +1 -0
  146. package/dist/nest-injection-contract.js +116 -0
  147. package/dist/nest-injection-contract.js.map +1 -0
  148. package/dist/operation-progress.d.ts +26 -0
  149. package/dist/operation-progress.d.ts.map +1 -0
  150. package/dist/operation-progress.js +92 -0
  151. package/dist/operation-progress.js.map +1 -0
  152. package/dist/optional-backend.d.ts +14 -0
  153. package/dist/optional-backend.d.ts.map +1 -0
  154. package/dist/optional-backend.js +145 -0
  155. package/dist/optional-backend.js.map +1 -0
  156. package/dist/package-compiler.d.ts +1 -1
  157. package/dist/package-compiler.d.ts.map +1 -1
  158. package/dist/package-compiler.js +1 -1
  159. package/dist/package-compiler.js.map +1 -1
  160. package/dist/session.d.ts +149 -4
  161. package/dist/session.d.ts.map +1 -1
  162. package/dist/session.js +362 -23
  163. package/dist/session.js.map +1 -1
  164. package/dist/testing.d.ts +77 -0
  165. package/dist/testing.d.ts.map +1 -0
  166. package/dist/testing.js +213 -0
  167. package/dist/testing.js.map +1 -0
  168. package/dist/toolchain-capsule.d.ts +45 -0
  169. package/dist/toolchain-capsule.d.ts.map +1 -0
  170. package/dist/toolchain-capsule.js +165 -0
  171. package/dist/toolchain-capsule.js.map +1 -0
  172. package/dist/workspace-loader.d.ts +1 -1
  173. package/dist/workspace-loader.d.ts.map +1 -1
  174. package/dist/workspace-loader.js +35 -3
  175. package/dist/workspace-loader.js.map +1 -1
  176. package/dist/workspace-operation.d.ts +3 -0
  177. package/dist/workspace-operation.d.ts.map +1 -0
  178. package/dist/workspace-operation.js +45 -0
  179. package/dist/workspace-operation.js.map +1 -0
  180. package/dist/workspace.d.ts.map +1 -1
  181. package/dist/workspace.js +37 -1
  182. package/dist/workspace.js.map +1 -1
  183. package/package.json +16 -4
  184. package/templates/backend/Dockerfile +20 -0
  185. package/templates/backend/package.json +27 -0
  186. package/templates/backend/src/app.module.ts +23 -0
  187. package/templates/backend/src/main.ts +5 -0
  188. package/templates/backend/tsconfig.json +9 -0
@@ -1,13 +1,28 @@
1
- import { OPENXIANGDA_CONTRACT_VERSION, SCHEMA_VERSIONS, } from "openxiangda-contracts/browser";
1
+ import { CONFIGURATION_COMPATIBILITY_CAPABILITY, CURRENT_APPLICATION_CONTRACT, OPENXIANGDA_CONTRACT_VERSION, } from "openxiangda-contracts/browser";
2
+ import { Agent, fetch as undiciFetch } from "undici";
3
+ const ARTIFACT_UPLOAD_HEADERS_TIMEOUT_MS = 30 * 60 * 1000;
4
+ const ARTIFACT_UPLOAD_BODY_TIMEOUT_MS = 5 * 60 * 1000;
5
+ function createArtifactUploadFetch() {
6
+ const dispatcher = new Agent({
7
+ headersTimeout: ARTIFACT_UPLOAD_HEADERS_TIMEOUT_MS,
8
+ bodyTimeout: ARTIFACT_UPLOAD_BODY_TIMEOUT_MS,
9
+ });
10
+ return async (input, init) => (await undiciFetch(input, {
11
+ ...(init || {}),
12
+ dispatcher,
13
+ }));
14
+ }
2
15
  export class ControlPlaneError extends Error {
3
16
  status;
4
17
  code;
5
18
  data;
6
- constructor(status, code, message, data) {
19
+ remote;
20
+ constructor(status, code, message, data, remote) {
7
21
  super(message);
8
22
  this.status = status;
9
23
  this.code = code;
10
24
  this.data = data;
25
+ this.remote = remote;
11
26
  this.name = "ControlPlaneError";
12
27
  }
13
28
  }
@@ -15,18 +30,83 @@ export class OpenXiangdaControlPlaneClient {
15
30
  options;
16
31
  baseUrl;
17
32
  fetch;
33
+ artifactUploadFetch;
18
34
  constructor(options) {
19
35
  this.options = options;
20
36
  this.baseUrl = options.baseUrl.replace(/\/+$/, "");
21
37
  this.fetch = options.fetch || globalThis.fetch.bind(globalThis);
38
+ this.artifactUploadFetch = options.fetch || createArtifactUploadFetch();
22
39
  }
23
40
  async capabilities() {
24
41
  const capabilities = await this.json("/openxiangda-api/v2/capabilities");
25
42
  if (capabilities.contractVersion !== OPENXIANGDA_CONTRACT_VERSION) {
26
- throw new ControlPlaneError(409, "OPENXIANGDA_CONTRACT_VERSION_MISMATCH", `平台 contract ${capabilities.contractVersion} 与工具 ${OPENXIANGDA_CONTRACT_VERSION} 不兼容`, capabilities);
43
+ const compatibility = capabilities.configurationCompatibility;
44
+ throw new ControlPlaneError(409, "OPENXIANGDA_CONTRACT_VERSION_MISMATCH", `平台 contract ${capabilities.contractVersion} 与工具 ${OPENXIANGDA_CONTRACT_VERSION} 不兼容`, {
45
+ pointer: "/contractVersion",
46
+ clientContractVersion: OPENXIANGDA_CONTRACT_VERSION,
47
+ clientSchemaVersions: {
48
+ appPackage: CURRENT_APPLICATION_CONTRACT.appPackageSchemaVersion,
49
+ configuration: CURRENT_APPLICATION_CONTRACT.configurationBundleSchemaVersion,
50
+ contract: CURRENT_APPLICATION_CONTRACT.contractBundleSchemaVersion,
51
+ compiler: CURRENT_APPLICATION_CONTRACT.compilerContractVersion,
52
+ },
53
+ platformVersion: String(capabilities.platformVersion || "unknown"),
54
+ platformCapability: compatibility?.capability || {
55
+ code: CONFIGURATION_COMPATIBILITY_CAPABILITY,
56
+ version: "unknown",
57
+ status: "unavailable",
58
+ },
59
+ required: { ...CURRENT_APPLICATION_CONTRACT },
60
+ supported: (compatibility?.supportedApplicationContracts || []).slice(0, 8),
61
+ requiredContractVersion: OPENXIANGDA_CONTRACT_VERSION,
62
+ supportedContractVersion: capabilities.contractVersion,
63
+ });
27
64
  }
28
65
  return capabilities;
29
66
  }
67
+ async validateConfigurationCompatibility(appCode, capabilities, input) {
68
+ const compatibility = capabilities.configurationCompatibility;
69
+ const expectedTemplate = "/openxiangda-api/v2/applications/{appCode}/configuration-compatibility";
70
+ if (compatibility.endpointTemplate !== expectedTemplate) {
71
+ throw new ControlPlaneError(409, "OPENXIANGDA_CONFIGURATION_COMPATIBILITY_ENDPOINT_INVALID", "平台配置兼容性端点不符合当前公开契约", {
72
+ pointer: "/configurationCompatibility/endpointTemplate",
73
+ clientContractVersion: OPENXIANGDA_CONTRACT_VERSION,
74
+ clientSchemaVersions: {
75
+ appPackage: input.required.appPackageSchemaVersion,
76
+ configuration: input.required.configurationBundleSchemaVersion,
77
+ contract: input.required.contractBundleSchemaVersion,
78
+ compiler: input.required.compilerContractVersion,
79
+ },
80
+ platformVersion: capabilities.platformVersion,
81
+ platformCapability: compatibility.capability,
82
+ required: { ...input.required },
83
+ supported: compatibility.supportedApplicationContracts.slice(0, 8),
84
+ requiredEndpointTemplate: expectedTemplate,
85
+ supportedEndpointTemplate: compatibility.endpointTemplate,
86
+ });
87
+ }
88
+ const body = JSON.stringify(input);
89
+ const requestBytes = new TextEncoder().encode(body).byteLength;
90
+ if (requestBytes > compatibility.limits.requestBytes) {
91
+ throw new ControlPlaneError(409, "OPENXIANGDA_CONFIGURATION_VALIDATION_REQUEST_TOO_LARGE", "配置兼容性请求超过目标平台公开上限", {
92
+ pointer: "/",
93
+ clientContractVersion: OPENXIANGDA_CONTRACT_VERSION,
94
+ clientSchemaVersions: {
95
+ appPackage: input.required.appPackageSchemaVersion,
96
+ configuration: input.required.configurationBundleSchemaVersion,
97
+ contract: input.required.contractBundleSchemaVersion,
98
+ compiler: input.required.compilerContractVersion,
99
+ },
100
+ platformVersion: capabilities.platformVersion,
101
+ platformCapability: compatibility.capability,
102
+ required: { ...input.required },
103
+ supported: compatibility.supportedApplicationContracts.slice(0, 8),
104
+ requiredRequestBytes: requestBytes,
105
+ supportedRequestBytes: compatibility.limits.requestBytes,
106
+ });
107
+ }
108
+ return await this.json(compatibility.endpointTemplate.replace("{appCode}", encodeURIComponent(appCode)), { method: "POST", body });
109
+ }
30
110
  async provisionApplication(input) {
31
111
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(input.appCode)}/provision`, {
32
112
  method: "POST",
@@ -36,6 +116,29 @@ export class OpenXiangdaControlPlaneClient {
36
116
  }),
37
117
  });
38
118
  }
119
+ async createConnectedDevelopmentSession(appCode, input) {
120
+ return await this.json(this.connectedDevelopmentSessionsPath(appCode), { method: "POST", body: JSON.stringify(input) });
121
+ }
122
+ async preparePreproductionAcceptanceIdentities(appCode, input) {
123
+ return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/acceptance/identities/prepare`, { method: "POST", body: JSON.stringify(input) });
124
+ }
125
+ async connectedDevelopmentSession(appCode, sessionToken) {
126
+ return await this.json(`${this.connectedDevelopmentSessionsPath(appCode)}/current`, { headers: this.connectedDevelopmentSessionHeaders(sessionToken) });
127
+ }
128
+ async refreshConnectedDevelopmentSession(appCode, sessionToken) {
129
+ return await this.json(`${this.connectedDevelopmentSessionsPath(appCode)}/current/refresh`, {
130
+ method: "POST",
131
+ body: "{}",
132
+ headers: this.connectedDevelopmentSessionHeaders(sessionToken),
133
+ });
134
+ }
135
+ async revokeConnectedDevelopmentSession(appCode, sessionToken) {
136
+ await this.json(`${this.connectedDevelopmentSessionsPath(appCode)}/current/revoke`, {
137
+ method: "POST",
138
+ body: "{}",
139
+ headers: this.connectedDevelopmentSessionHeaders(sessionToken),
140
+ });
141
+ }
39
142
  async oauthClients(appCode) {
40
143
  return await this.json(`${this.oauthPath(appCode)}/clients`);
41
144
  }
@@ -104,16 +207,15 @@ export class OpenXiangdaControlPlaneClient {
104
207
  }
105
208
  async applicationApiResponse(appCode, environmentKey, runtimePath, input) {
106
209
  const path = this.applicationApiPath(appCode, environmentKey, runtimePath, input.query);
107
- const { query: _query, roleSessionId: _roleSessionId, ...init } = input;
210
+ const { query: _query, perspectiveCode: _perspectiveCode, ...init } = input;
211
+ const token = await this.accessToken(false);
108
212
  return await this.fetch(`${this.baseUrl}${path}`, {
109
213
  ...init,
110
214
  credentials: init.credentials || this.options.credentials || "include",
111
215
  headers: {
112
216
  Accept: "application/json",
113
- ...(this.options.token
114
- ? { Authorization: `Bearer ${this.options.token}` }
115
- : {}),
116
- ...this.optionalRoleSessionHeaders(input),
217
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
218
+ ...this.perspectiveHeaders(input),
117
219
  ...(init.headers || {}),
118
220
  },
119
221
  });
@@ -143,6 +245,16 @@ export class OpenXiangdaControlPlaneClient {
143
245
  }
144
246
  return data;
145
247
  }
248
+ async artifactStatus(appCode, digest) {
249
+ try {
250
+ return await this.request(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/artifacts/${digest}`, { method: 'GET' });
251
+ }
252
+ catch (error) {
253
+ if (error instanceof ControlPlaneError && error.status === 404 && error.code === 'DELIVERY_ARTIFACT_NOT_FOUND')
254
+ return null;
255
+ throw error;
256
+ }
257
+ }
146
258
  async uploadArtifact(input) {
147
259
  const params = new URLSearchParams({
148
260
  kind: input.kind,
@@ -151,7 +263,22 @@ export class OpenXiangdaControlPlaneClient {
151
263
  });
152
264
  const form = new FormData();
153
265
  form.append("file", new Blob([input.content], { type: input.contentType }), input.digest);
154
- return await this.request(`/openxiangda-api/v2/applications/${encodeURIComponent(input.appCode)}/artifacts/${input.digest}?${params}`, { method: "POST", body: form });
266
+ try {
267
+ return await this.request(`/openxiangda-api/v2/applications/${encodeURIComponent(input.appCode)}/artifacts/${input.digest}?${params}`, { method: "POST", body: form }, this.artifactUploadFetch);
268
+ }
269
+ catch (error) {
270
+ if (error instanceof ControlPlaneError)
271
+ throw error;
272
+ const causeCode = String(error?.cause?.code || error?.code || "").trim();
273
+ throw new ControlPlaneError(503, "OPENXIANGDA_ARTIFACT_UPLOAD_FAILED", "Application v2 制品上传连接中断", {
274
+ digest: input.digest,
275
+ kind: input.kind,
276
+ ...(causeCode ? { causeCode } : {}),
277
+ }, {
278
+ retryable: true,
279
+ remediation: "重新运行 openxiangda deploy;已完成的内容寻址制品会自动去重",
280
+ });
281
+ }
155
282
  }
156
283
  async createDeployment(input) {
157
284
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(input.appCode)}/deployments`, {
@@ -173,6 +300,15 @@ export class OpenXiangdaControlPlaneClient {
173
300
  async deployments(appCode, limit = 20) {
174
301
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/deployments?limit=${Math.min(Math.max(Number(limit) || 20, 1), 100)}`);
175
302
  }
303
+ async applicationEnvironments(appCode) {
304
+ return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/environments`);
305
+ }
306
+ async startEnvironment(appCode, environmentKey, input) {
307
+ return await this.changeEnvironmentRuntimeState(appCode, environmentKey, "start", input);
308
+ }
309
+ async stopEnvironment(appCode, environmentKey, input) {
310
+ return await this.changeEnvironmentRuntimeState(appCode, environmentKey, "stop", input);
311
+ }
176
312
  async retryDeployment(appCode, deploymentId) {
177
313
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/deployments/${encodeURIComponent(deploymentId)}/retry`, { method: "POST", body: "{}" });
178
314
  }
@@ -182,15 +318,27 @@ export class OpenXiangdaControlPlaneClient {
182
318
  async promote(input) {
183
319
  return await this.deployExistingVersion(input, "promotions");
184
320
  }
321
+ async redeploy(input) {
322
+ return await this.deployExistingVersion(input, "redeployments");
323
+ }
185
324
  async rollback(input) {
186
325
  return await this.deployExistingVersion(input, "rollbacks");
187
326
  }
188
327
  async appVersions(appCode, limit = 30) {
189
328
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/versions?limit=${Math.min(Math.max(Number(limit) || 30, 1), 100)}`);
190
329
  }
330
+ async productionPromotionPreflight(appCode, sourceDeploymentId) {
331
+ return this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/deployments/${encodeURIComponent(sourceDeploymentId)}/promotion-preflight`, { method: 'POST', body: '{}' });
332
+ }
191
333
  async environmentHead(appCode, environmentKey) {
192
334
  return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/environment-heads/${encodeURIComponent(environmentKey)}`);
193
335
  }
336
+ async changeEnvironmentRuntimeState(appCode, environmentKey, action, input) {
337
+ return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/environments/${encodeURIComponent(environmentKey)}/${action}`, {
338
+ method: "POST",
339
+ body: JSON.stringify(input),
340
+ });
341
+ }
194
342
  async applicationSecrets(appCode, environmentKey) {
195
343
  return await this.json(this.applicationSecretsPath(appCode, environmentKey));
196
344
  }
@@ -212,19 +360,12 @@ export class OpenXiangdaControlPlaneClient {
212
360
  async applicationSecretAuditEvents(appCode, environmentKey, name, limit = 100) {
213
361
  return await this.json(`${this.applicationSecretsPath(appCode, environmentKey)}/${encodeURIComponent(name)}/audit?limit=${Math.min(Math.max(Number(limit) || 100, 1), 500)}`);
214
362
  }
215
- async createEventSubscription(input) {
216
- const { appCode, ...body } = input;
217
- return await this.json(`${this.eventsPath(appCode)}/subscriptions`, { method: "POST", body: JSON.stringify(body) });
218
- }
219
363
  async eventSubscriptions(appCode) {
220
364
  return await this.json(`${this.eventsPath(appCode)}/subscriptions`);
221
365
  }
222
366
  async setEventSubscriptionStatus(appCode, subscriptionId, input) {
223
367
  return await this.json(`${this.eventsPath(appCode)}/subscriptions/${encodeURIComponent(subscriptionId)}/status`, { method: "POST", body: JSON.stringify(input) });
224
368
  }
225
- async rotateEventSubscriptionSecret(appCode, subscriptionId, input) {
226
- return await this.json(`${this.eventsPath(appCode)}/subscriptions/${encodeURIComponent(subscriptionId)}/rotate-secret`, { method: "POST", body: JSON.stringify(input) });
227
- }
228
369
  async eventDeliveries(appCode, limit = 100) {
229
370
  return await this.json(`${this.eventsPath(appCode)}/deliveries?limit=${Math.min(Math.max(Number(limit) || 100, 1), 500)}`);
230
371
  }
@@ -234,16 +375,18 @@ export class OpenXiangdaControlPlaneClient {
234
375
  body: JSON.stringify(idempotencyKey ? { idempotencyKey } : {}),
235
376
  });
236
377
  }
237
- async createTimerSubscription(input) {
238
- const { appCode, ...body } = input;
239
- return await this.json(`${this.eventsPath(appCode)}/timers`, { method: "POST", body: JSON.stringify(body) });
240
- }
241
378
  async timerSubscriptions(appCode) {
242
379
  return await this.json(`${this.eventsPath(appCode)}/timers`);
243
380
  }
244
381
  async setTimerSubscriptionStatus(appCode, timerId, input) {
245
382
  return await this.json(`${this.eventsPath(appCode)}/timers/${encodeURIComponent(timerId)}/status`, { method: "POST", body: JSON.stringify(input) });
246
383
  }
384
+ async dateTriggers(appCode) {
385
+ return await this.json(`${this.eventsPath(appCode)}/date-triggers`);
386
+ }
387
+ async setDateTriggerStatus(appCode, triggerId, input) {
388
+ return await this.json(`${this.eventsPath(appCode)}/date-triggers/${encodeURIComponent(triggerId)}/status`, { method: "POST", body: JSON.stringify(input) });
389
+ }
247
390
  async registerWorkflowDefinition(appCode, version, definition) {
248
391
  return await this.json(`${this.workflowPath(appCode)}/definitions`, {
249
392
  method: "POST",
@@ -268,98 +411,173 @@ export class OpenXiangdaControlPlaneClient {
268
411
  async activateWorkflow(appCode, workflowCode, input) {
269
412
  return await this.json(`${this.workflowPath(appCode)}/definitions/${encodeURIComponent(workflowCode)}/activate`, { method: "POST", body: JSON.stringify(input) });
270
413
  }
271
- async prepareWorkflowStart(input) {
272
- const { appCode, workflowCode, roleSessionId, ...body } = input;
273
- return await this.json(`${this.workflowPath(appCode)}/definitions/${encodeURIComponent(workflowCode)}/prepare-start`, {
274
- method: "POST",
275
- body: JSON.stringify(body),
276
- headers: this.roleSessionHeaders({ roleSessionId }),
277
- });
278
- }
279
- async startWorkflow(appCode, input) {
280
- const { roleSessionId, ...body } = input;
281
- return await this.json(`${this.workflowPath(appCode)}/instances`, {
282
- method: "POST",
283
- body: JSON.stringify(body),
284
- headers: this.roleSessionHeaders({ roleSessionId }),
285
- });
286
- }
287
- async createWorkflowDelegation(appCode, input, request) {
414
+ async createWorkflowDelegation(appCode, input) {
288
415
  return await this.json(`${this.workflowPath(appCode)}/delegations`, {
289
416
  method: "POST",
290
417
  body: JSON.stringify(input),
291
- headers: this.roleSessionHeaders(request),
292
418
  });
293
419
  }
294
- async workflowDelegationTargets(appCode, userId, request) {
295
- return await this.json(`${this.workflowPath(appCode)}/delegations/targets?userId=${encodeURIComponent(userId)}`, { headers: this.roleSessionHeaders(request) });
420
+ async workflowDelegationTargets(appCode, userId, environmentKey) {
421
+ return await this.json(`${this.workflowPath(appCode)}/delegations/targets?userId=${encodeURIComponent(userId)}${environmentKey ? `&environmentKey=${encodeURIComponent(environmentKey)}` : ""}`);
296
422
  }
297
- async workflowDelegations(appCode, request, input = {}) {
298
- return await this.json(`${this.workflowPath(appCode)}/delegations?all=${input.all === true}`, { headers: this.roleSessionHeaders(request) });
423
+ async workflowDelegations(appCode, input = {}) {
424
+ return await this.json(`${this.workflowPath(appCode)}/delegations?all=${input.all === true}${input.environmentKey
425
+ ? `&environmentKey=${encodeURIComponent(input.environmentKey)}`
426
+ : ""}`);
299
427
  }
300
- async revokeWorkflowDelegation(appCode, delegationId, request) {
301
- return await this.json(`${this.workflowPath(appCode)}/delegations/${encodeURIComponent(delegationId)}/revoke`, {
428
+ async revokeWorkflowDelegation(appCode, delegationId, environmentKey) {
429
+ return await this.json(`${this.workflowPath(appCode)}/delegations/${encodeURIComponent(delegationId)}/revoke${environmentKey
430
+ ? `?environmentKey=${encodeURIComponent(environmentKey)}`
431
+ : ""}`, {
302
432
  method: "POST",
303
- headers: this.roleSessionHeaders(request),
304
433
  });
305
434
  }
306
- async workflowTaskSurface(appCode, taskId, request) {
307
- return await this.json(`${this.workflowPath(appCode)}/tasks/${encodeURIComponent(taskId)}/surface`, { headers: this.roleSessionHeaders(request) });
435
+ async workflowTaskSurface(appCode, taskId, csrfToken) {
436
+ return await this.json(`${this.workflowPath(appCode)}/tasks/${encodeURIComponent(taskId)}/surface`, { headers: { "X-OpenXiangda-CSRF-Token": csrfToken } });
308
437
  }
309
- async workflowInstanceSurface(appCode, instanceId, request) {
310
- return await this.json(`${this.workflowPath(appCode)}/instances/${encodeURIComponent(instanceId)}/surface`, { headers: this.roleSessionHeaders(request) });
438
+ async workflowInstanceSurface(appCode, instanceId, csrfToken) {
439
+ return await this.json(`${this.workflowPath(appCode)}/instances/${encodeURIComponent(instanceId)}/surface`, { headers: { "X-OpenXiangda-CSRF-Token": csrfToken } });
311
440
  }
312
- async executeWorkflowTaskCommand(appCode, taskId, command, input, request) {
441
+ async executeWorkflowTaskCommand(appCode, taskId, command, input) {
442
+ const { csrfToken, ...request } = input;
313
443
  return await this.json(`${this.workflowPath(appCode)}/tasks/${encodeURIComponent(taskId)}/commands/${encodeURIComponent(command)}`, {
314
444
  method: "POST",
315
- body: JSON.stringify(input),
316
- headers: this.roleSessionHeaders(request),
445
+ headers: { "X-OpenXiangda-CSRF-Token": csrfToken },
446
+ body: JSON.stringify(request),
317
447
  });
318
448
  }
319
- async executeWorkflowInstanceCommand(appCode, instanceId, command, input, request) {
449
+ async executeWorkflowInstanceCommand(appCode, instanceId, command, input) {
450
+ const { csrfToken, ...request } = input;
320
451
  return await this.json(`${this.workflowPath(appCode)}/instances/${encodeURIComponent(instanceId)}/commands/${command}`, {
321
452
  method: "POST",
322
- body: JSON.stringify(input),
323
- headers: this.roleSessionHeaders(request),
453
+ headers: { "X-OpenXiangda-CSRF-Token": csrfToken },
454
+ body: JSON.stringify(request),
324
455
  });
325
456
  }
326
- async workflowAssignmentExplain(appCode, taskId, request) {
327
- return await this.json(`${this.workflowPath(appCode)}/tasks/${encodeURIComponent(taskId)}/assignment-explain`, { headers: this.roleSessionHeaders(request) });
457
+ async workflowAssignmentExplain(appCode, taskId) {
458
+ return await this.json(`${this.workflowPath(appCode)}/tasks/${encodeURIComponent(taskId)}/assignment-explain`);
328
459
  }
329
- async workflowTimeline(appCode, instanceId, request) {
330
- return await this.json(`${this.workflowPath(appCode)}/instances/${encodeURIComponent(instanceId)}/timeline`, { headers: this.roleSessionHeaders(request) });
460
+ async workflowTimeline(appCode, instanceId) {
461
+ return await this.json(`${this.workflowPath(appCode)}/instances/${encodeURIComponent(instanceId)}/timeline`);
331
462
  }
332
- async workflowWorkCenter(appCode, request, input = {}) {
463
+ async workflowWorkCenter(appCode, input = {}) {
333
464
  const query = new URLSearchParams({
334
465
  status: input.status || "pending",
335
466
  limit: String(Math.min(Math.max(Number(input.limit) || 50, 1), 200)),
467
+ ...(input.environmentKey ? { environmentKey: input.environmentKey } : {}),
336
468
  });
337
- return await this.json(`${this.workflowPath(appCode)}/work-center/items?${query}`, { headers: this.roleSessionHeaders(request) });
469
+ return await this.json(`${this.workflowPath(appCode)}/work-center/items?${query}`);
470
+ }
471
+ async workflowDiagnostics(appCode, limit = 100) {
472
+ return await this.json(`${this.workflowPath(appCode)}/diagnostics?limit=${Math.min(Math.max(Number(limit) || 100, 1), 500)}`);
338
473
  }
339
- async workflowKernelInstance(appCode, instanceId, request) {
340
- return await this.json(`${this.workflowPath(appCode)}/kernel/instances/${encodeURIComponent(instanceId)}`, { headers: this.roleSessionHeaders(request) });
474
+ async applicationAdministrationContext(appCode, environmentKey) {
475
+ return await this.json(`${this.administrationPath(appCode)}/context?${this.query({ environmentKey })}`);
341
476
  }
342
- async workflowKernelWorkCenter(appCode, request, input = {}) {
343
- const query = new URLSearchParams({
344
- category: input.category || "pending",
345
- limit: String(Math.min(Math.max(Number(input.limit) || 50, 1), 200)),
477
+ async workflowNodeConfigurations(appCode, workflowCode, environmentKey) {
478
+ return await this.json(`${this.administrationPath(appCode)}/workflows/${encodeURIComponent(workflowCode)}/node-configurations?${this.query({ environmentKey })}`);
479
+ }
480
+ async nativeAuthorizationCatalog(appCode, input = {}) {
481
+ const query = this.query({
482
+ environmentKey: input.environmentKey || "preproduction",
346
483
  });
347
- return await this.json(`${this.workflowPath(appCode)}/kernel/work-center?${query}`, { headers: this.roleSessionHeaders(request) });
484
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/catalog?${query}`);
348
485
  }
349
- async workflowDiagnostics(appCode, limit = 100) {
350
- return await this.json(`${this.workflowPath(appCode)}/diagnostics?limit=${Math.min(Math.max(Number(limit) || 100, 1), 500)}`);
486
+ async nativeScopeValues(appCode, input) {
487
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/scope-values?${this.query({
488
+ ...input,
489
+ environmentKey: input.environmentKey || "preproduction",
490
+ })}`);
491
+ }
492
+ async nativeRoleMemberships(appCode, input = {}) {
493
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/memberships?${this.query({
494
+ ...input,
495
+ environmentKey: input.environmentKey || "preproduction",
496
+ })}`);
497
+ }
498
+ async createNativeRoleMembership(appCode, input) {
499
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/memberships`, {
500
+ method: "POST",
501
+ body: JSON.stringify(input),
502
+ });
351
503
  }
352
- async bootstrapRoleSession(appCode) {
353
- return await this.json(`${this.authzPath(appCode)}/role-session`);
504
+ async updateNativeRoleMembership(appCode, membershipId, input) {
505
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/memberships/${encodeURIComponent(membershipId)}/update`, {
506
+ method: "POST",
507
+ body: JSON.stringify(input),
508
+ });
354
509
  }
355
- async switchRoleSession(appCode, roleAssignmentId) {
356
- return await this.json(`${this.authzPath(appCode)}/role-session/switch`, {
510
+ async revokeNativeRoleMembership(appCode, membershipId, input) {
511
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/memberships/${encodeURIComponent(membershipId)}/revoke`, {
357
512
  method: "POST",
358
- body: JSON.stringify({ roleAssignmentId }),
513
+ body: JSON.stringify(input),
359
514
  });
360
515
  }
361
- async currentPrincipal(appCode, request) {
362
- return await this.json(`${this.authzPath(appCode)}/principal`, { headers: this.roleSessionHeaders(request) });
516
+ async nativeRoleManagementGrants(appCode, input = {}) {
517
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/role-management-grants?${this.query({
518
+ ...input,
519
+ environmentKey: input.environmentKey || "preproduction",
520
+ })}`);
521
+ }
522
+ async createNativeRoleManagementGrant(appCode, input) {
523
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/role-management-grants`, { method: "POST", body: JSON.stringify(input) });
524
+ }
525
+ async updateNativeRoleManagementGrant(appCode, grantId, input) {
526
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/role-management-grants/${encodeURIComponent(grantId)}/update`, { method: "POST", body: JSON.stringify(input) });
527
+ }
528
+ async revokeNativeRoleManagementGrant(appCode, grantId, input) {
529
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/role-management-grants/${encodeURIComponent(grantId)}/revoke`, { method: "POST", body: JSON.stringify(input) });
530
+ }
531
+ async nativeAuthorizationMutationReceipt(appCode, operationId) {
532
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/mutation-receipts/${encodeURIComponent(operationId)}`);
533
+ }
534
+ async nativeSuperAdmins(appCode, input = {}) {
535
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/super-admins?${this.query({ ...input, environmentKey: input.environmentKey || "preproduction" })}`);
536
+ }
537
+ async grantNativeSuperAdmin(appCode, input) {
538
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/super-admins`, {
539
+ method: "POST",
540
+ body: JSON.stringify(input),
541
+ });
542
+ }
543
+ async revokeNativeSuperAdmin(appCode, grantId, input) {
544
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/super-admins/${encodeURIComponent(grantId)}/revoke`, {
545
+ method: "POST",
546
+ body: JSON.stringify(input),
547
+ });
548
+ }
549
+ async nativeRelationshipGrants(appCode, input = {}) {
550
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/relationship-grants?${this.query({
551
+ ...input,
552
+ environmentKey: input.environmentKey || "preproduction",
553
+ })}`);
554
+ }
555
+ async createNativeRelationshipGrant(appCode, input) {
556
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/relationship-grants`, {
557
+ method: "POST",
558
+ body: JSON.stringify(input),
559
+ });
560
+ }
561
+ async updateNativeRelationshipGrant(appCode, grantId, input) {
562
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/relationship-grants/${encodeURIComponent(grantId)}/update`, {
563
+ method: "POST",
564
+ body: JSON.stringify(input),
565
+ });
566
+ }
567
+ async revokeNativeRelationshipGrant(appCode, grantId, input) {
568
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/relationship-grants/${encodeURIComponent(grantId)}/revoke`, {
569
+ method: "POST",
570
+ body: JSON.stringify(input),
571
+ });
572
+ }
573
+ async nativeAuthorizationProjectionHealth(appCode, environmentKey = "preproduction") {
574
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/projections/health?${this.query({ environmentKey })}`);
575
+ }
576
+ async rebuildNativeAuthorizationProjections(appCode, input) {
577
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/projections/rebuild`, { method: "POST", body: JSON.stringify(input) });
578
+ }
579
+ async recoverNativeAuthorizationProjection(appCode, jobId, input) {
580
+ return await this.json(`${this.nativeAuthzManagementPath(appCode)}/projections/jobs/${encodeURIComponent(jobId)}/recover`, { method: "POST", body: JSON.stringify(input) });
363
581
  }
364
582
  async myRoleAssignments(appCode) {
365
583
  return await this.json(`${this.authzPath(appCode)}/assignments/me`);
@@ -376,38 +594,37 @@ export class OpenXiangdaControlPlaneClient {
376
594
  async revokeRoleAssignment(appCode, assignmentId, expectedRevision) {
377
595
  return await this.json(`${this.authzPath(appCode)}/assignments/${encodeURIComponent(assignmentId)}/revoke`, { method: "POST", body: JSON.stringify({ expectedRevision }) });
378
596
  }
379
- async explainAuthorization(appCode, input) {
380
- const { roleSessionId, ...body } = input;
381
- return await this.json(`${this.authzPath(appCode)}/explain`, {
382
- method: "POST",
383
- body: JSON.stringify(body),
384
- headers: this.roleSessionHeaders({ roleSessionId }),
385
- });
386
- }
387
- async explainAuthorizations(appCode, input) {
388
- return await this.json(`${this.authzPath(appCode)}/explain-batch`, {
389
- method: "POST",
390
- body: JSON.stringify({
391
- schemaVersion: SCHEMA_VERSIONS.authorizationBatchRequest,
392
- requests: input.requests,
393
- }),
394
- headers: this.roleSessionHeaders({
395
- roleSessionId: input.roleSessionId,
396
- }),
397
- });
398
- }
399
- async searchDirectoryEntries(appCode, kind, input, request) {
597
+ async searchDirectoryEntries(appCode, kind, input) {
400
598
  const query = new URLSearchParams({
401
599
  keyword: input.keyword.trim(),
402
600
  limit: String(Math.min(Math.max(Number(input.limit) || 20, 1), 50)),
403
601
  });
404
- return await this.json(`${this.directoryPath(appCode)}/${kind}s?${query}`, { headers: this.roleSessionHeaders(request) });
602
+ return await this.json(`${this.directoryPath(appCode)}/${kind}s?${query}`);
603
+ }
604
+ async browseDepartmentEntries(appCode, input) {
605
+ const query = new URLSearchParams({
606
+ offset: String(Math.max(Number(input.offset) || 0, 0)),
607
+ limit: String(Math.min(Math.max(Number(input.limit) || 100, 1), 100)),
608
+ });
609
+ const parentId = String(input.parentId || "").trim();
610
+ if (parentId)
611
+ query.set("parentId", parentId);
612
+ return await this.json(`${this.directoryPath(appCode)}/departments/tree?${query}`);
613
+ }
614
+ async browseDepartmentUserEntries(appCode, input) {
615
+ const departmentId = String(input.departmentId || "").trim();
616
+ if (!departmentId)
617
+ throw new Error("departmentId is required");
618
+ const query = new URLSearchParams({
619
+ page: String(Math.max(Number(input.page) || 1, 1)),
620
+ limit: String(Math.min(Math.max(Number(input.limit) || 50, 1), 100)),
621
+ });
622
+ return await this.json(`${this.directoryPath(appCode)}/departments/${encodeURIComponent(departmentId)}/users?${query}`);
405
623
  }
406
- async resolveDirectoryEntries(appCode, input, request) {
624
+ async resolveDirectoryEntries(appCode, input) {
407
625
  return await this.json(`${this.directoryPath(appCode)}/resolve`, {
408
626
  method: "POST",
409
627
  body: JSON.stringify(input),
410
- headers: this.roleSessionHeaders(request),
411
628
  });
412
629
  }
413
630
  async applyDataResource(resource, input = {}) {
@@ -445,17 +662,24 @@ export class OpenXiangdaControlPlaneClient {
445
662
  return await this.json(this.dataPath(appCode, resourceCode, "query"), {
446
663
  method: "POST",
447
664
  body: JSON.stringify(query),
448
- headers: this.optionalRoleSessionHeaders(request),
665
+ headers: this.perspectiveHeaders(request),
449
666
  });
450
667
  }
668
+ async chinaDivisions(parentAdcode) {
669
+ const query = new URLSearchParams();
670
+ if (parentAdcode)
671
+ query.set("parentAdcode", parentAdcode);
672
+ const suffix = query.size ? `?${query}` : "";
673
+ return await this.json(`/china-divisions/${suffix}`);
674
+ }
451
675
  async getData(appCode, resourceCode, id, request = {}) {
452
- return await this.json(this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}`), { headers: this.optionalRoleSessionHeaders(request) });
676
+ return await this.json(this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}`), { headers: this.perspectiveHeaders(request) });
453
677
  }
454
678
  async aggregateData(appCode, resourceCode, query, request = {}) {
455
679
  return await this.json(this.dataPath(appCode, resourceCode, "aggregate"), {
456
680
  method: "POST",
457
681
  body: JSON.stringify(query),
458
- headers: this.optionalRoleSessionHeaders(request),
682
+ headers: this.perspectiveHeaders(request),
459
683
  });
460
684
  }
461
685
  async dataAudit(appCode, resourceCode, id, input = {}, request = {}) {
@@ -465,40 +689,45 @@ export class OpenXiangdaControlPlaneClient {
465
689
  if (input.offset !== undefined)
466
690
  query.set("offset", String(input.offset));
467
691
  const suffix = query.size ? `?${query}` : "";
468
- return await this.json(`${this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}/audit`)}${suffix}`, { headers: this.optionalRoleSessionHeaders(request) });
692
+ return await this.json(`${this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}/audit`)}${suffix}`, { headers: this.perspectiveHeaders(request) });
469
693
  }
470
694
  async initiateDataFileUpload(appCode, resourceCode, input, request = {}) {
471
695
  return await this.json(this.dataPath(appCode, resourceCode, "files/uploads/initiate"), {
472
696
  method: "POST",
473
697
  body: JSON.stringify(input),
474
- headers: this.optionalRoleSessionHeaders(request),
698
+ headers: this.perspectiveHeaders(request),
475
699
  });
476
700
  }
477
701
  async completeDataFileUpload(appCode, resourceCode, fileId, request = {}) {
478
702
  return await this.json(this.dataPath(appCode, resourceCode, `files/${encodeURIComponent(fileId)}/complete`), {
479
703
  method: "POST",
480
704
  body: "{}",
481
- headers: this.optionalRoleSessionHeaders(request),
705
+ headers: this.perspectiveHeaders(request),
482
706
  });
483
707
  }
484
- async deleteUnboundDataFile(appCode, resourceCode, fileId, request = {}) {
708
+ async deleteUnreferencedDataFile(appCode, resourceCode, fileId, request = {}) {
485
709
  return await this.json(this.dataPath(appCode, resourceCode, `files/${encodeURIComponent(fileId)}/delete`), {
486
710
  method: "POST",
487
711
  body: "{}",
488
- headers: this.optionalRoleSessionHeaders(request),
712
+ headers: this.perspectiveHeaders(request),
489
713
  });
490
714
  }
491
715
  async dataFileContent(appCode, resourceCode, fileId, request = {}) {
492
716
  const path = this.dataPath(appCode, resourceCode, `files/${encodeURIComponent(fileId)}/content`);
493
- const response = await this.fetch(`${this.baseUrl}${path}`, {
494
- credentials: this.options.credentials || "same-origin",
495
- headers: {
496
- ...(this.options.token
497
- ? { Authorization: `Bearer ${this.options.token}` }
498
- : {}),
499
- ...this.optionalRoleSessionHeaders(request),
500
- },
501
- });
717
+ const download = async (forceRefresh) => {
718
+ const token = await this.accessToken(forceRefresh);
719
+ return await this.fetch(`${this.baseUrl}${path}`, {
720
+ credentials: this.options.credentials || "same-origin",
721
+ headers: {
722
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
723
+ ...this.perspectiveHeaders(request),
724
+ },
725
+ });
726
+ };
727
+ let response = await download(false);
728
+ if (response.status === 401 && this.options.tokenProvider) {
729
+ response = await download(true);
730
+ }
502
731
  if (!response.ok) {
503
732
  let data = null;
504
733
  try {
@@ -515,32 +744,32 @@ export class OpenXiangdaControlPlaneClient {
515
744
  return await this.json(this.dataPath(appCode, resourceCode, "records"), {
516
745
  method: "POST",
517
746
  body: JSON.stringify({ data }),
518
- headers: this.optionalRoleSessionHeaders(request),
747
+ headers: this.perspectiveHeaders(request),
519
748
  });
520
749
  }
521
750
  async updateData(appCode, resourceCode, id, input, request = {}) {
522
751
  return await this.json(this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}/update`), {
523
752
  method: "POST",
524
753
  body: JSON.stringify(input),
525
- headers: this.optionalRoleSessionHeaders(request),
754
+ headers: this.perspectiveHeaders(request),
526
755
  });
527
756
  }
528
757
  async deleteData(appCode, resourceCode, id, expectedRevision, request = {}) {
529
758
  return await this.json(this.dataPath(appCode, resourceCode, `records/${encodeURIComponent(id)}/delete`), {
530
759
  method: "POST",
531
760
  body: JSON.stringify({ expectedRevision }),
532
- headers: this.optionalRoleSessionHeaders(request),
761
+ headers: this.perspectiveHeaders(request),
533
762
  });
534
763
  }
535
764
  async transactData(appCode, transaction, request = {}) {
536
- return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/data/transactions`, {
765
+ return await this.json(`/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/native/data/transactions`, {
537
766
  method: "POST",
538
767
  body: JSON.stringify(transaction),
539
- headers: this.optionalRoleSessionHeaders(request),
768
+ headers: this.perspectiveHeaders(request),
540
769
  });
541
770
  }
542
771
  dataPath(appCode, resourceCode, suffix) {
543
- return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/data/${encodeURIComponent(resourceCode)}/${suffix}`;
772
+ return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/native/data/${encodeURIComponent(resourceCode)}/${suffix}`;
544
773
  }
545
774
  applicationApiPath(appCode, environmentKey, runtimePath, query = {}) {
546
775
  const normalized = String(runtimePath || "")
@@ -579,6 +808,21 @@ export class OpenXiangdaControlPlaneClient {
579
808
  authzPath(appCode) {
580
809
  return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/authz`;
581
810
  }
811
+ nativeAuthzPath(appCode) {
812
+ return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/native/authz`;
813
+ }
814
+ nativeAuthzManagementPath(appCode) {
815
+ return `${this.nativeAuthzPath(appCode)}/management`;
816
+ }
817
+ query(input) {
818
+ const query = new URLSearchParams();
819
+ for (const [key, value] of Object.entries(input)) {
820
+ if (value === undefined || value === null || value === "")
821
+ continue;
822
+ query.set(key, String(value));
823
+ }
824
+ return query.toString();
825
+ }
582
826
  directoryPath(appCode) {
583
827
  return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/directory`;
584
828
  }
@@ -591,21 +835,28 @@ export class OpenXiangdaControlPlaneClient {
591
835
  eventsPath(appCode) {
592
836
  return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/events`;
593
837
  }
838
+ connectedDevelopmentSessionsPath(appCode) {
839
+ return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/dev-sessions`;
840
+ }
841
+ connectedDevelopmentSessionHeaders(sessionToken) {
842
+ const token = String(sessionToken || "").trim();
843
+ if (!token)
844
+ throw new Error("OPENXIANGDA_CONNECTED_DEV_SESSION_REQUIRED");
845
+ return { "X-OpenXiangda-Dev-Session": token };
846
+ }
594
847
  workflowPath(appCode) {
595
848
  return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/workflow`;
596
849
  }
597
- roleSessionHeaders(request) {
598
- if (!request?.roleSessionId?.trim()) {
599
- throw new ControlPlaneError(400, "ROLE_SESSION_REQUIRED", "OpenXiangda v2 用户作用域请求必须显式携带 roleSessionId");
600
- }
601
- return {
602
- "X-OpenXiangda-Role-Session-Id": request.roleSessionId,
603
- };
850
+ administrationPath(appCode) {
851
+ return `/openxiangda-api/v2/applications/${encodeURIComponent(appCode)}/admin`;
604
852
  }
605
- optionalRoleSessionHeaders(request) {
606
- const roleSessionId = String(request?.roleSessionId || "").trim();
607
- return roleSessionId
608
- ? { "X-OpenXiangda-Role-Session-Id": roleSessionId }
853
+ perspectiveHeaders(request) {
854
+ const perspectiveCode = String(request?.perspectiveCode || "").trim();
855
+ if (perspectiveCode && !/^[a-z][a-z0-9._-]{0,127}$/.test(perspectiveCode)) {
856
+ throw new ControlPlaneError(400, "OPENXIANGDA_PERSPECTIVE_INVALID", "perspectiveCode must be a stable lowercase identifier");
857
+ }
858
+ return perspectiveCode
859
+ ? { "X-OpenXiangda-Perspective": perspectiveCode }
609
860
  : {};
610
861
  }
611
862
  basicCredentials(clientId, clientSecret) {
@@ -623,15 +874,24 @@ export class OpenXiangdaControlPlaneClient {
623
874
  },
624
875
  });
625
876
  }
626
- async request(path, init = {}) {
627
- const response = await this.fetch(`${this.baseUrl}${path}`, {
877
+ async request(path, init = {}, fetcher = this.fetch) {
878
+ try {
879
+ return await this.requestOnce(path, init, false, fetcher);
880
+ }
881
+ catch (error) {
882
+ if (!this.options.tokenProvider || !this.isUnauthorized(error))
883
+ throw error;
884
+ return await this.requestOnce(path, init, true, fetcher);
885
+ }
886
+ }
887
+ async requestOnce(path, init, forceRefresh, fetcher) {
888
+ const token = await this.accessToken(forceRefresh);
889
+ const response = await fetcher(`${this.baseUrl}${path}`, {
628
890
  ...init,
629
891
  credentials: init.credentials || this.options.credentials || "same-origin",
630
892
  headers: {
631
893
  Accept: "application/json",
632
- ...(this.options.token
633
- ? { Authorization: `Bearer ${this.options.token}` }
634
- : {}),
894
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
635
895
  ...(init.headers || {}),
636
896
  },
637
897
  });
@@ -643,9 +903,28 @@ export class OpenXiangdaControlPlaneClient {
643
903
  throw new ControlPlaneError(response.status, "CONTROL_PLANE_RESPONSE_INVALID", "平台返回的不是有效 JSON");
644
904
  }
645
905
  if (!response.ok || Number(envelope.code) >= 400) {
646
- throw new ControlPlaneError(response.status, envelope.errorCode || "CONTROL_PLANE_REQUEST_FAILED", envelope.message || `平台请求失败: ${response.status}`, envelope.data);
906
+ const status = response.ok ? Number(envelope.code) : response.status;
907
+ throw new ControlPlaneError(status, envelope.errorCode || "CONTROL_PLANE_REQUEST_FAILED", envelope.message || `平台请求失败: ${response.status}`, envelope.data, {
908
+ ...(envelope.retryable === undefined
909
+ ? {}
910
+ : { retryable: envelope.retryable }),
911
+ ...(envelope.remediation
912
+ ? { remediation: envelope.remediation }
913
+ : {}),
914
+ ...(envelope.requestId ? { requestId: envelope.requestId } : {}),
915
+ ...(envelope.path ? { path: envelope.path } : {}),
916
+ ...(envelope.field ? { field: envelope.field } : {}),
917
+ });
647
918
  }
648
919
  return envelope.data;
649
920
  }
921
+ isUnauthorized(error) {
922
+ return error instanceof ControlPlaneError && error.status === 401;
923
+ }
924
+ async accessToken(forceRefresh) {
925
+ return this.options.tokenProvider
926
+ ? await this.options.tokenProvider.getAccessToken({ forceRefresh })
927
+ : this.options.token;
928
+ }
650
929
  }
651
930
  //# sourceMappingURL=control-plane-client.js.map