@treeseed/sdk 0.10.28 → 0.11.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 (148) hide show
  1. package/README.md +207 -6
  2. package/dist/capacity-provider.d.ts +3 -1
  3. package/dist/capacity-provider.js +25 -5
  4. package/dist/control-plane.d.ts +1 -0
  5. package/dist/control-plane.js +38 -13
  6. package/dist/db/market-schema.d.ts +8860 -6172
  7. package/dist/db/market-schema.js +108 -0
  8. package/dist/db/node-sqlite.js +7 -2
  9. package/dist/hosting/apps.d.ts +12 -0
  10. package/dist/hosting/apps.js +107 -0
  11. package/dist/hosting/builtins.d.ts +25 -0
  12. package/dist/hosting/builtins.js +791 -0
  13. package/dist/hosting/contracts.d.ts +207 -0
  14. package/dist/hosting/contracts.js +0 -0
  15. package/dist/hosting/graph.d.ts +192 -0
  16. package/dist/hosting/graph.js +1106 -0
  17. package/dist/hosting/index.d.ts +4 -0
  18. package/dist/hosting/index.js +4 -0
  19. package/dist/index.d.ts +10 -3
  20. package/dist/index.js +63 -6
  21. package/dist/managed-dependencies.js +1 -2
  22. package/dist/market-client.d.ts +63 -3
  23. package/dist/market-client.js +83 -11
  24. package/dist/operations/services/bootstrap-runner.d.ts +3 -1
  25. package/dist/operations/services/bootstrap-runner.js +22 -2
  26. package/dist/operations/services/config-runtime.d.ts +10 -5
  27. package/dist/operations/services/config-runtime.js +209 -66
  28. package/dist/operations/services/deploy.d.ts +70 -7
  29. package/dist/operations/services/deploy.js +579 -64
  30. package/dist/operations/services/deployment-readiness.d.ts +30 -0
  31. package/dist/operations/services/deployment-readiness.js +175 -0
  32. package/dist/operations/services/git-workflow.d.ts +2 -1
  33. package/dist/operations/services/git-workflow.js +9 -3
  34. package/dist/operations/services/github-actions-verification.d.ts +1 -0
  35. package/dist/operations/services/github-actions-verification.js +1 -0
  36. package/dist/operations/services/github-api.js +1 -1
  37. package/dist/operations/services/github-automation.d.ts +1 -1
  38. package/dist/operations/services/github-automation.js +4 -3
  39. package/dist/operations/services/github-credentials.d.ts +13 -0
  40. package/dist/operations/services/github-credentials.js +58 -0
  41. package/dist/operations/services/hosted-service-checks.d.ts +63 -0
  42. package/dist/operations/services/hosted-service-checks.js +327 -0
  43. package/dist/operations/services/hub-provider-launch.js +3 -3
  44. package/dist/operations/services/live-hosted-service-checks.d.ts +25 -0
  45. package/dist/operations/services/live-hosted-service-checks.js +350 -0
  46. package/dist/operations/services/managed-host-security.js +1 -1
  47. package/dist/operations/services/operations-runner-smoke.d.ts +30 -0
  48. package/dist/operations/services/operations-runner-smoke.js +180 -0
  49. package/dist/operations/services/package-adapters.d.ts +95 -0
  50. package/dist/operations/services/package-adapters.js +288 -0
  51. package/dist/operations/services/package-reference-policy.d.ts +1 -0
  52. package/dist/operations/services/package-reference-policy.js +15 -2
  53. package/dist/operations/services/project-platform.d.ts +80 -22
  54. package/dist/operations/services/project-platform.js +49 -8
  55. package/dist/operations/services/project-web-monitor.js +26 -4
  56. package/dist/operations/services/railway-api.d.ts +88 -5
  57. package/dist/operations/services/railway-api.js +626 -35
  58. package/dist/operations/services/railway-deploy.d.ts +46 -40
  59. package/dist/operations/services/railway-deploy.js +261 -293
  60. package/dist/operations/services/release-candidate.d.ts +19 -0
  61. package/dist/operations/services/release-candidate.js +375 -38
  62. package/dist/operations/services/repository-save-orchestrator.d.ts +3 -1
  63. package/dist/operations/services/repository-save-orchestrator.js +279 -66
  64. package/dist/operations/services/runtime-tools.d.ts +1 -0
  65. package/dist/operations/services/runtime-tools.js +10 -9
  66. package/dist/operations/services/verification-cache.d.ts +25 -0
  67. package/dist/operations/services/verification-cache.js +71 -0
  68. package/dist/operations/services/workspace-dependency-mode.js +9 -1
  69. package/dist/operations/services/workspace-save.js +1 -1
  70. package/dist/operations/services/workspace-tools.js +2 -1
  71. package/dist/platform/contracts.d.ts +32 -1
  72. package/dist/platform/deploy-config.js +73 -8
  73. package/dist/platform/env.yaml +163 -35
  74. package/dist/platform/environment.d.ts +1 -0
  75. package/dist/platform/environment.js +74 -5
  76. package/dist/platform/plugin.d.ts +9 -0
  77. package/dist/platform-operation-store.js +2 -2
  78. package/dist/platform-operations.js +1 -1
  79. package/dist/reconcile/bootstrap-systems.js +2 -2
  80. package/dist/reconcile/builtin-adapters.js +372 -189
  81. package/dist/reconcile/contracts.d.ts +9 -5
  82. package/dist/reconcile/desired-state.d.ts +1 -0
  83. package/dist/reconcile/desired-state.js +5 -5
  84. package/dist/reconcile/engine.d.ts +5 -2
  85. package/dist/reconcile/engine.js +53 -32
  86. package/dist/reconcile/index.d.ts +2 -0
  87. package/dist/reconcile/index.js +2 -0
  88. package/dist/reconcile/live-acceptance.d.ts +79 -0
  89. package/dist/reconcile/live-acceptance.js +1615 -0
  90. package/dist/reconcile/platform.d.ts +104 -0
  91. package/dist/reconcile/platform.js +100 -0
  92. package/dist/reconcile/state.js +4 -4
  93. package/dist/reconcile/units.js +2 -2
  94. package/dist/scripts/deployment-readiness.js +20 -0
  95. package/dist/scripts/generate-treedx-openapi-types.js +186 -0
  96. package/dist/scripts/operations-runner-smoke.js +16 -0
  97. package/dist/scripts/release-verify.js +4 -1
  98. package/dist/scripts/tenant-workflow-action.js +10 -1
  99. package/dist/sdk-types.d.ts +169 -4
  100. package/dist/sdk-types.js +20 -2
  101. package/dist/sdk.d.ts +35 -24
  102. package/dist/sdk.js +186 -17
  103. package/dist/template-launch-requirements.js +9 -0
  104. package/dist/treedx/adapters.d.ts +6 -0
  105. package/dist/treedx/adapters.js +36 -0
  106. package/dist/treedx/client.d.ts +222 -0
  107. package/dist/treedx/client.js +871 -0
  108. package/dist/treedx/errors.d.ts +13 -0
  109. package/dist/treedx/errors.js +17 -0
  110. package/dist/treedx/federated-client.d.ts +27 -0
  111. package/dist/treedx/federated-client.js +158 -0
  112. package/dist/treedx/generated/openapi-types.d.ts +3558 -0
  113. package/dist/treedx/generated/openapi-types.js +0 -0
  114. package/dist/treedx/graph-adapter.d.ts +33 -0
  115. package/dist/treedx/graph-adapter.js +156 -0
  116. package/dist/treedx/index.d.ts +14 -0
  117. package/dist/treedx/index.js +48 -0
  118. package/dist/treedx/market-integration.d.ts +27 -0
  119. package/dist/treedx/market-integration.js +131 -0
  120. package/dist/treedx/ports.d.ts +166 -0
  121. package/dist/treedx/ports.js +231 -0
  122. package/dist/treedx/query-adapter.d.ts +19 -0
  123. package/dist/treedx/query-adapter.js +62 -0
  124. package/dist/treedx/registry-client.d.ts +11 -0
  125. package/dist/treedx/registry-client.js +19 -0
  126. package/dist/treedx/repository-adapter.d.ts +45 -0
  127. package/dist/treedx/repository-adapter.js +308 -0
  128. package/dist/treedx/sdk-integration.d.ts +27 -0
  129. package/dist/treedx/sdk-integration.js +63 -0
  130. package/dist/treedx/types.d.ts +1084 -0
  131. package/dist/treedx/types.js +8 -0
  132. package/dist/treedx/workspace-adapter.d.ts +27 -0
  133. package/dist/treedx/workspace-adapter.js +65 -0
  134. package/dist/treedx-backends.d.ts +218 -0
  135. package/dist/treedx-backends.js +632 -0
  136. package/dist/treedx-client.d.ts +86 -0
  137. package/dist/treedx-client.js +175 -0
  138. package/dist/treeseed/template-catalog/catalog.fixture.json +23 -23
  139. package/dist/workflow/operations.d.ts +119 -13
  140. package/dist/workflow/operations.js +309 -53
  141. package/dist/workflow-state.d.ts +13 -0
  142. package/dist/workflow-state.js +43 -26
  143. package/dist/workflow-support.d.ts +11 -3
  144. package/dist/workflow-support.js +67 -3
  145. package/dist/workflow.d.ts +5 -0
  146. package/drizzle/market/0004_treedx_market_integration.sql +99 -0
  147. package/package.json +34 -3
  148. package/templates/github/deploy-web.workflow.yml +39 -6
