@fabrika/provider-zerops 0.0.26 → 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.
Files changed (83) hide show
  1. package/package.json +18 -5
  2. package/src/api/client.ts +522 -0
  3. package/src/api/errors.ts +50 -0
  4. package/src/api/polling.ts +59 -0
  5. package/src/api/readers.ts +185 -0
  6. package/src/api/service-env-response.ts +34 -0
  7. package/src/api/types.ts +602 -0
  8. package/src/api.ts +29 -1378
  9. package/src/authoring.ts +7 -10
  10. package/src/cli-args.ts +0 -5
  11. package/src/cli.ts +3 -28
  12. package/src/collaborators.ts +2 -4
  13. package/src/compile.ts +75 -20
  14. package/src/control.ts +217 -447
  15. package/src/descriptor.ts +135 -0
  16. package/src/index.ts +24 -128
  17. package/src/installation/admin-options.ts +128 -0
  18. package/src/installation/admin.ts +123 -0
  19. package/src/installation/deploy-options.ts +155 -0
  20. package/src/installation/deploy.ts +668 -0
  21. package/src/installation/generated/platform-console-schema.ts +41 -0
  22. package/src/installation/generated/platform-proxy-manifest.ts +72 -0
  23. package/src/installation/hosts.ts +117 -0
  24. package/src/installation/index.ts +366 -0
  25. package/src/installation/init.ts +521 -0
  26. package/src/installation/install-collaborators.ts +28 -0
  27. package/src/installation/install-environment.ts +193 -0
  28. package/src/installation/install-options.ts +193 -0
  29. package/src/installation/install-project.ts +201 -0
  30. package/src/installation/install-provisioning.ts +185 -0
  31. package/src/installation/install.ts +286 -0
  32. package/src/installation/installation-source.ts +42 -0
  33. package/src/installation/log.ts +77 -0
  34. package/src/installation/machine-key.ts +65 -0
  35. package/src/installation/manifest.ts +95 -0
  36. package/src/installation/placement-options.ts +33 -0
  37. package/src/installation/platform-source.ts +106 -0
  38. package/src/installation/platform-upload.ts +34 -0
  39. package/src/installation/proxy-manifest.ts +113 -0
  40. package/src/installation/secrets.ts +79 -0
  41. package/src/installation/sidecar.ts +122 -0
  42. package/src/installation/source-options.ts +12 -0
  43. package/src/installation/templates/README.md +116 -0
  44. package/src/installation/templates/fabrika.ref +1 -0
  45. package/src/installation/templates/gitignore +3 -0
  46. package/src/installation/templates/platform.yml +144 -0
  47. package/src/installation/topology/artifacts.ts +141 -0
  48. package/src/installation/topology/index.ts +13 -0
  49. package/src/installation/topology/installation-schemas.ts +225 -0
  50. package/src/installation/topology/invariants.ts +86 -0
  51. package/src/installation/topology/setups.ts +442 -0
  52. package/src/installation/topology/topology.ts +501 -0
  53. package/src/installation/topology/validate.ts +26 -0
  54. package/src/installation/upgrade-options.ts +108 -0
  55. package/src/installation/upgrade-output.ts +31 -0
  56. package/src/installation/upgrade.ts +373 -0
  57. package/src/managed-env.ts +105 -0
  58. package/src/manifest.ts +208 -315
  59. package/src/namespace/claims.ts +77 -0
  60. package/src/namespace/codec.ts +179 -0
  61. package/src/namespace/constants.ts +30 -0
  62. package/src/namespace/errors.ts +60 -0
  63. package/src/namespace/manifest.ts +28 -0
  64. package/src/namespace/operator.ts +151 -0
  65. package/src/namespace/provisioning.ts +482 -0
  66. package/src/namespace/proxy-attempt.ts +220 -0
  67. package/src/namespace/proxy-source.ts +22 -0
  68. package/src/namespace/topology.ts +115 -0
  69. package/src/namespace/types.ts +114 -0
  70. package/src/namespace.ts +34 -1260
  71. package/src/plan.ts +21 -23
  72. package/src/provider.ts +399 -254
  73. package/src/service-references.ts +28 -0
  74. package/src/source/constants.ts +11 -0
  75. package/src/source/port.ts +49 -0
  76. package/src/source/types.ts +4 -0
  77. package/src/source/validation.ts +72 -0
  78. package/src/source.ts +2 -1220
  79. package/src/types.ts +8 -7
  80. package/src/version-attempt.ts +18 -0
  81. package/src/codec.ts +0 -108
  82. package/src/namespace-command.ts +0 -209
  83. package/src/source-connection.ts +0 -344
