@fabrika/provider-zerops 0.8.2 → 0.9.0-cloudflare.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.
Files changed (128) hide show
  1. package/package.json +16 -14
  2. package/src/api/client.ts +6 -0
  3. package/src/api/types.ts +12 -0
  4. package/src/cli.ts +11 -0
  5. package/src/collaborators.ts +0 -14
  6. package/src/control.ts +33 -57
  7. package/src/execution.ts +113 -102
  8. package/src/installation/admin.ts +1 -1
  9. package/src/installation/deploy-options.ts +1 -2
  10. package/src/installation/deploy.ts +41 -75
  11. package/src/installation/generated/platform-console-schema.ts +3 -0
  12. package/src/installation/generated/platform-proxy-manifest.ts +21 -1
  13. package/src/installation/guide.md +9 -6
  14. package/src/installation/hosts.ts +1 -7
  15. package/src/installation/index.ts +0 -13
  16. package/src/installation/init-options.ts +2 -1
  17. package/src/installation/install-environment.ts +42 -106
  18. package/src/installation/install-options.ts +3 -1
  19. package/src/installation/install-secrets.ts +24 -68
  20. package/src/installation/install.ts +8 -4
  21. package/src/installation/sidecar.ts +5 -26
  22. package/src/installation/topology/setups.ts +5 -0
  23. package/src/installation/upgrade-options.ts +2 -2
  24. package/src/managed-env.ts +1 -174
  25. package/src/manifest.ts +11 -14
  26. package/src/namespace/claims.ts +56 -1
  27. package/src/namespace/errors.ts +1 -1
  28. package/src/namespace/manifest.ts +6 -19
  29. package/src/namespace/provisioning.ts +15 -3
  30. package/src/namespace/proxy-attempt.ts +43 -2
  31. package/src/namespace/proxy-reads.ts +12 -22
  32. package/src/namespace-cli.ts +152 -0
  33. package/src/plan.ts +2 -7
  34. package/src/provider.ts +128 -126
  35. package/src/proxy-manifest-carrier.ts +18 -0
  36. package/src/types.ts +0 -2
  37. package/types/src/api/client.d.ts +5 -0
  38. package/types/src/api/errors.d.ts +24 -0
  39. package/types/src/api/polling.d.ts +41 -0
  40. package/types/src/api/readers.d.ts +1115 -0
  41. package/types/src/api/service-env-limit.d.ts +17 -0
  42. package/types/src/api/service-env-response.d.ts +23 -0
  43. package/types/src/api/types.d.ts +687 -0
  44. package/types/src/api.d.ts +6 -0
  45. package/types/src/authoring.d.ts +9 -0
  46. package/types/src/cli-args.d.ts +19 -0
  47. package/types/src/cli.d.ts +13 -0
  48. package/types/src/collaborators.d.ts +16 -0
  49. package/types/src/compile.d.ts +91 -0
  50. package/types/src/control.d.ts +40 -0
  51. package/types/src/database-budget.d.ts +38 -0
  52. package/types/src/descriptor.d.ts +28 -0
  53. package/types/src/execution.d.ts +125 -0
  54. package/types/src/exposure.d.ts +47 -0
  55. package/types/src/index.d.ts +31 -0
  56. package/types/src/installation/admin-options.d.ts +24 -0
  57. package/types/src/installation/admin.d.ts +35 -0
  58. package/types/src/installation/checker-release.d.ts +12 -0
  59. package/types/src/installation/deploy-options.d.ts +37 -0
  60. package/types/src/installation/deploy.d.ts +136 -0
  61. package/types/src/installation/generated/platform-console-schema.d.ts +2 -0
  62. package/types/src/installation/generated/platform-proxy-manifest.d.ts +2 -0
  63. package/types/src/installation/hosts.d.ts +34 -0
  64. package/types/src/installation/index.d.ts +7 -0
  65. package/types/src/installation/init-options.d.ts +38 -0
  66. package/types/src/installation/init.d.ts +60 -0
  67. package/types/src/installation/install-collaborators.d.ts +24 -0
  68. package/types/src/installation/install-environment.d.ts +63 -0
  69. package/types/src/installation/install-options.d.ts +49 -0
  70. package/types/src/installation/install-project.d.ts +13 -0
  71. package/types/src/installation/install-provisioning.d.ts +58 -0
  72. package/types/src/installation/install-secrets.d.ts +17 -0
  73. package/types/src/installation/install-token.d.ts +10 -0
  74. package/types/src/installation/install.d.ts +23 -0
  75. package/types/src/installation/installation-source.d.ts +8 -0
  76. package/types/src/installation/log.d.ts +44 -0
  77. package/types/src/installation/machine-key.d.ts +19 -0
  78. package/types/src/installation/placement-options.d.ts +11 -0
  79. package/types/src/installation/platform-archive.d.ts +7 -0
  80. package/types/src/installation/platform-source.d.ts +8 -0
  81. package/types/src/installation/platform-upload.d.ts +3 -0
  82. package/types/src/installation/sidecar.d.ts +49 -0
  83. package/types/src/installation/source-options.d.ts +1 -0
  84. package/types/src/installation/topology/artifacts.d.ts +8 -0
  85. package/types/src/installation/topology/index.d.ts +5 -0
  86. package/types/src/installation/topology/installation-schemas.d.ts +2242 -0
  87. package/types/src/installation/topology/invariants.d.ts +23 -0
  88. package/types/src/installation/topology/setups.d.ts +59 -0
  89. package/types/src/installation/topology/topology.d.ts +153 -0
  90. package/types/src/installation/topology/validate.d.ts +11 -0
  91. package/types/src/installation/upgrade-options.d.ts +26 -0
  92. package/types/src/installation/upgrade-output.d.ts +6 -0
  93. package/types/src/installation/upgrade.d.ts +88 -0
  94. package/types/src/managed-env.d.ts +24 -0
  95. package/types/src/manifest.d.ts +204 -0
  96. package/types/src/namespace/claims.d.ts +16 -0
  97. package/types/src/namespace/codec.d.ts +334 -0
  98. package/types/src/namespace/constants.d.ts +25 -0
  99. package/types/src/namespace/errors.d.ts +15 -0
  100. package/types/src/namespace/manifest.d.ts +4 -0
  101. package/types/src/namespace/operator.d.ts +12 -0
  102. package/types/src/namespace/provisioning.d.ts +4 -0
  103. package/types/src/namespace/proxy-attempt.d.ts +39 -0
  104. package/types/src/namespace/proxy-reads.d.ts +22 -0
  105. package/types/src/namespace/proxy-secrets.d.ts +8 -0
  106. package/types/src/namespace/proxy-source.d.ts +74 -0
  107. package/types/src/namespace/topology.d.ts +9 -0
  108. package/types/src/namespace/types.d.ts +101 -0
  109. package/types/src/namespace/update.d.ts +6 -0
  110. package/types/src/namespace/validation.d.ts +12 -0
  111. package/types/src/namespace-cli.d.ts +2 -0
  112. package/types/src/namespace.d.ts +9 -0
  113. package/types/src/plan.d.ts +11 -0
  114. package/types/src/provider.d.ts +63 -0
  115. package/types/src/proxy-manifest-carrier.d.ts +24 -0
  116. package/types/src/schema.generated.d.ts +376 -0
  117. package/types/src/service-names.d.ts +4 -0
  118. package/types/src/service-references.d.ts +13 -0
  119. package/types/src/source/constants.d.ts +6 -0
  120. package/types/src/source/port.d.ts +60 -0
  121. package/types/src/source/types.d.ts +4 -0
  122. package/types/src/source/validation.d.ts +19 -0
  123. package/types/src/source.d.ts +2 -0
  124. package/types/src/types.d.ts +119 -0
  125. package/types/src/version-attempt.d.ts +8 -0
  126. package/src/installation/mcp.ts +0 -102
  127. package/src/installation/proxy-manifest.ts +0 -214
  128. package/src/installation/secrets.ts +0 -78
