@fabrika/provider-zerops 0.2.0 → 0.3.1
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.
- package/package.json +18 -5
- package/src/api/client.ts +522 -0
- package/src/api/errors.ts +50 -0
- package/src/api/polling.ts +59 -0
- package/src/api/readers.ts +185 -0
- package/src/api/service-env-response.ts +34 -0
- package/src/api/types.ts +602 -0
- package/src/api.ts +29 -1378
- package/src/authoring.ts +7 -10
- package/src/cli-args.ts +0 -5
- package/src/cli.ts +3 -28
- package/src/collaborators.ts +2 -4
- package/src/compile.ts +3 -1
- package/src/control.ts +203 -450
- package/src/descriptor.ts +135 -0
- package/src/index.ts +23 -127
- package/src/installation/admin-options.ts +128 -0
- package/src/installation/admin.ts +123 -0
- package/src/installation/deploy-options.ts +155 -0
- package/src/installation/deploy.ts +668 -0
- package/src/installation/generated/platform-console-schema.ts +41 -0
- package/src/installation/generated/platform-proxy-manifest.ts +72 -0
- package/src/installation/hosts.ts +117 -0
- package/src/installation/index.ts +366 -0
- package/src/installation/init.ts +521 -0
- package/src/installation/install-collaborators.ts +28 -0
- package/src/installation/install-environment.ts +193 -0
- package/src/installation/install-options.ts +193 -0
- package/src/installation/install-project.ts +201 -0
- package/src/installation/install-provisioning.ts +185 -0
- package/src/installation/install.ts +286 -0
- package/src/installation/installation-source.ts +42 -0
- package/src/installation/log.ts +77 -0
- package/src/installation/machine-key.ts +65 -0
- package/src/installation/manifest.ts +95 -0
- package/src/installation/placement-options.ts +33 -0
- package/src/installation/platform-source.ts +106 -0
- package/src/installation/platform-upload.ts +34 -0
- package/src/installation/proxy-manifest.ts +113 -0
- package/src/installation/secrets.ts +79 -0
- package/src/installation/sidecar.ts +122 -0
- package/src/installation/source-options.ts +12 -0
- package/src/installation/templates/README.md +116 -0
- package/src/installation/templates/fabrika.ref +1 -0
- package/src/installation/templates/gitignore +3 -0
- package/src/installation/templates/platform.yml +144 -0
- package/src/installation/topology/artifacts.ts +141 -0
- package/src/installation/topology/index.ts +13 -0
- package/src/installation/topology/installation-schemas.ts +225 -0
- package/src/installation/topology/invariants.ts +86 -0
- package/src/installation/topology/setups.ts +442 -0
- package/src/installation/topology/topology.ts +501 -0
- package/src/installation/topology/validate.ts +26 -0
- package/src/installation/upgrade-options.ts +108 -0
- package/src/installation/upgrade-output.ts +31 -0
- package/src/installation/upgrade.ts +373 -0
- package/src/managed-env.ts +105 -0
- package/src/manifest.ts +191 -344
- package/src/namespace/claims.ts +77 -0
- package/src/namespace/codec.ts +179 -0
- package/src/namespace/constants.ts +30 -0
- package/src/namespace/errors.ts +60 -0
- package/src/namespace/manifest.ts +28 -0
- package/src/namespace/operator.ts +151 -0
- package/src/namespace/provisioning.ts +482 -0
- package/src/namespace/proxy-attempt.ts +220 -0
- package/src/namespace/proxy-source.ts +22 -0
- package/src/namespace/topology.ts +115 -0
- package/src/namespace/types.ts +114 -0
- package/src/namespace.ts +34 -1271
- package/src/plan.ts +21 -23
- package/src/provider.ts +266 -241
- package/src/source/constants.ts +11 -0
- package/src/source/port.ts +49 -0
- package/src/source/types.ts +4 -0
- package/src/source/validation.ts +72 -0
- package/src/source.ts +2 -1220
- package/src/types.ts +8 -7
- package/src/version-attempt.ts +18 -0
- package/src/codec.ts +0 -108
- package/src/namespace-command.ts +0 -209
- package/src/source-connection.ts +0 -344
package/src/types.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
ZeropsYamlSetup,
|
|
11
11
|
} from './schema.generated'
|
|
12
12
|
import type { ZeropsSourceRepository } from './source'
|
|
13
|
+
import type { ZeropsSourcePrivateBinding } from './source/port'
|
|
13
14
|
|
|
14
15
|
export interface ZeropsResourceContext {
|
|
15
16
|
env: string
|
|
@@ -119,15 +120,15 @@ export interface ZeropsRuntimeSource {
|
|
|
119
120
|
runId: string
|
|
120
121
|
repository: ZeropsSourceRepository
|
|
121
122
|
commitSha: string
|
|
122
|
-
|
|
123
|
+
/** Absent for a public repository. */
|
|
124
|
+
privateBinding?: ZeropsSourcePrivateBinding
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
/**
|
|
126
|
-
export
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| { appVersionId: string; phase: 'build_triggered'; processId?: string }
|
|
127
|
+
/** The run checkpoint (ADR-0044): the reserved version, and whether its build request may have been sent. */
|
|
128
|
+
export interface ZeropsRunState {
|
|
129
|
+
appVersionId: string
|
|
130
|
+
triggered: boolean
|
|
131
|
+
}
|
|
131
132
|
|
|
132
133
|
/** Ephemeral runtime coordinates. This value is encoded only after credentials are composed. */
|
|
133
134
|
export interface ZeropsRuntimeTarget {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ZeropsApiError } from './api/errors'
|
|
2
|
+
import type { ZeropsApi } from './api/types'
|
|
3
|
+
|
|
4
|
+
export const isVersionNotFound = (error: unknown): boolean =>
|
|
5
|
+
error instanceof ZeropsApiError && error.status === 400 && error.code === 'appVersionNotFound'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Delete a reserved version whose build was never requested. Deletion is the barrier: a later upload to
|
|
9
|
+
* it leaves nothing buildable and a build request fails `appVersionNotFound` (ADR-0044). An already
|
|
10
|
+
* absent version counts as deleted. Never call this once a build may have been submitted.
|
|
11
|
+
*/
|
|
12
|
+
export async function deleteVersion(api: Pick<ZeropsApi, 'deleteAppVersion'>, appVersionId: string, signal: AbortSignal): Promise<void> {
|
|
13
|
+
try {
|
|
14
|
+
await api.deleteAppVersion({ appVersionId, signal })
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (!isVersionNotFound(error)) throw error
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/codec.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import type { JsonValue, ProviderCodec } from '@fabrika/provider-contract'
|
|
2
|
-
import type { ZeropsRuntimeSource, ZeropsRuntimeTarget } from './types'
|
|
3
|
-
|
|
4
|
-
const field = (payload: JsonValue, key: string): JsonValue | undefined => {
|
|
5
|
-
if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
|
|
6
|
-
throw new Error('Zerops target must be an object')
|
|
7
|
-
}
|
|
8
|
-
return payload[key]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const requiredString = (payload: JsonValue, key: string): string => {
|
|
12
|
-
const value = field(payload, key)
|
|
13
|
-
if (typeof value !== 'string' || value === '') {
|
|
14
|
-
throw new Error(`Zerops target ${key} must be a non-empty string`)
|
|
15
|
-
}
|
|
16
|
-
return value
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const optionalString = (payload: JsonValue, key: string): string | undefined => {
|
|
20
|
-
const value = field(payload, key)
|
|
21
|
-
if (value === undefined) {
|
|
22
|
-
return undefined
|
|
23
|
-
}
|
|
24
|
-
if (typeof value !== 'string' || value === '') {
|
|
25
|
-
throw new Error(`Zerops target ${key} must be a non-empty string when present`)
|
|
26
|
-
}
|
|
27
|
-
return value
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const IMMUTABLE_GIT_OBJECT = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/
|
|
31
|
-
|
|
32
|
-
const object = (value: JsonValue | undefined, label: string): { readonly [key: string]: JsonValue } => {
|
|
33
|
-
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
34
|
-
throw new Error(`${label} must be an object`)
|
|
35
|
-
}
|
|
36
|
-
return value
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const runtimeSource = (payload: JsonValue): ZeropsRuntimeSource | undefined => {
|
|
40
|
-
const value = field(payload, 'source')
|
|
41
|
-
if (value === undefined) return undefined
|
|
42
|
-
const source = object(value, 'Zerops target source')
|
|
43
|
-
const repository = object(source['repository'], 'Zerops target source repository')
|
|
44
|
-
const allowedSourceKeys = ['runId', 'repository', 'commitSha', 'githubInstallationId']
|
|
45
|
-
const allowedRepositoryKeys = ['owner', 'name']
|
|
46
|
-
if (Object.keys(source).some((key) => !allowedSourceKeys.includes(key))) {
|
|
47
|
-
throw new Error('Zerops target source contains an unknown field')
|
|
48
|
-
}
|
|
49
|
-
if (Object.keys(repository).some((key) => !allowedRepositoryKeys.includes(key))) {
|
|
50
|
-
throw new Error('Zerops target source repository contains an unknown field')
|
|
51
|
-
}
|
|
52
|
-
const installation = source['githubInstallationId']
|
|
53
|
-
if (installation !== undefined && (typeof installation !== 'number' || !Number.isSafeInteger(installation) || installation <= 0)) {
|
|
54
|
-
throw new Error('Zerops target source githubInstallationId must be a positive safe integer')
|
|
55
|
-
}
|
|
56
|
-
const commitSha = requiredString(source, 'commitSha')
|
|
57
|
-
if (!IMMUTABLE_GIT_OBJECT.test(commitSha)) {
|
|
58
|
-
throw new Error('Zerops target source commitSha must be an exact lowercase Git object id')
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
runId: requiredString(source, 'runId'),
|
|
62
|
-
repository: {
|
|
63
|
-
owner: requiredString(repository, 'owner'),
|
|
64
|
-
name: requiredString(repository, 'name'),
|
|
65
|
-
},
|
|
66
|
-
commitSha,
|
|
67
|
-
...(installation === undefined ? {} : { githubInstallationId: installation }),
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export const zeropsTargetCodec: ProviderCodec<ZeropsRuntimeTarget> = {
|
|
72
|
-
version: 2,
|
|
73
|
-
encode: (target) => ({
|
|
74
|
-
projectId: target.projectId,
|
|
75
|
-
serviceId: target.serviceId,
|
|
76
|
-
accessToken: target.accessToken,
|
|
77
|
-
...(target.source === undefined
|
|
78
|
-
? {}
|
|
79
|
-
: {
|
|
80
|
-
source: {
|
|
81
|
-
runId: target.source.runId,
|
|
82
|
-
repository: { owner: target.source.repository.owner, name: target.source.repository.name },
|
|
83
|
-
commitSha: target.source.commitSha,
|
|
84
|
-
...(target.source.githubInstallationId === undefined ? {} : { githubInstallationId: target.source.githubInstallationId }),
|
|
85
|
-
},
|
|
86
|
-
}),
|
|
87
|
-
...(target.apiBaseUrl !== undefined ? { apiBaseUrl: target.apiBaseUrl } : {}),
|
|
88
|
-
...(target.propustkaUrl !== undefined ? { propustkaUrl: target.propustkaUrl } : {}),
|
|
89
|
-
...(target.adminKey !== undefined ? { adminKey: target.adminKey } : {}),
|
|
90
|
-
}),
|
|
91
|
-
decode: (payload) => {
|
|
92
|
-
const target = object(payload, 'Zerops target')
|
|
93
|
-
const allowedKeys = ['projectId', 'serviceId', 'accessToken', 'source', 'apiBaseUrl', 'propustkaUrl', 'adminKey']
|
|
94
|
-
if (Object.keys(target).some((key) => !allowedKeys.includes(key))) {
|
|
95
|
-
throw new Error('Zerops target contains an unknown field')
|
|
96
|
-
}
|
|
97
|
-
const source = runtimeSource(payload)
|
|
98
|
-
return {
|
|
99
|
-
projectId: requiredString(payload, 'projectId'),
|
|
100
|
-
serviceId: requiredString(payload, 'serviceId'),
|
|
101
|
-
accessToken: requiredString(payload, 'accessToken'),
|
|
102
|
-
...(source === undefined ? {} : { source }),
|
|
103
|
-
...(optionalString(payload, 'apiBaseUrl') !== undefined ? { apiBaseUrl: optionalString(payload, 'apiBaseUrl') } : {}),
|
|
104
|
-
...(optionalString(payload, 'propustkaUrl') !== undefined ? { propustkaUrl: optionalString(payload, 'propustkaUrl') } : {}),
|
|
105
|
-
...(optionalString(payload, 'adminKey') !== undefined ? { adminKey: optionalString(payload, 'adminKey') } : {}),
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
}
|
package/src/namespace-command.ts
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import type { JsonValue, ProviderDeploymentNamespace, ProviderNamespacePlan } from '@fabrika/provider-contract'
|
|
2
|
-
import type { ZeropsCliArgs } from './cli-args'
|
|
3
|
-
import { createZeropsNamespaceOperator, type ZeropsNamespacePostgres, zeropsNamespaceTargetCodec } from './namespace'
|
|
4
|
-
|
|
5
|
-
export interface ZeropsNamespaceCommandDependencies {
|
|
6
|
-
readonly source: Readonly<Record<string, string | undefined>>
|
|
7
|
-
readonly fetch: (input: string | URL | Request, init?: RequestInit) => Promise<Response>
|
|
8
|
-
readonly write: (value: string) => void
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const required = (value: string | undefined, label: string): string => {
|
|
12
|
-
if (value === undefined || value.trim() === '') {
|
|
13
|
-
throw new Error(`${label} is required`)
|
|
14
|
-
}
|
|
15
|
-
return value.trim()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const postgres = (args: ZeropsCliArgs): ZeropsNamespacePostgres | undefined => {
|
|
19
|
-
const type = args.postgresType
|
|
20
|
-
const profile = args.postgresProfile
|
|
21
|
-
if (type === undefined && profile === undefined) return undefined
|
|
22
|
-
if (type === undefined) {
|
|
23
|
-
throw new Error('--postgres-type is required with --postgres-profile')
|
|
24
|
-
}
|
|
25
|
-
if (type === 'postgresql:ha@18') {
|
|
26
|
-
if (
|
|
27
|
-
profile !== undefined
|
|
28
|
-
&& profile !== 'oltp-staging'
|
|
29
|
-
&& profile !== 'oltp-production'
|
|
30
|
-
&& profile !== 'oltp-enterprise'
|
|
31
|
-
&& profile !== 'olap-production'
|
|
32
|
-
&& profile !== 'writeheavy-production'
|
|
33
|
-
) {
|
|
34
|
-
throw new Error(`--postgres-profile ${profile} is not supported by ${type}`)
|
|
35
|
-
}
|
|
36
|
-
return profile === undefined ? { type } : { type, profile }
|
|
37
|
-
}
|
|
38
|
-
if (type === 'postgresql:single@18') {
|
|
39
|
-
if (
|
|
40
|
-
profile !== undefined
|
|
41
|
-
&& profile !== 'oltp-hobby'
|
|
42
|
-
&& profile !== 'oltp-staging'
|
|
43
|
-
&& profile !== 'oltp-production'
|
|
44
|
-
&& profile !== 'olap-production'
|
|
45
|
-
&& profile !== 'writeheavy-production'
|
|
46
|
-
) {
|
|
47
|
-
throw new Error(`--postgres-profile ${profile} is not supported by ${type}`)
|
|
48
|
-
}
|
|
49
|
-
return profile === undefined ? { type } : { type, profile }
|
|
50
|
-
}
|
|
51
|
-
throw new Error('--postgres-type must be postgresql:ha@18 or postgresql:single@18')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const planOptions = (args: ZeropsCliArgs): { [key: string]: JsonValue } | undefined => {
|
|
55
|
-
const values: { [key: string]: JsonValue } = {}
|
|
56
|
-
if (args.projectName !== undefined) values['projectName'] = required(args.projectName, '--project-name')
|
|
57
|
-
if (args.corePackage !== undefined) values['corePackage'] = required(args.corePackage, '--core-package')
|
|
58
|
-
if (args.publicAccess !== undefined) values['publicAccess'] = required(args.publicAccess, '--public-access')
|
|
59
|
-
const database = postgres(args)
|
|
60
|
-
if (database !== undefined) {
|
|
61
|
-
values['postgres'] = database.profile === undefined ? { type: database.type } : { type: database.type, profile: database.profile }
|
|
62
|
-
}
|
|
63
|
-
return Object.keys(values).length === 0 ? undefined : values
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const namespacePlan = (
|
|
67
|
-
args: ZeropsCliArgs,
|
|
68
|
-
source: Readonly<Record<string, string | undefined>>,
|
|
69
|
-
): ProviderNamespacePlan => {
|
|
70
|
-
// `FABRIKA_ZEROPS_*` because Zerops reserves the bare `ZEROPS_` prefix and refuses to store a custom
|
|
71
|
-
// variable using it (`userDataZeropsPrefixForbidden`).
|
|
72
|
-
const proxyBuildFromGit = required(
|
|
73
|
-
args.proxyBuildFromGit ?? source['FABRIKA_ZEROPS_PROXY_BUILD_FROM_GIT'],
|
|
74
|
-
'--proxy-build-from-git or FABRIKA_ZEROPS_PROXY_BUILD_FROM_GIT',
|
|
75
|
-
)
|
|
76
|
-
const operator = createZeropsNamespaceOperator({ proxyBuildFromGit })
|
|
77
|
-
const options = planOptions(args)
|
|
78
|
-
return operator.plan({
|
|
79
|
-
id: required(args.namespaceId, '--id'),
|
|
80
|
-
env: required(args.env, '--env'),
|
|
81
|
-
preset: required(args.preset, '--preset'),
|
|
82
|
-
...(args.exclusiveAppId === undefined ? {} : { exclusiveAppId: required(args.exclusiveAppId, '--exclusive-app') }),
|
|
83
|
-
...(options === undefined ? {} : { options }),
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const outputJson = (value: unknown): string => `${JSON.stringify(value, null, '\t')}\n`
|
|
88
|
-
|
|
89
|
-
const responseText = async (response: Response): Promise<string> => {
|
|
90
|
-
const text = await response.text()
|
|
91
|
-
if (response.ok) return text.trim() === '' ? 'null' : text
|
|
92
|
-
let message = `Control API request failed (${response.status})`
|
|
93
|
-
try {
|
|
94
|
-
const body: unknown = JSON.parse(text)
|
|
95
|
-
if (typeof body === 'object' && body !== null) {
|
|
96
|
-
const error = Reflect.get(body, 'error')
|
|
97
|
-
if (typeof error === 'string' && error !== '') message = error
|
|
98
|
-
}
|
|
99
|
-
} catch {
|
|
100
|
-
if (text.trim() !== '' && text.length < 500) message = text
|
|
101
|
-
}
|
|
102
|
-
throw new Error(message)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const controlCoordinates = (
|
|
106
|
-
args: ZeropsCliArgs,
|
|
107
|
-
source: Readonly<Record<string, string | undefined>>,
|
|
108
|
-
): { baseUrl: URL; token: string } => {
|
|
109
|
-
const value = required(args.controlUrl ?? source['FABRIKA_CONTROL_URL'], '--control-url or FABRIKA_CONTROL_URL')
|
|
110
|
-
const token = required(source['FABRIKA_CONTROL_TOKEN'], 'FABRIKA_CONTROL_TOKEN')
|
|
111
|
-
let baseUrl: URL
|
|
112
|
-
try {
|
|
113
|
-
baseUrl = new URL(value)
|
|
114
|
-
} catch {
|
|
115
|
-
throw new Error('--control-url or FABRIKA_CONTROL_URL must be an absolute URL')
|
|
116
|
-
}
|
|
117
|
-
if (baseUrl.protocol !== 'https:' && baseUrl.protocol !== 'http:') {
|
|
118
|
-
throw new Error('--control-url or FABRIKA_CONTROL_URL must use http or https')
|
|
119
|
-
}
|
|
120
|
-
return { baseUrl, token }
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const callControl = async (
|
|
124
|
-
deps: ZeropsNamespaceCommandDependencies,
|
|
125
|
-
coordinates: { baseUrl: URL; token: string },
|
|
126
|
-
path: string,
|
|
127
|
-
body?: unknown,
|
|
128
|
-
): Promise<void> => {
|
|
129
|
-
const response = await deps.fetch(new URL(path, coordinates.baseUrl), {
|
|
130
|
-
method: 'POST',
|
|
131
|
-
headers: {
|
|
132
|
-
accept: 'application/json',
|
|
133
|
-
authorization: `Bearer ${coordinates.token}`,
|
|
134
|
-
...(body === undefined ? {} : { 'content-type': 'application/json' }),
|
|
135
|
-
},
|
|
136
|
-
...(body === undefined ? {} : { body: JSON.stringify(body) }),
|
|
137
|
-
})
|
|
138
|
-
const text = await responseText(response)
|
|
139
|
-
let parsed: unknown
|
|
140
|
-
try {
|
|
141
|
-
parsed = JSON.parse(text)
|
|
142
|
-
} catch {
|
|
143
|
-
parsed = text
|
|
144
|
-
}
|
|
145
|
-
deps.write(outputJson(parsed))
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const createBody = (namespace: ProviderDeploymentNamespace): object => ({
|
|
149
|
-
id: namespace.id,
|
|
150
|
-
env: namespace.env,
|
|
151
|
-
...(namespace.exclusiveAppId === undefined ? {} : { exclusiveAppId: namespace.exclusiveAppId }),
|
|
152
|
-
target: namespace.target,
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
const adoptBody = (namespace: ProviderDeploymentNamespace): object => ({
|
|
156
|
-
env: namespace.env,
|
|
157
|
-
...(namespace.exclusiveAppId === undefined ? {} : { exclusiveAppId: namespace.exclusiveAppId }),
|
|
158
|
-
target: namespace.target,
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
/** Execute one namespace command. All command inputs are validated before the first fetch. */
|
|
162
|
-
export const runZeropsNamespaceCommand = async (
|
|
163
|
-
args: ZeropsCliArgs,
|
|
164
|
-
deps: ZeropsNamespaceCommandDependencies,
|
|
165
|
-
): Promise<void> => {
|
|
166
|
-
const subcommand = required(args.subcommand, 'namespace command')
|
|
167
|
-
if (subcommand === 'plan') {
|
|
168
|
-
deps.write(outputJson(namespacePlan(args, deps.source)))
|
|
169
|
-
return
|
|
170
|
-
}
|
|
171
|
-
if (subcommand === 'reconcile') {
|
|
172
|
-
const id = required(args.namespaceId, '--id')
|
|
173
|
-
const control = controlCoordinates(args, deps.source)
|
|
174
|
-
await callControl(deps, control, `/api/namespaces/${encodeURIComponent(id)}/reconcile`)
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
if (subcommand !== 'create' && subcommand !== 'adopt') {
|
|
178
|
-
throw new Error(`Unknown namespace command: ${subcommand}`)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const planned = namespacePlan(args, deps.source)
|
|
182
|
-
const control = controlCoordinates(args, deps.source)
|
|
183
|
-
if (subcommand === 'create') {
|
|
184
|
-
await callControl(deps, control, '/api/namespaces', createBody(planned.namespace))
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const projectId = required(args.projectId, '--project-id')
|
|
189
|
-
const decoded = zeropsNamespaceTargetCodec.decode(planned.namespace.target.payload)
|
|
190
|
-
const namespace: ProviderDeploymentNamespace = {
|
|
191
|
-
...planned.namespace,
|
|
192
|
-
target: {
|
|
193
|
-
provider: 'zerops',
|
|
194
|
-
version: zeropsNamespaceTargetCodec.version,
|
|
195
|
-
payload: zeropsNamespaceTargetCodec.encode({
|
|
196
|
-
...decoded,
|
|
197
|
-
managed: false,
|
|
198
|
-
projectId,
|
|
199
|
-
ready: false,
|
|
200
|
-
}),
|
|
201
|
-
},
|
|
202
|
-
}
|
|
203
|
-
await callControl(
|
|
204
|
-
deps,
|
|
205
|
-
control,
|
|
206
|
-
`/api/namespaces/${encodeURIComponent(namespace.id)}/adopt`,
|
|
207
|
-
adoptBody(namespace),
|
|
208
|
-
)
|
|
209
|
-
}
|