@@ -0,0 +1,28 @@
1
+ /**
2
+ * `${<host>_<KEY>}` — Zerops resolves it across services regardless of `envIsolation`, so the host is the boundary.
3
+ * `${RUNTIME_<host>_<KEY>}`, the build-time bridge, counts as a reference to that host until measured otherwise.
4
+ */
5
+ const SERVICE_REFERENCE = /\$\{(?:RUNTIME_)?([a-z0-9]{1,25})_[A-Za-z0-9_]+\}/g
6
+
7
+ /** Namespace services every app in it may reference; the proxy is deliberately not one of them. */
8
+ const SHARED_NAMESPACE_HOSTNAMES: readonly string[] = ['postgres']
9
+
10
+ /** Hosts named by cross-service references in `text`, deduplicated, in order of first appearance. */
11
+ export function serviceReferenceHosts(text: string): string[] {
12
+ const hosts: string[] = []
13
+ for (const match of text.matchAll(SERVICE_REFERENCE)) {
14
+ const host = match[1]
15
+ if (host !== undefined && !hosts.includes(host)) hosts.push(host)
16
+ }
17
+ return hosts
18
+ }
19
+
20
+ /** The hosts a service of this app may reference: its own declared hostnames plus the namespace's shared services. */
21
+ export function allowedReferenceHosts(ownHostnames: readonly string[]): ReadonlySet<string> {
22
+ return new Set([...ownHostnames, ...SHARED_NAMESPACE_HOSTNAMES])
23
+ }
24
+
25
+ /** The first referenced host outside `allowed`, or null when every reference stays inside the app. */
26
+ export function foreignReferenceHost(text: string, allowed: ReadonlySet<string>): string | null {
27
+ return serviceReferenceHosts(text).find((host) => !allowed.has(host)) ?? null
28
+ }
@@ -0,0 +1,11 @@
1
+ export const MAX_ID_LENGTH = 128
2
+
3
+ export const SHA256_PATTERN = /^[a-f0-9]{64}$/
4
+
5
+ export const COMMIT_SHA_PATTERN = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/
6
+
7
+ export const ID_PATTERN = /^[A-Za-z0-9._:-]+$/
8
+
9
+ export const GITHUB_OWNER_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,37}[a-z0-9])?$/
10
+
11
+ export const GITHUB_REPOSITORY_PATTERN = /^[a-z0-9._-]{1,100}$/
@@ -0,0 +1,49 @@
1
+ import type { ZeropsSourceRepository } from './types'
2
+
3
+ /** A private source names its connection; an installation id alone never selects a credential (ADR-0029). */
4
+ export interface ZeropsSourcePrivateBinding {
5
+ readonly connectionId: string
6
+ readonly installationId: number
7
+ }
8
+
9
+ export interface ZeropsSourceResolveInput {
10
+ readonly repository: ZeropsSourceRepository
11
+ readonly requestedRef: string
12
+ readonly expectedCommitSha?: string
13
+ readonly privateBinding?: ZeropsSourcePrivateBinding
14
+ readonly descriptorSha256: string
15
+ readonly signal: AbortSignal
16
+ }
17
+
18
+ export interface ZeropsSourceResolution {
19
+ readonly commitSha: string
20
+ readonly descriptorSha256: string
21
+ }
22
+
23
+ /** ADR-0045: platform archives are anonymous, tree-prechecked, keep relative symlinks. */
24
+ export type ZeropsSourceArchive =
25
+ | { readonly kind: 'application'; readonly privateBinding?: ZeropsSourcePrivateBinding }
26
+ | { readonly kind: 'platform' }
27
+
28
+ export interface ZeropsSourceUploadInput {
29
+ readonly repository: ZeropsSourceRepository
30
+ readonly commitSha: string
31
+ readonly descriptorSha256: string
32
+ readonly archive: ZeropsSourceArchive
33
+ /** A credential in transit: never logged, persisted, or returned in an error. */
34
+ readonly uploadUrl: string
35
+ readonly signal: AbortSignal
36
+ }
37
+
38
+ export interface ZeropsSourceUploadResult {
39
+ readonly commitSha: string
40
+ readonly descriptorSha256: string
41
+ readonly entryCount: number
42
+ readonly expandedBytes: number
43
+ }
44
+
45
+ /** The GitHub source the Zerops composition injects; Control implements it in process. Callers verify what it returns. */
46
+ export interface ZeropsSourcePort {
47
+ resolve(input: ZeropsSourceResolveInput): Promise<ZeropsSourceResolution>
48
+ upload(input: ZeropsSourceUploadInput): Promise<ZeropsSourceUploadResult>
49
+ }
@@ -0,0 +1,4 @@
1
+ export interface ZeropsSourceRepository {
2
+ owner: string
3
+ name: string
4
+ }
@@ -0,0 +1,72 @@
1
+ import { z } from 'zod'
2
+ import { COMMIT_SHA_PATTERN, GITHUB_OWNER_PATTERN, GITHUB_REPOSITORY_PATTERN, ID_PATTERN, MAX_ID_LENGTH, SHA256_PATTERN } from './constants'
3
+ import type { ZeropsSourceRepository } from './types'
4
+
5
+ // Default Zod diagnostics can include rejected values and unknown keys, both of which may be secrets.
6
+ export function parseSourceWire<T>(schema: z.ZodType<T, z.ZodTypeDef, unknown>, value: unknown, label: string): T {
7
+ const result = schema.safeParse(value)
8
+ if (result.success) return result.data
9
+ if (result.error.issues.some((issue) => issue.code === 'unrecognized_keys')) throw new Error(`${label} contains an unknown field`)
10
+ const domainIssue = result.error.issues.find((issue) => issue.code === 'custom')
11
+ throw new Error(`${label}: ${domainIssue?.message ?? 'invalid wire value'}`)
12
+ }
13
+
14
+ export const identifierSchema = z.string().min(1).max(MAX_ID_LENGTH).regex(ID_PATTERN)
15
+ export const commitShaSchema = z.string().regex(COMMIT_SHA_PATTERN)
16
+ export const sha256Schema = z.string().regex(SHA256_PATTERN)
17
+ export const repositorySchema = z.object({
18
+ owner: z.string().min(1).max(39).regex(GITHUB_OWNER_PATTERN),
19
+ name: z.string().min(1).max(100).regex(GITHUB_REPOSITORY_PATTERN).refine((name) => name !== '.' && name !== '..', 'invalid repository name'),
20
+ }).strict()
21
+
22
+ export const rejectExplicitUndefined = (value: object, context: z.RefinementCtx): void => {
23
+ if (Object.values(value).some((entry) => entry === undefined)) {
24
+ context.addIssue({ code: 'custom', message: 'optional fields must be omitted instead of undefined' })
25
+ }
26
+ }
27
+
28
+ const repository = (value: unknown, label: string): ZeropsSourceRepository => parseSourceWire(repositorySchema, value, label)
29
+
30
+ export const isZeropsUploadDestination = (value: string): boolean => {
31
+ if (!value.startsWith('https://proxy.app-prg1.zerops.io/api/rest/object-storage/upload?')) return false
32
+ let url: URL
33
+ try {
34
+ url = new URL(value)
35
+ } catch {
36
+ return false
37
+ }
38
+ return url.protocol === 'https:'
39
+ && url.hostname === 'proxy.app-prg1.zerops.io'
40
+ && url.pathname === '/api/rest/object-storage/upload'
41
+ && url.username === ''
42
+ && url.password === ''
43
+ && url.port === ''
44
+ && url.hash === ''
45
+ && url.search !== ''
46
+ }
47
+
48
+ export function normalizeZeropsSourceRepository(repoUrl: string): ZeropsSourceRepository {
49
+ if (/\s/u.test(repoUrl) || /\p{Cc}/u.test(repoUrl)) {
50
+ throw new Error('source repository URL must be a canonical GitHub repository URL')
51
+ }
52
+ const candidate = repoUrl.startsWith('github.com/') ? `https://${repoUrl}` : repoUrl
53
+ let parsed: URL
54
+ try {
55
+ parsed = new URL(candidate)
56
+ } catch {
57
+ throw new Error('source repository URL must be a canonical GitHub repository URL')
58
+ }
59
+ if (
60
+ parsed.protocol !== 'https:' || parsed.hostname !== 'github.com' || parsed.port !== '' || parsed.username !== '' || parsed.password !== ''
61
+ || parsed.search !== '' || parsed.hash !== ''
62
+ ) {
63
+ throw new Error('source repository URL must be an HTTPS GitHub URL without credentials, port, query, or fragment')
64
+ }
65
+ const segments = parsed.pathname.split('/')
66
+ if (segments.length !== 3 || segments[0] !== '') throw new Error('source repository URL must identify one GitHub repository')
67
+ const owner = segments[1]
68
+ const rawName = segments[2]
69
+ if (owner === undefined || rawName === undefined) throw new Error('source repository URL must identify one GitHub repository')
70
+ const name = rawName.endsWith('.git') ? rawName.slice(0, -4) : rawName
71
+ return repository({ owner: owner.toLowerCase(), name: name.toLowerCase() }, 'source repository')
72
+ }