@@ -0,0 +1,136 @@
1
+ import type { SchemaReconciler } from '@fabrika/provider-contract';
2
+ import { type Sleeper, type ZeropsApi, type ZeropsServiceEnv } from '../index';
3
+ import { type CheckerPublication } from './checker-release';
4
+ import type { PlatformDeployInput } from './deploy-options';
5
+ import { type PlatformSourcePreparer } from './installation-source';
6
+ import type { DeployLog } from './log';
7
+ import type { PreparedPlatformSource } from './platform-source';
8
+ import { type PlatformUploadFetch } from './platform-upload';
9
+ /**
10
+ * The four services this command touches, in the order it RESOLVES and WRITES them.
11
+ *
12
+ * It is no longer the order they are deployed in — that is `PLATFORM_CONCURRENT_DEPLOY` followed by
13
+ * `PLATFORM_SEQUENTIAL_DEPLOY`, and the two stages concatenate back to this list (pinned by
14
+ * `deploy-order.test.ts` in `@fabrika/platform-artifacts`). What this list still decides is which services must exist
15
+ * and which environment is written, both of which happen for ALL FOUR before any of them is deployed.
16
+ *
17
+ * Each name is a service hostname in the topology AND the `zerops.yaml` setup name the pipeline
18
+ * selects — the platform's own "setup name defaults to the hostname" rule.
19
+ * `deploy-order.test.ts` in `@fabrika/platform-artifacts` pins both against the declarations that own them.
20
+ */
21
+ export declare const PLATFORM_DEPLOY_ORDER: readonly ["iam", "operations", "proxy", "control"];
22
+ export type PlatformDeployService = (typeof PLATFORM_DEPLOY_ORDER)[number];
23
+ /**
24
+ * The two services built AT ONCE, because nothing orders them against each other.
25
+ *
26
+ * Neither calls a sibling at boot: IAM holds no sibling origin at all, and Operations only
27
+ * CONSTRUCTS its IAM client (the first request is the first call). Each readiness gate hits the
28
+ * service's own `/healthz`, and no deploy-written variable of one is read by another's BUILD — the
29
+ * only build-time read on the whole path is the proxy reading its own manifest. So the order among them was arbitrary, and paying for it sequentially cost about 3 min 45 s
30
+ * of the ~9 min 35 s a warm five-service roll took (two measured runs, 2026-08-21).
31
+ *
32
+ * What is NOT arbitrary stays: every environment write happens before any of these starts, the proxy
33
+ * is deployed after both, and control after the proxy (ADR-0022 — the enforcement point ahead of
34
+ * the service whose table just widened). `deploy-order.test.ts` in `@fabrika/platform-artifacts` and
35
+ * `__tests__/deploy.test.ts` fail if that sequence changes.
36
+ */
37
+ export declare const PLATFORM_CONCURRENT_DEPLOY: readonly ["iam", "operations"];
38
+ /** What is deployed after the concurrent stage, one at a time and in this order. */
39
+ export declare const PLATFORM_SEQUENTIAL_DEPLOY: readonly ["proxy", "control"];
40
+ /** The proxy's hostname. The only publicly routed service, and the one that carries the manifest. */
41
+ export declare const PLATFORM_PROXY_SERVICE = "proxy";
42
+ /** IAM's and control's database, on both tiers. This command deploys nothing to it; it sets its backup schedule. */
43
+ export declare const PLATFORM_DATABASE_SERVICE = "db";
44
+ /** Operations' own database. A light installation created before it existed keeps Operations in `db`. */
45
+ export declare const OPERATIONS_DATABASE_SERVICE = "operationsdb";
46
+ /**
47
+ * Hourly. Zerops has no point-in-time recovery: a single-node database loses everything since its last `pg_dump`, which
48
+ * by default is daily. UNVERIFIED: that `backupPeriod` takes this 5-field cron, as the GUI documentation describes.
49
+ */
50
+ export declare const PLATFORM_DATABASE_BACKUP_PERIOD = "0 * * * *";
51
+ /**
52
+ * What deploying ONE service needs. Narrower than the whole command's collaborators so the bring-up
53
+ * (`install.ts`), which deploys the proxy alone before any manifest exists, can reuse `deployPlatformService`
54
+ * without inventing an IAM reconciler it has no use for.
55
+ */
56
+ export interface PlatformServiceDeployCollaborators {
57
+ readonly uploadFetch: PlatformUploadFetch;
58
+ readonly api: ZeropsApi;
59
+ readonly sleep: Sleeper;
60
+ readonly log: DeployLog;
61
+ readonly signal: AbortSignal;
62
+ }
63
+ /** Everything `deployPlatform` reaches the outside world through. */
64
+ export interface PlatformDeployCollaborators extends PlatformServiceDeployCollaborators {
65
+ readonly prepareSource: PlatformSourcePreparer;
66
+ readonly checkerPublished: CheckerPublication;
67
+ readonly reconcileSchema: SchemaReconciler;
68
+ }
69
+ /** The prepared snapshot shared by every build in an installation run. */
70
+ export interface PlatformServiceDeployInput {
71
+ readonly source: PreparedPlatformSource;
72
+ readonly dryRun: boolean;
73
+ /** The proxy's manifest, which its archive carries as the one data file (ADR-0045); the proxy is refused without it. */
74
+ readonly proxyManifest?: string;
75
+ }
76
+ /** One resolved platform service. */
77
+ export interface ResolvedService {
78
+ readonly hostname: PlatformDeployService;
79
+ readonly id: string;
80
+ }
81
+ export declare const serviceOf: (services: ReadonlyMap<PlatformDeployService, ResolvedService>, hostname: PlatformDeployService) => ResolvedService;
82
+ /** One service's environment by key. A sensitive record carries no value. Values are never logged. */
83
+ export type LiveServiceEnv = ReadonlyMap<string, ZeropsServiceEnv>;
84
+ /** Read one service's environment by key. */
85
+ export declare const readServiceEnv: (serviceId: string, { api, signal }: Pick<PlatformServiceDeployCollaborators, "api" | "signal">) => Promise<LiveServiceEnv>;
86
+ /**
87
+ * Deploy ONE service and wait for it to become the active version.
88
+ *
89
+ * A failed deploy throws, which stops the sequence: the platform keeps the previous version serving
90
+ * (`deploy.readinessCheck` is a real gate, live-verified), so a failure here leaves the installation
91
+ * consistent — old code behind the manifest that was written for it.
92
+ *
93
+ * Exported for the BRING-UP, which builds the proxy on its own before any manifest exists so that the
94
+ * service publishes the HTTP ports its public hostnames are named after (`install.ts`, pass 1). That is
95
+ * one service, not an order — the order below stays this file's.
96
+ */
97
+ export declare const deployPlatformService: (service: ResolvedService, input: PlatformServiceDeployInput, collaborators: PlatformServiceDeployCollaborators) => Promise<void>;
98
+ /** What `ensureBackupPeriod` found and did. */
99
+ export type BackupPeriodOutcome = {
100
+ readonly kind: 'unchanged';
101
+ } | {
102
+ readonly kind: 'kept';
103
+ readonly current: string;
104
+ } | {
105
+ readonly kind: 'would-change';
106
+ readonly from: string;
107
+ } | {
108
+ readonly kind: 'changed';
109
+ readonly from: string;
110
+ } | {
111
+ readonly kind: 'unconfirmed';
112
+ readonly readBack: string;
113
+ };
114
+ /**
115
+ * Set a managed service's backup period, read-compare-write, replacing only a daily one.
116
+ *
117
+ * A different period is sent with the retention the service reads — its own, else the default — WHOLE, because a
118
+ * PUT on this API resets what it leaves out. The decision is the read-back, never the PUT returning.
119
+ */
120
+ export declare const ensureBackupPeriod: (input: {
121
+ readonly api: Pick<ZeropsApi, "getBackupConfig" | "configureBackup" | "getProcess">;
122
+ readonly sleep: Sleeper;
123
+ readonly signal: AbortSignal;
124
+ readonly serviceId: string;
125
+ readonly hostname: string;
126
+ readonly period: string;
127
+ readonly dryRun: boolean;
128
+ }) => Promise<BackupPeriodOutcome>;
129
+ /**
130
+ * Bring one Zerops platform installation to this checkout, unattended.
131
+ *
132
+ * Every step is idempotent and the whole sequence fails closed: nothing is deployed until the manifest
133
+ * and the environment name have been applied, and nothing after a failed step runs.
134
+ */
135
+ export declare const deployPlatform: (input: PlatformDeployInput, collaborators: PlatformDeployCollaborators) => Promise<void>;
136
+ export declare const deployPreparedPlatform: (input: PlatformDeployInput, collaborators: PlatformDeployCollaborators, source: PreparedPlatformSource) => Promise<void>;
@@ -0,0 +1,2 @@
1
+ import type { AppSchema } from '@fabrika/auth-core';
2
+ export declare const PLATFORM_CONSOLE_APP_SCHEMA: AppSchema;
@@ -0,0 +1,2 @@
1
+ import type { PlatformProxyManifestTemplate } from '@fabrika/installation-init';
2
+ export declare const PLATFORM_PROXY_MANIFEST_TEMPLATE: PlatformProxyManifestTemplate;
@@ -0,0 +1,34 @@
1
+ import type { PlatformHosts, PlatformProxyService } from '@fabrika/installation-init';
2
+ /** Everything the deploy needs to know about where this installation answers. */
3
+ export interface PlatformPlacement {
4
+ readonly hosts: PlatformHosts;
5
+ /** The scheme the BROWSER speaks. Configuration, never a header — see `ProxyApp.scheme`. */
6
+ readonly scheme: 'http' | 'https';
7
+ /**
8
+ * Whether the proxy's public entry point is Zerops' generated subdomain. True only on the derived
9
+ * path: a custom-domain installation must not additionally publish a `.zerops.app` address.
10
+ */
11
+ readonly zeropsSubdomain: boolean;
12
+ }
13
+ /** The Zerops variable naming one URL per published HTTP port. READ_ONLY, written by the platform. */
14
+ export declare const ZEROPS_SUBDOMAIN_VARIABLE = "zeropsSubdomain";
15
+ /**
16
+ * Map the proxy's generated subdomains by the listener port each one fronts.
17
+ *
18
+ * The host form is `<hostname>-<hash>-<port>.<region>.zerops.app`, one line per HTTP port. Read as
19
+ * URLs rather than by splitting on `-`, so a hostname that itself contains a digit-suffixed segment
20
+ * cannot be misread: the port is the trailing `-<digits>` of the FIRST label only.
21
+ */
22
+ export declare const parseZeropsSubdomains: (value: string) => Map<number, string>;
23
+ /** One platform app's listener, as the committed template assigns it. */
24
+ export interface PlatformListener {
25
+ readonly service: PlatformProxyService;
26
+ readonly port: number;
27
+ }
28
+ /**
29
+ * Bind every platform service to the generated subdomain of its listener.
30
+ *
31
+ * Throws naming every port it could not find, because the alternative — writing a manifest with a
32
+ * guessed or missing host — is a proxy that fronts nothing at an address the console then bounces to.
33
+ */
34
+ export declare const derivePlatformHosts: (subdomains: string, listeners: readonly PlatformListener[]) => PlatformHosts;
@@ -0,0 +1,7 @@
1
+ import type { InstallationCli } from '@fabrika/provider-contract/installation';
2
+ export { PLATFORM_CONCURRENT_DEPLOY, PLATFORM_DEPLOY_ORDER, PLATFORM_PROXY_SERVICE, PLATFORM_SEQUENTIAL_DEPLOY } from './deploy';
3
+ export { PLATFORM_CONSOLE_APP_SCHEMA } from './generated/platform-console-schema';
4
+ export { PLATFORM_PROXY_MANIFEST_TEMPLATE } from './generated/platform-proxy-manifest';
5
+ /** The operator's guide of this release, shipped beside this module. */
6
+ export declare const readInstallationGuide: () => Promise<string>;
7
+ export declare const installationCli: InstallationCli;
@@ -0,0 +1,38 @@
1
+ import { type CommandEnv } from '@fabrika/installation-init';
2
+ /** Every input `runInit` takes from the operator. */
3
+ export interface InitInput {
4
+ /** Names the GitHub Environment, the default repository and the local checkout directory. */
5
+ readonly installation: string;
6
+ readonly repo: string;
7
+ /** The sidecar's local checkout: `--checkout`, or `fabrika-zerops-<installation>` in the working directory. */
8
+ readonly checkoutDir: string;
9
+ /** The published fabrika-platform tag the sidecar pins in `fabrika.ref`. */
10
+ readonly fabrikaRef: string;
11
+ readonly projectId: string;
12
+ /** The name this installation calls itself — written to every service as `ENVIRONMENT`. */
13
+ readonly environmentName: string;
14
+ /** All three or none: none derives them from the proxy's Zerops subdomains. */
15
+ readonly hosts?: {
16
+ readonly iam: string;
17
+ readonly control: string;
18
+ readonly operations: string;
19
+ };
20
+ /** Region API base, when the installation is not on the default one. */
21
+ readonly apiBaseUrl?: string;
22
+ /** The Zerops INTEGRATION token `platform install` minted. Environment only. */
23
+ readonly accessToken: string;
24
+ /** The `px_` key this installation's IAM was seeded with. Environment only. */
25
+ readonly provisioningKey: string;
26
+ /** `--yes`: answer every confirmation yes. */
27
+ readonly unattended: boolean;
28
+ }
29
+ /**
30
+ * The installation's environment name, refused when it claims to be local.
31
+ *
32
+ * The same refusal the services enforce at boot: `local` is the value `localDevLogin`, the ephemeral
33
+ * signing key and the credential-less caller path are all gated on, and a deployed installation is
34
+ * never a loopback address.
35
+ */
36
+ export declare const checkedEnvironmentName: (declared: string) => string;
37
+ /** Parse the command's arguments and environment into the one input `runInit` takes. */
38
+ export declare const parseInitArgs: (argv: readonly string[], env: CommandEnv, cwd?: string) => InitInput;
@@ -0,0 +1,60 @@
1
+ import { type Confirmations, type EnvironmentConfig, type SidecarScaffoldInput, type SidecarScaffoldResult } from '@fabrika/installation-init';
2
+ import { type ZeropsApi } from '../index';
3
+ import type { InitInput } from './init-options';
4
+ import type { InitLog } from './log';
5
+ /** Everything `runInit` does outside the operator's own disk. Every one of them is confirmed first. */
6
+ export interface InitEffects {
7
+ /** Only decides how the scaffold confirmation is phrased; the scaffold itself re-reads it. */
8
+ repositoryExists(repo: string): Promise<boolean>;
9
+ scaffold(input: SidecarScaffoldInput): Promise<SidecarScaffoldResult>;
10
+ configureEnvironment(config: EnvironmentConfig): Promise<void>;
11
+ triggerWorkflow(repo: string): Promise<void>;
12
+ /** Read one Zerops project's name — the cheapest proof that the token and the project id agree. */
13
+ describeProject(input: {
14
+ projectId: string;
15
+ accessToken: string;
16
+ apiBaseUrl?: string;
17
+ }): Promise<string>;
18
+ inspectPlatform(input: InspectPlatformInput): Promise<PlatformInspection>;
19
+ }
20
+ export interface InitCollaborators {
21
+ readonly log: InitLog;
22
+ readonly prompts: Confirmations;
23
+ readonly effects: InitEffects;
24
+ }
25
+ /** Where this installation answers, as far as `init` needs to know it. */
26
+ interface Placement {
27
+ readonly hosts?: {
28
+ readonly iam: string;
29
+ readonly control: string;
30
+ readonly operations: string;
31
+ };
32
+ }
33
+ export interface InspectPlatformInput {
34
+ readonly projectId: string;
35
+ readonly accessToken: string;
36
+ readonly apiBaseUrl?: string;
37
+ }
38
+ /** What `init` reads off the live installation to print origins it can verify. Values are never logged. */
39
+ export interface PlatformInspection {
40
+ readonly controlEnv: ReadonlyMap<string, string>;
41
+ readonly proxyEnv: ReadonlyMap<string, string>;
42
+ readonly proxyPublished: boolean;
43
+ }
44
+ /** Read `control` and `proxy` without writing anything. */
45
+ export declare const inspectPlatform: (projectId: string, api: ZeropsApi, signal: AbortSignal) => Promise<PlatformInspection>;
46
+ /**
47
+ * IAM's PUBLIC origin as the installation itself records it, or nothing when init would have to guess.
48
+ *
49
+ * `platform install` writes it to `control` as `FABRIKA_IAM_ISSUER`, so this reads the live value
50
+ * rather than re-deriving one — and refuses it when the operator named a different IAM host, because
51
+ * a printed origin an operator then pastes into `FABRIKA_IAM_RPC_URL` must be the one that answers.
52
+ */
53
+ export declare const platformIamOrigin: (placement: Placement, platform: PlatformInspection) => string | undefined;
54
+ /** Return a verified live console URL, or no URL when init would have to guess. */
55
+ export declare const sourceConnectionSettingsUrl: (placement: Placement, platform: PlatformInspection) => string | undefined;
56
+ /** Run the whole thing for `<installation>`. */
57
+ export declare const runInit: (input: InitInput, collaborators: InitCollaborators) => Promise<void>;
58
+ /** The real collaborators: a TTY, `gh`, git, and one read of the Zerops API. */
59
+ export declare const consoleInitCollaborators: (input: InitInput) => InitCollaborators;
60
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { Confirmations } from '@fabrika/installation-init';
2
+ import type { SchemaReconciler } from '@fabrika/provider-contract';
3
+ import type { Sleeper, ZeropsApi } from '../index';
4
+ import type { CheckerPublication } from './checker-release';
5
+ import type { PlatformSourcePreparer } from './installation-source';
6
+ import type { InitLog } from './log';
7
+ import type { PlatformUploadFetch } from './platform-upload';
8
+ /** The one question this command asks. Injected so the flow can be exercised without a TTY. */
9
+ export type InstallPrompts = Confirmations;
10
+ /** Everything `runInstall` reaches the outside world through. */
11
+ export interface InstallCollaborators {
12
+ readonly prepareSource: PlatformSourcePreparer;
13
+ readonly checkerPublished: CheckerPublication;
14
+ readonly uploadFetch: PlatformUploadFetch;
15
+ readonly api: ZeropsApi;
16
+ readonly reconcileSchema: SchemaReconciler;
17
+ readonly sleep: Sleeper;
18
+ readonly log: InitLog;
19
+ readonly prompts: InstallPrompts;
20
+ readonly signal: AbortSignal;
21
+ /** Create the local secrets file (`--secrets-file`) with this text. Never logged. */
22
+ readonly storeSecrets: (text: string) => Promise<void>;
23
+ }
24
+ export declare const assertRunning: (signal: AbortSignal) => void;
@@ -0,0 +1,63 @@
1
+ import { type InstallationEmail, type InstallationSecrets, type PlatformHosts } from '@fabrika/installation-init';
2
+ import type { ZeropsNamespaceProxySource } from '../index';
3
+ import type { PlatformDeployService, ResolvedService } from './deploy';
4
+ import { type InstallCollaborators } from './install-collaborators';
5
+ import type { PlatformTier } from './topology/topology';
6
+ /** The private address the proxy dials IAM at inside the project, and pass 1's placeholder issuer. */
7
+ export declare const PRIVATE_IAM_UPSTREAM = "iam:3000";
8
+ /**
9
+ * The three variables pass 1 writes on the proxy, and nothing else.
10
+ *
11
+ * `FABRIKA_IAM_ISSUER` is the private address rather than the public issuer because the public one is not known
12
+ * yet; `deployPlatform` corrects it in pass 2, before the manifest it belongs to is applied. The pass-1 manifest is
13
+ * `PASS_ONE_PROXY_MANIFEST`, which the proxy's archive carries.
14
+ */
15
+ export declare const passOneProxyEnv: (secrets: InstallationSecrets) => ReadonlyMap<string, string>;
16
+ /** EMPTY on purpose: the only legal document before the hosts exist. The proxy comes up answering 404. */
17
+ export declare const PASS_ONE_PROXY_MANIFEST: string;
18
+ /** What `installationServiceEnv` needs. Everything in it is settled before the first write. */
19
+ export interface InstallationEnvInput {
20
+ readonly environment: string;
21
+ /** The installation's own Zerops project, which no deployment namespace may adopt. */
22
+ readonly projectId: string;
23
+ readonly tier: PlatformTier;
24
+ readonly scheme: 'http' | 'https';
25
+ readonly hosts: PlatformHosts;
26
+ readonly clientId: string;
27
+ readonly proxySource: ZeropsNamespaceProxySource;
28
+ readonly apiBaseUrl?: string;
29
+ readonly secrets: InstallationSecrets;
30
+ /** The Zerops integration token minted for the control plane. Never logged, never printed. */
31
+ readonly zeropsAccessToken: string;
32
+ /** IAM sends its own mail with it, and Control hands it to applications whose job declares `mailer: 'installation'`. */
33
+ readonly email: InstallationEmail;
34
+ }
35
+ /**
36
+ * EVERY variable this command places, per service: fabrika's (`installationServiceEnvironment`) over this
37
+ * project's own references, and control's Zerops variables after them.
38
+ *
39
+ * Pure, and exported, because the matrix is the thing most worth pinning: a name that is right on
40
+ * Cloudflare and wrong on Bun is a silent no-op rather than a failure. No key any service declares in its
41
+ * own `zerops.yaml` appears here — `PORT`, `FABRIKA_IAM_RPC_URL`, `FABRIKA_OPERATIONS_URL`,
42
+ * `FABRIKA_CONTROL_ASSETS_DIR`, `FABRIKA_CONTROL_URL`, `FABRIKA_PROXY_MANIFEST`, `FABRIKA_PROXY_PORT`. The env
43
+ * API refuses those (`provider-zerops/src/api.ts`), because the conflict cannot be resolved to a record id.
44
+ */
45
+ export declare const installationServiceEnv: (input: InstallationEnvInput) => ReadonlyMap<PlatformDeployService, ReadonlyMap<string, string>>;
46
+ /**
47
+ * The keys whose VALUE this command generates, per service: fabrika's, and the two Zerops names on control
48
+ * that carry the proxy key and the minted token.
49
+ *
50
+ * Their presence on a live service is what "this project already holds an installation" means, and it is
51
+ * checked by KEY only — a value is never read back for comparison. `__tests__/install.test.ts` pins this
52
+ * against the matrix above, so a new generated secret cannot be added without appearing here.
53
+ */
54
+ export declare const GENERATED_SECRET_KEYS: ReadonlyMap<PlatformDeployService, readonly string[]>;
55
+ /**
56
+ * Write a set of variables, reporting the KEYS — never a value, not even in a debug line.
57
+ *
58
+ * Write-first and unconditional: a generated secret cannot be read back to compare, and `PUT
59
+ * /user-data/{id}` replaces in place, so a repeat costs a call and nothing else. Exactly the `sensitive`
60
+ * keys are written sensitive (the generated secrets and the operator's mail credentials); everything else
61
+ * stays readable, because `platform deploy` compares and merges it later.
62
+ */
63
+ export declare const writeServiceEnv: (service: ResolvedService, desired: ReadonlyMap<string, string>, { api, log, signal }: InstallCollaborators, sensitive: ReadonlySet<string>) => Promise<void>;
@@ -0,0 +1,49 @@
1
+ import { type InstallationEmail } from '@fabrika/installation-init';
2
+ import type { PlatformTier } from './topology/topology';
3
+ /**
4
+ * Where the installation's project comes from.
5
+ *
6
+ * A UNION rather than an optional id beside a boolean, because the two mistakes worth making
7
+ * unrepresentable are "neither" and "both": the parser is the only place that can tell them apart, and
8
+ * downstream code must not have to ask a second time.
9
+ */
10
+ export type InstallProjectSource =
11
+ /** One the operator created, empty, by hand. */
12
+ {
13
+ readonly kind: 'existing';
14
+ readonly projectId: string;
15
+ }
16
+ /** One this command creates, from the same declaration the provisioning import is compiled from. */
17
+ | {
18
+ readonly kind: 'create';
19
+ readonly projectName: string;
20
+ };
21
+ /** Every input `runInstall` takes from the operator. */
22
+ export interface PlatformInstallInput {
23
+ /** The project this installation is brought up in — named, or created here. */
24
+ readonly project: InstallProjectSource;
25
+ /** The client the project belongs to — required, because the control plane's token is minted on it. */
26
+ readonly clientId: string;
27
+ /** Zerops personal access token. Environment only. */
28
+ readonly accessToken: string;
29
+ /** Region API base, when the installation is not on the default one. */
30
+ readonly apiBaseUrl?: string;
31
+ /** The name this installation calls itself — written to every platform service as `ENVIRONMENT`. */
32
+ readonly environment: string;
33
+ /** The scheme a browser speaks to this installation. */
34
+ readonly scheme: 'http' | 'https';
35
+ readonly sourceDir: string;
36
+ /** Where every credential this run creates is written, mode 0600, before the first is placed. */
37
+ readonly secretsFile: string;
38
+ readonly tier: PlatformTier;
39
+ /** The installation's mail transport, written on `iam` and `control`; `none` when the operator named no provider. */
40
+ readonly email: InstallationEmail;
41
+ /** `--yes`: answer every confirmation yes, for a bring-up with nobody at the keyboard. */
42
+ readonly unattended: boolean;
43
+ }
44
+ /** The canonical public release repository used for namespace proxy source identities. */
45
+ export declare const FABRIKA_REPOSITORY_URL = "https://github.com/contember/fabrika-platform";
46
+ /** `--create-project`: bring the project up too, instead of naming one the operator made. */
47
+ export declare const CREATE_PROJECT_FLAG = "--create-project";
48
+ /** Parse the command's arguments and environment into the one input `runInstall` takes. */
49
+ export declare const parsePlatformInstallArgs: (argv: readonly string[], env: Record<string, string | undefined>) => PlatformInstallInput;
@@ -0,0 +1,13 @@
1
+ import { type InstallCollaborators } from './install-collaborators';
2
+ import type { PlatformInstallInput } from './install-options';
3
+ /**
4
+ * Settle which project this run installs into — the operator's, or one created here.
5
+ *
6
+ * ONE confirmation either way, and both cover the token check and the read that follows: a created project is read back
7
+ * through the same `resolveProject` an operator-made one goes through, so the core package is checked on
8
+ * the project that will actually be installed into rather than on the document that asked for it.
9
+ */
10
+ export declare const resolveInstallationProject: (input: PlatformInstallInput, environment: string, collaborators: InstallCollaborators) => Promise<{
11
+ id: string;
12
+ name: string;
13
+ }>;
@@ -0,0 +1,58 @@
1
+ import { type ZeropsService, type ZeropsServiceStatus } from '../index';
2
+ import { type PlatformDeployService, type ResolvedService } from './deploy';
3
+ import { type InstallCollaborators } from './install-collaborators';
4
+ import { type CompiledDocument, type CompiledTopology, type PlatformTier } from './topology/topology';
5
+ /** The topology this command installs for a tier, so the project document and the services document cannot drift. */
6
+ export declare const installationTopology: (environment: string, tier: PlatformTier) => CompiledTopology;
7
+ /**
8
+ * The services-only provisioning document (WU2), compiled from the declaration the committed artifact
9
+ * is rendered from.
10
+ *
11
+ * Not read off disk: `gen:check` already proves
12
+ * `packages/platform-artifacts/generated/platform{,-light}.services.provision.zerops-import.yaml` is this exact text,
13
+ * and a value needs no filesystem in a published package.
14
+ */
15
+ export declare const provisioningDocument: (environment: string, tier: PlatformTier) => CompiledDocument;
16
+ /** One service of the provisioning document that the project already has. */
17
+ interface ExistingService {
18
+ readonly id: string;
19
+ readonly status?: ZeropsServiceStatus;
20
+ }
21
+ /**
22
+ * Every service of the provisioning document that the project already has, by hostname.
23
+ *
24
+ * The STATUS travels with the id because `NEW` is not a service this command may touch: measured live,
25
+ * a service holds NO environment at all — not even the platform's generated keys — until it leaves that
26
+ * state, so both a read and a write against one are meaningless rather than merely early.
27
+ */
28
+ export declare const existingServices: (declared: readonly string[], services: readonly ZeropsService[]) => Map<string, ExistingService>;
29
+ /**
30
+ * Refuse a service the platform is still creating.
31
+ *
32
+ * Not a wait: this command holds no process id for a service some earlier run imported, and a sleep
33
+ * would be a guess at a number the platform never promised. The whole light topology settles in about a
34
+ * minute, so "run it again shortly" is both true and cheap.
35
+ */
36
+ export declare const assertNoServiceIsBeingCreated: (existing: ReadonlyMap<string, ExistingService>) => void;
37
+ /**
38
+ * Refuse a project that already carries this installation's generated secrets.
39
+ *
40
+ * By KEY, never by value. Re-running a bring-up would roll a fresh vault KEK — whose loss is
41
+ * unrecoverable by design — and fresh signing keys, invalidating every live token, so the safe answer to
42
+ * "was this already installed?" is to stop and say so. `platform deploy` is the command for an
43
+ * installation that exists.
44
+ */
45
+ export declare const assertNotAlreadyInstalled: (existing: ReadonlyMap<string, ExistingService>, collaborators: InstallCollaborators) => Promise<void>;
46
+ /**
47
+ * Import the topology, unless the project already has it.
48
+ *
49
+ * Three outcomes, and the middle one is the one that costs something to get wrong: re-applying a
50
+ * `startWithoutCode: true` document at a service that carries code activates an EMPTY app version and
51
+ * demotes the running one to `BACKUP` (`docs/reference/zerops-platform.md`). A PARTIAL set is refused
52
+ * rather than completed, because an import applies as one document and cannot skip the services that
53
+ * are already there.
54
+ */
55
+ export declare const provision: (projectId: string, document: CompiledDocument, existing: ReadonlyMap<string, ExistingService>, collaborators: InstallCollaborators) => Promise<void>;
56
+ /** Resolve the four platform services by hostname, naming the whole set that is missing rather than the first. */
57
+ export declare const resolvePlatformServices: (projectId: string, { api, signal }: InstallCollaborators) => Promise<Map<PlatformDeployService, ResolvedService>>;
58
+ export { serviceOf } from './deploy';
@@ -0,0 +1,17 @@
1
+ import { type InstallationSecrets } from '@fabrika/installation-init';
2
+ /** What the file records beside the credentials, so it identifies its installation on its own. */
3
+ export interface InstallationSecretsRecord {
4
+ readonly environment: string;
5
+ readonly projectId: string;
6
+ readonly clientId: string;
7
+ readonly secrets: InstallationSecrets;
8
+ /** The integration token minted for the control plane. */
9
+ readonly zeropsAccessToken: string;
10
+ }
11
+ /**
12
+ * The file's text, named as the commands that read it name each value.
13
+ *
14
+ * `FABRIKA_ZEROPS_ACCESS_TOKEN` is the INTEGRATION token, which is what `platform init` and
15
+ * `platform deploy` take; the personal token the install ran with is not written.
16
+ */
17
+ export declare const renderInstallationSecretsFile: (record: InstallationSecretsRecord) => string;
@@ -0,0 +1,10 @@
1
+ import type { InstallCollaborators } from './install-collaborators';
2
+ /**
3
+ * Refuse an integration token before anything is created.
4
+ *
5
+ * The install mints an integration token at step 4, and an integration token is refused that mint. Without
6
+ * this read the mistake costs a billed project and six imported services first.
7
+ */
8
+ export declare const assertPersonalAccessToken: ({ api, signal }: InstallCollaborators) => Promise<void>;
9
+ /** Translate the mint's refusal of an integration token into the fix and the way back into this project. */
10
+ export declare const explainMintFailure: (failure: unknown, projectId: string) => unknown;
@@ -0,0 +1,23 @@
1
+ import type { SchemaReconciler } from '@fabrika/provider-contract';
2
+ import { type InstallCollaborators, type InstallPrompts } from './install-collaborators';
3
+ import type { PlatformInstallInput } from './install-options';
4
+ export type { InstallCollaborators, InstallPrompts } from './install-collaborators';
5
+ export { GENERATED_SECRET_KEYS, type InstallationEnvInput, installationServiceEnv } from './install-environment';
6
+ /**
7
+ * Bring up one Zerops platform installation, in a project the operator created empty or in one created
8
+ * here.
9
+ *
10
+ * Every step that leaves this machine is confirmed first, and declining any of them stops there with
11
+ * what to run instead. Nothing after the project step and before the import is a mutation, so a declined
12
+ * install leaves the project exactly as it was.
13
+ */
14
+ export declare const runInstall: (input: PlatformInstallInput, collaborators: InstallCollaborators) => Promise<void>;
15
+ /**
16
+ * The confirmations stand between a stray invocation and an installation: this command generates six
17
+ * credentials, mints a Zerops token on the account and deploys.
18
+ */
19
+ export declare const installPrompts: (input: PlatformInstallInput, stdin: {
20
+ readonly isTTY?: boolean;
21
+ }, announce: (line: string) => void) => InstallPrompts;
22
+ /** The real collaborators: a TTY for the confirmations, the Zerops API, and IAM's own schema reconciler. */
23
+ export declare const consoleInstallCollaborators: (input: PlatformInstallInput, reconcileSchema: SchemaReconciler) => InstallCollaborators;
@@ -0,0 +1,8 @@
1
+ import { type ZeropsNamespaceProxySource } from '../index';
2
+ import { type PreparedPlatformSource } from './platform-source';
3
+ export type PlatformSourcePreparer = (sourceDir: string, signal: AbortSignal) => Promise<PreparedPlatformSource>;
4
+ export declare const prepareInstallationSource: PlatformSourcePreparer;
5
+ export declare const validateInstallationSetups: (source: PreparedPlatformSource, setups: readonly string[]) => void;
6
+ export declare const FABRIKA_ZEROPS_PROXY_SOURCE_JSON = "FABRIKA_ZEROPS_PROXY_SOURCE_JSON";
7
+ export declare const serializeNamespaceProxySource: (source: ZeropsNamespaceProxySource) => string;
8
+ export declare const prepareNamespaceProxySource: (source: PreparedPlatformSource) => Promise<ZeropsNamespaceProxySource>;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Progress reporting for `fabrika platform deploy --provider=zerops` and for `platform init`.
3
+ *
4
+ * HARD RULE, the same one `@fabrika/installation-init`'s `log.ts` states: **nothing here ever
5
+ * prints a secret VALUE, and there is deliberately no helper that accepts one.** Callers may pass a
6
+ * variable NAME, a count, or a "✓ written" confirmation. The Zerops access token and the IAM
7
+ * provisioning key are the two credentials this command holds; neither has a formatting path.
8
+ *
9
+ * A caught error is never passed through here either — `ZeropsApiError` (`src/api/errors.ts`)
10
+ * already redacts the platform's message on the calls that carry a value, but a raw error from
11
+ * anywhere else may quote a URL with an embedded token. Log a short sentence, never an error object.
12
+ *
13
+ * Only INTERFACES and test doubles live here. The console bindings live with the flow that uses them,
14
+ * so nothing on the deploy path imports the interactive `platform init` machinery.
15
+ */
16
+ /** Where the command's progress goes. Injected so a test can read the transcript instead of stdout. */
17
+ export interface DeployLog {
18
+ /** A numbered stage of the sequence. */
19
+ step(title: string): void;
20
+ /** A detail line under the current stage. */
21
+ info(message: string): void;
22
+ /** Something the operator should notice but which does not stop the deploy. */
23
+ warn(message: string): void;
24
+ }
25
+ /** The real console log. Stateful only in its step counter. */
26
+ export declare const consoleDeployLog: () => DeployLog;
27
+ /** A log that records every line, for tests and for `--dry-run` assertions. */
28
+ export declare const recordingDeployLog: () => DeployLog & {
29
+ readonly lines: readonly string[];
30
+ };
31
+ /**
32
+ * What `platform init` reports. Two lines more than a deploy: a confirmation of something that
33
+ * happened, and the boxed hand-off an operator must not scroll past.
34
+ */
35
+ export interface InitLog extends DeployLog {
36
+ /** Something outward-facing succeeded. Names a key or a repository, never a value. */
37
+ ok(message: string): void;
38
+ /** A boxed OPERATOR ACTION — what to run when a confirmation was declined, or what is left to do. */
39
+ action(title: string, lines: readonly string[]): void;
40
+ }
41
+ /** A log that records every line, so a test can assert on the transcript — including what is NOT in it. */
42
+ export declare const recordingInitLog: () => InitLog & {
43
+ readonly lines: readonly string[];
44
+ };
@@ -0,0 +1,19 @@
1
+ /** What the calling verb knows about this installation. Both fields are omitted when it would guess. */
2
+ export interface MachineKeyNextStep {
3
+ /** IAM's PUBLIC origin — the address `FABRIKA_IAM_RPC_URL` takes. */
4
+ readonly iamOrigin?: string;
5
+ /** The sidecar GitHub Environment that also holds the provisioning key, when its name is known. */
6
+ readonly sidecarEnvironment?: string;
7
+ }
8
+ /** The boxed hand-off's title. Exported so a test names it once. */
9
+ export declare const MACHINE_KEY_NEXT_STEP_TITLE = "NEXT \u2014 mint a machine key for `fabrika control`";
10
+ /** The command the block leads to, with the three flags `key issue` requires. */
11
+ export declare const MACHINE_KEY_ISSUE_COMMAND = "fabrika control key issue --label=<name> --permissions=<a,b,c> --expires-in=<seconds>";
12
+ /**
13
+ * The lines of the block, in the order an operator uses them.
14
+ *
15
+ * The origin is the one VALUE printed, because it is not a credential: it is where the installation
16
+ * answers, and the rebuild that motivated this block failed precisely because an operator guessed it.
17
+ * The two keys are named and located; a value for either would come from the environment anyway.
18
+ */
19
+ export declare const machineKeyNextStepLines: (step?: MachineKeyNextStep) => readonly string[];