@@ -0,0 +1,86 @@
1
+ export interface TreeDxClientConfig {
2
+ baseUrl: string;
3
+ token?: string;
4
+ fetchImpl?: typeof fetch;
5
+ transport?: Transport;
6
+ defaultHeaders?: Record<string, string>;
7
+ }
8
+ export interface TreeDxRequest {
9
+ method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
10
+ path: string;
11
+ query?: Record<string, string | number | boolean | undefined>;
12
+ headers?: Record<string, string>;
13
+ body?: unknown;
14
+ binaryBody?: Uint8Array | ArrayBuffer | Buffer | ReadableStream<Uint8Array>;
15
+ }
16
+ export interface TreeDxResponse<T = unknown> {
17
+ status: number;
18
+ headers: Record<string, string>;
19
+ data: T;
20
+ }
21
+ export interface Transport {
22
+ request<T = unknown>(request: TreeDxRequest): Promise<TreeDxResponse<T>>;
23
+ }
24
+ export declare class TreeDxApiError extends Error {
25
+ readonly status: number;
26
+ readonly code: string;
27
+ readonly details?: unknown;
28
+ readonly payload?: unknown;
29
+ readonly cause?: unknown;
30
+ constructor(input: {
31
+ status: number;
32
+ code: string;
33
+ message: string;
34
+ details?: unknown;
35
+ payload?: unknown;
36
+ cause?: unknown;
37
+ });
38
+ static fromResponse(status: number, payload: unknown): TreeDxApiError;
39
+ static network(message: string, cause?: unknown): TreeDxApiError;
40
+ }
41
+ export declare class TreeDxClient {
42
+ readonly config: TreeDxClientConfig;
43
+ readonly transport: Transport;
44
+ readonly repositories: RepositoriesAdapter;
45
+ readonly query: QueryAdapter;
46
+ readonly files: FilesAdapter;
47
+ readonly graph: GraphAdapter;
48
+ readonly federation: FederationAdapter;
49
+ readonly exec: ExecAdapter;
50
+ constructor(config: TreeDxClientConfig);
51
+ }
52
+ declare class RepositoriesAdapter {
53
+ private readonly transport;
54
+ constructor(transport: Transport);
55
+ list(): Promise<unknown>;
56
+ }
57
+ declare class QueryAdapter {
58
+ private readonly transport;
59
+ constructor(transport: Transport);
60
+ readFile(repoId: string, body: unknown): Promise<unknown>;
61
+ listPaths(repoId: string, body: unknown): Promise<unknown>;
62
+ searchFiles(repoId: string, body: unknown): Promise<unknown>;
63
+ }
64
+ declare class FilesAdapter {
65
+ private readonly transport;
66
+ constructor(transport: Transport);
67
+ write(workspaceId: string, body: unknown): Promise<unknown>;
68
+ patch(workspaceId: string, body: unknown): Promise<unknown>;
69
+ }
70
+ declare class GraphAdapter {
71
+ private readonly transport;
72
+ constructor(transport: Transport);
73
+ refresh(repoId: string, body: unknown): Promise<unknown>;
74
+ }
75
+ declare class FederationAdapter {
76
+ private readonly transport;
77
+ constructor(transport: Transport);
78
+ graphQuery(body: unknown): Promise<unknown>;
79
+ contextBuild(body: unknown): Promise<unknown>;
80
+ }
81
+ declare class ExecAdapter {
82
+ private readonly transport;
83
+ constructor(transport: Transport);
84
+ run(workspaceId: string, body: unknown): Promise<unknown>;
85
+ }
86
+ export {};
@@ -0,0 +1,175 @@
1
+ class TreeDxApiError extends Error {
2
+ status;
3
+ code;
4
+ details;
5
+ payload;
6
+ cause;
7
+ constructor(input) {
8
+ super(input.message);
9
+ this.name = "TreeDxApiError";
10
+ this.status = input.status;
11
+ this.code = input.code;
12
+ this.details = input.details;
13
+ this.payload = input.payload;
14
+ this.cause = input.cause;
15
+ }
16
+ static fromResponse(status, payload) {
17
+ const envelope = payload;
18
+ return new TreeDxApiError({
19
+ status,
20
+ code: envelope?.error?.code ?? "internal_error",
21
+ message: envelope?.error?.message ?? `TreeDX request failed with status ${status}`,
22
+ details: envelope?.error?.details,
23
+ payload
24
+ });
25
+ }
26
+ static network(message, cause) {
27
+ return new TreeDxApiError({
28
+ status: 0,
29
+ code: "network_error",
30
+ message,
31
+ cause
32
+ });
33
+ }
34
+ }
35
+ class FetchTreeDxTransport {
36
+ constructor(config) {
37
+ this.config = config;
38
+ }
39
+ config;
40
+ async request(request) {
41
+ const fetchImpl = this.config.fetchImpl ?? globalThis.fetch;
42
+ if (!fetchImpl) throw TreeDxApiError.network("fetch is not available in this runtime");
43
+ const url = new URL(request.path, this.config.baseUrl);
44
+ for (const [key, value] of Object.entries(request.query ?? {})) {
45
+ if (value !== void 0) url.searchParams.set(key, String(value));
46
+ }
47
+ const headers = new Headers({
48
+ ...this.config.defaultHeaders ?? {},
49
+ ...request.headers ?? {}
50
+ });
51
+ if (this.config.token) headers.set("Authorization", `Bearer ${this.config.token}`);
52
+ let body;
53
+ if (request.binaryBody) {
54
+ body = request.binaryBody;
55
+ } else if (request.body !== void 0) {
56
+ headers.set("Content-Type", headers.get("Content-Type") ?? "application/json");
57
+ body = JSON.stringify(request.body);
58
+ }
59
+ try {
60
+ const response = await fetchImpl(url, {
61
+ method: request.method,
62
+ headers,
63
+ body
64
+ });
65
+ const contentType = response.headers.get("content-type") ?? "";
66
+ const data = contentType.includes("application/json") ? await response.json() : await response.text();
67
+ if (!response.ok) throw TreeDxApiError.fromResponse(response.status, data);
68
+ return {
69
+ status: response.status,
70
+ headers: Object.fromEntries(response.headers.entries()),
71
+ data
72
+ };
73
+ } catch (error) {
74
+ if (error instanceof TreeDxApiError) throw error;
75
+ throw TreeDxApiError.network(error instanceof Error ? error.message : "TreeDX request failed", error);
76
+ }
77
+ }
78
+ }
79
+ function segment(value) {
80
+ return encodeURIComponent(value);
81
+ }
82
+ async function requestData(transport, request) {
83
+ const response = await transport.request(request);
84
+ return response.data;
85
+ }
86
+ class TreeDxClient {
87
+ constructor(config) {
88
+ this.config = config;
89
+ this.transport = config.transport ?? new FetchTreeDxTransport(config);
90
+ this.repositories = new RepositoriesAdapter(this.transport);
91
+ this.query = new QueryAdapter(this.transport);
92
+ this.files = new FilesAdapter(this.transport);
93
+ this.graph = new GraphAdapter(this.transport);
94
+ this.federation = new FederationAdapter(this.transport);
95
+ this.exec = new ExecAdapter(this.transport);
96
+ }
97
+ config;
98
+ transport;
99
+ repositories;
100
+ query;
101
+ files;
102
+ graph;
103
+ federation;
104
+ exec;
105
+ }
106
+ class RepositoriesAdapter {
107
+ constructor(transport) {
108
+ this.transport = transport;
109
+ }
110
+ transport;
111
+ list() {
112
+ return requestData(this.transport, { method: "GET", path: "/api/v1/repos" });
113
+ }
114
+ }
115
+ class QueryAdapter {
116
+ constructor(transport) {
117
+ this.transport = transport;
118
+ }
119
+ transport;
120
+ readFile(repoId, body) {
121
+ return requestData(this.transport, { method: "POST", path: `/api/v1/repos/${segment(repoId)}/files/read`, body });
122
+ }
123
+ listPaths(repoId, body) {
124
+ return requestData(this.transport, { method: "POST", path: `/api/v1/repos/${segment(repoId)}/paths/list`, body });
125
+ }
126
+ searchFiles(repoId, body) {
127
+ return requestData(this.transport, { method: "POST", path: `/api/v1/repos/${segment(repoId)}/search/files`, body });
128
+ }
129
+ }
130
+ class FilesAdapter {
131
+ constructor(transport) {
132
+ this.transport = transport;
133
+ }
134
+ transport;
135
+ write(workspaceId, body) {
136
+ return requestData(this.transport, { method: "PUT", path: `/api/v1/workspaces/${segment(workspaceId)}/files`, body });
137
+ }
138
+ patch(workspaceId, body) {
139
+ return requestData(this.transport, { method: "PATCH", path: `/api/v1/workspaces/${segment(workspaceId)}/files`, body });
140
+ }
141
+ }
142
+ class GraphAdapter {
143
+ constructor(transport) {
144
+ this.transport = transport;
145
+ }
146
+ transport;
147
+ refresh(repoId, body) {
148
+ return requestData(this.transport, { method: "POST", path: `/api/v1/repos/${segment(repoId)}/graph/refresh`, body });
149
+ }
150
+ }
151
+ class FederationAdapter {
152
+ constructor(transport) {
153
+ this.transport = transport;
154
+ }
155
+ transport;
156
+ graphQuery(body) {
157
+ return requestData(this.transport, { method: "POST", path: "/api/v1/graph/query", body });
158
+ }
159
+ contextBuild(body) {
160
+ return requestData(this.transport, { method: "POST", path: "/api/v1/context/build", body });
161
+ }
162
+ }
163
+ class ExecAdapter {
164
+ constructor(transport) {
165
+ this.transport = transport;
166
+ }
167
+ transport;
168
+ run(workspaceId, body) {
169
+ return requestData(this.transport, { method: "POST", path: `/api/v1/workspaces/${segment(workspaceId)}/exec`, body });
170
+ }
171
+ }
172
+ export {
173
+ TreeDxApiError,
174
+ TreeDxClient
175
+ };
@@ -664,7 +664,7 @@
664
664
  {
665
665
  "target": "treeseed.site.yaml",
666
666
  "path": "hosting.kind",
667
- "valueFrom": "literal.market_control_plane"
667
+ "valueFrom": "literal.treeseed_control_plane"
668
668
  },
669
669
  {
670
670
  "target": "treeseed.site.yaml",
@@ -704,44 +704,44 @@
704
704
  "resources": [
705
705
  {
706
706
  "kind": "resource",
707
- "key": "marketDatabase",
707
+ "key": "treeseedDatabase",
708
708
  "type": "database",
709
709
  "required": true,
710
710
  "compatibleProviders": [
711
711
  "railway-postgres"
712
712
  ],
713
- "displayName": "Market database",
714
- "purpose": "Provide the PostgreSQL database used by the Market API control plane.",
713
+ "displayName": "Treeseed database",
714
+ "purpose": "Provide the PostgreSQL database used by the API control plane.",
715
715
  "configWrites": [
716
716
  {
717
717
  "target": "treeseed.site.yaml",
718
- "path": "services.marketDatabase.enabled",
718
+ "path": "services.treeseedDatabase.enabled",
719
719
  "valueFrom": "literal.true"
720
720
  },
721
721
  {
722
722
  "target": "treeseed.site.yaml",
723
- "path": "services.marketDatabase.provider",
723
+ "path": "services.treeseedDatabase.provider",
724
724
  "valueFrom": "literal.railway"
725
725
  },
726
726
  {
727
727
  "target": "treeseed.site.yaml",
728
- "path": "services.marketDatabase.railway.resourceType",
728
+ "path": "services.treeseedDatabase.railway.resourceType",
729
729
  "valueFrom": "literal.postgres"
730
730
  },
731
731
  {
732
732
  "target": "treeseed.site.yaml",
733
- "path": "services.marketDatabase.railway.serviceName",
733
+ "path": "services.treeseedDatabase.railway.serviceName",
734
734
  "valueFrom": "selectedResource.configValues.serviceName"
735
735
  },
736
736
  {
737
737
  "target": "treeseed.site.yaml",
738
- "path": "services.marketDatabase.railway.environmentVariable",
739
- "valueFrom": "literal.TREESEED_MARKET_DATABASE_URL"
738
+ "path": "services.treeseedDatabase.railway.environmentVariable",
739
+ "valueFrom": "literal.TREESEED_DATABASE_URL"
740
740
  }
741
741
  ],
742
742
  "environmentWrites": [
743
743
  {
744
- "env": "TREESEED_MARKET_DATABASE_URL",
744
+ "env": "TREESEED_DATABASE_URL",
745
745
  "valueFrom": "selectedResource.secretRefs.databaseUrl",
746
746
  "targets": [
747
747
  "github-secret",
@@ -763,8 +763,8 @@
763
763
  "compatibleProviders": [
764
764
  "railway"
765
765
  ],
766
- "displayName": "Market API service",
767
- "purpose": "Run the Market API service that serves the control-plane routes.",
766
+ "displayName": "API service",
767
+ "purpose": "Run the API service that serves the control-plane routes.",
768
768
  "configWrites": [
769
769
  {
770
770
  "target": "treeseed.site.yaml",
@@ -794,7 +794,7 @@
794
794
  ],
795
795
  "environmentWrites": [
796
796
  {
797
- "env": "TREESEED_MARKET_DATABASE_URL",
797
+ "env": "TREESEED_DATABASE_URL",
798
798
  "valueFrom": "selectedResource.secretRefs.databaseUrl",
799
799
  "targets": [
800
800
  "railway-secret"
@@ -809,39 +809,39 @@
809
809
  },
810
810
  {
811
811
  "kind": "resource",
812
- "key": "marketOperationsRunner",
812
+ "key": "operationsRunner",
813
813
  "type": "service",
814
814
  "required": true,
815
815
  "compatibleProviders": [
816
816
  "railway"
817
817
  ],
818
- "displayName": "Market operations runner",
819
- "purpose": "Run the governed Market operations runner for queued control-plane operations.",
818
+ "displayName": "Treeseed operations runner",
819
+ "purpose": "Run the governed Treeseed operations runner for queued control-plane operations.",
820
820
  "configWrites": [
821
821
  {
822
822
  "target": "treeseed.site.yaml",
823
- "path": "services.marketOperationsRunner.enabled",
823
+ "path": "services.operationsRunner.enabled",
824
824
  "valueFrom": "literal.true"
825
825
  },
826
826
  {
827
827
  "target": "treeseed.site.yaml",
828
- "path": "services.marketOperationsRunner.provider",
828
+ "path": "services.operationsRunner.provider",
829
829
  "valueFrom": "literal.railway"
830
830
  },
831
831
  {
832
832
  "target": "treeseed.site.yaml",
833
- "path": "services.marketOperationsRunner.railway.serviceName",
833
+ "path": "services.operationsRunner.railway.serviceName",
834
834
  "valueFrom": "selectedResource.configValues.serviceName"
835
835
  },
836
836
  {
837
837
  "target": "treeseed.site.yaml",
838
- "path": "services.marketOperationsRunner.railway.startCommand",
839
- "valueFrom": "literal.node dist/market-operations-runner/runner.js"
838
+ "path": "services.operationsRunner.railway.startCommand",
839
+ "valueFrom": "literal.node dist/operations-runner/runner.js"
840
840
  }
841
841
  ],
842
842
  "environmentWrites": [
843
843
  {
844
- "env": "TREESEED_MARKET_DATABASE_URL",
844
+ "env": "TREESEED_DATABASE_URL",
845
845
  "valueFrom": "selectedResource.secretRefs.databaseUrl",
846
846
  "targets": [
847
847
  "railway-secret"