@fabrika/provider-zerops 0.9.0-dev.1 → 0.9.0-dev.2

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 (93) hide show
  1. package/package.json +15 -14
  2. package/src/execution.ts +45 -8
  3. package/types/src/api/client.d.ts +5 -0
  4. package/types/src/api/errors.d.ts +24 -0
  5. package/types/src/api/polling.d.ts +41 -0
  6. package/types/src/api/readers.d.ts +977 -0
  7. package/types/src/api/service-env-limit.d.ts +17 -0
  8. package/types/src/api/service-env-response.d.ts +23 -0
  9. package/types/src/api/types.d.ts +638 -0
  10. package/types/src/api.d.ts +6 -0
  11. package/types/src/authoring.d.ts +9 -0
  12. package/types/src/cli-args.d.ts +19 -0
  13. package/types/src/cli.d.ts +10 -0
  14. package/types/src/collaborators.d.ts +18 -0
  15. package/types/src/compile.d.ts +91 -0
  16. package/types/src/control.d.ts +41 -0
  17. package/types/src/database-budget.d.ts +38 -0
  18. package/types/src/descriptor.d.ts +28 -0
  19. package/types/src/execution.d.ts +137 -0
  20. package/types/src/exposure.d.ts +47 -0
  21. package/types/src/index.d.ts +31 -0
  22. package/types/src/installation/admin-options.d.ts +24 -0
  23. package/types/src/installation/admin.d.ts +35 -0
  24. package/types/src/installation/checker-release.d.ts +12 -0
  25. package/types/src/installation/deploy-options.d.ts +37 -0
  26. package/types/src/installation/deploy.d.ts +96 -0
  27. package/types/src/installation/generated/platform-console-schema.d.ts +2 -0
  28. package/types/src/installation/generated/platform-proxy-manifest.d.ts +2 -0
  29. package/types/src/installation/hosts.d.ts +38 -0
  30. package/types/src/installation/index.d.ts +9 -0
  31. package/types/src/installation/init-options.d.ts +38 -0
  32. package/types/src/installation/init.d.ts +60 -0
  33. package/types/src/installation/install-collaborators.d.ts +24 -0
  34. package/types/src/installation/install-environment.d.ts +70 -0
  35. package/types/src/installation/install-options.d.ts +49 -0
  36. package/types/src/installation/install-project.d.ts +13 -0
  37. package/types/src/installation/install-provisioning.d.ts +58 -0
  38. package/types/src/installation/install-secrets.d.ts +30 -0
  39. package/types/src/installation/install-token.d.ts +10 -0
  40. package/types/src/installation/install.d.ts +23 -0
  41. package/types/src/installation/installation-source.d.ts +8 -0
  42. package/types/src/installation/log.d.ts +44 -0
  43. package/types/src/installation/machine-key.d.ts +19 -0
  44. package/types/src/installation/mcp.d.ts +18 -0
  45. package/types/src/installation/placement-options.d.ts +11 -0
  46. package/types/src/installation/platform-archive.d.ts +7 -0
  47. package/types/src/installation/platform-source.d.ts +8 -0
  48. package/types/src/installation/platform-upload.d.ts +3 -0
  49. package/types/src/installation/proxy-manifest.d.ts +105 -0
  50. package/types/src/installation/secrets.d.ts +17 -0
  51. package/types/src/installation/sidecar.d.ts +51 -0
  52. package/types/src/installation/source-options.d.ts +1 -0
  53. package/types/src/installation/topology/artifacts.d.ts +8 -0
  54. package/types/src/installation/topology/index.d.ts +5 -0
  55. package/types/src/installation/topology/installation-schemas.d.ts +2242 -0
  56. package/types/src/installation/topology/invariants.d.ts +23 -0
  57. package/types/src/installation/topology/setups.d.ts +58 -0
  58. package/types/src/installation/topology/topology.d.ts +148 -0
  59. package/types/src/installation/topology/validate.d.ts +11 -0
  60. package/types/src/installation/upgrade-options.d.ts +26 -0
  61. package/types/src/installation/upgrade-output.d.ts +6 -0
  62. package/types/src/installation/upgrade.d.ts +88 -0
  63. package/types/src/managed-env.d.ts +57 -0
  64. package/types/src/manifest.d.ts +206 -0
  65. package/types/src/namespace/claims.d.ts +3 -0
  66. package/types/src/namespace/codec.d.ts +334 -0
  67. package/types/src/namespace/constants.d.ts +25 -0
  68. package/types/src/namespace/errors.d.ts +15 -0
  69. package/types/src/namespace/manifest.d.ts +4 -0
  70. package/types/src/namespace/operator.d.ts +12 -0
  71. package/types/src/namespace/provisioning.d.ts +4 -0
  72. package/types/src/namespace/proxy-attempt.d.ts +36 -0
  73. package/types/src/namespace/proxy-reads.d.ts +33 -0
  74. package/types/src/namespace/proxy-secrets.d.ts +8 -0
  75. package/types/src/namespace/proxy-source.d.ts +74 -0
  76. package/types/src/namespace/topology.d.ts +9 -0
  77. package/types/src/namespace/types.d.ts +99 -0
  78. package/types/src/namespace/update.d.ts +6 -0
  79. package/types/src/namespace/validation.d.ts +12 -0
  80. package/types/src/namespace.d.ts +9 -0
  81. package/types/src/plan.d.ts +12 -0
  82. package/types/src/provider.d.ts +65 -0
  83. package/types/src/proxy-manifest-carrier.d.ts +16 -0
  84. package/types/src/schema.generated.d.ts +376 -0
  85. package/types/src/service-names.d.ts +4 -0
  86. package/types/src/service-references.d.ts +13 -0
  87. package/types/src/source/constants.d.ts +6 -0
  88. package/types/src/source/port.d.ts +60 -0
  89. package/types/src/source/types.d.ts +4 -0
  90. package/types/src/source/validation.d.ts +19 -0
  91. package/types/src/source.d.ts +2 -0
  92. package/types/src/types.d.ts +121 -0
  93. package/types/src/version-attempt.d.ts +8 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabrika/provider-zerops",
3
- "version": "0.9.0-dev.1",
3
+ "version": "0.9.0-dev.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,27 +12,28 @@
12
12
  },
13
13
  "files": [
14
14
  "src",
15
- "!src/**/__tests__/**"
15
+ "!src/**/__tests__/**",
16
+ "types"
16
17
  ],
17
18
  "exports": {
18
19
  ".": {
19
20
  "bun": "./src/index.ts",
20
- "types": "./src/index.ts",
21
+ "types": "./types/src/index.d.ts",
21
22
  "default": "./src/index.ts"
22
23
  },
23
24
  "./cli": {
24
25
  "bun": "./src/cli.ts",
25
- "types": "./src/cli.ts",
26
+ "types": "./types/src/cli.d.ts",
26
27
  "default": "./src/cli.ts"
27
28
  },
28
29
  "./installation": {
29
30
  "bun": "./src/installation/index.ts",
30
- "types": "./src/installation/index.ts",
31
+ "types": "./types/src/installation/index.d.ts",
31
32
  "default": "./src/installation/index.ts"
32
33
  },
33
34
  "./installation/topology": {
34
35
  "bun": "./src/installation/topology/index.ts",
35
- "types": "./src/installation/topology/index.ts",
36
+ "types": "./types/src/installation/topology/index.d.ts",
36
37
  "default": "./src/installation/topology/index.ts"
37
38
  }
38
39
  },
@@ -43,14 +44,14 @@
43
44
  },
44
45
  "dependencies": {
45
46
  "zod": "^3.25.76",
46
- "@fabrika/auth": "0.9.0-dev.1",
47
- "@fabrika/auth-core": "0.9.0-dev.1",
48
- "@fabrika/email": "0.9.0-dev.1",
49
- "@fabrika/iam-contract": "0.9.0-dev.1",
50
- "@fabrika/installation-init": "0.9.0-dev.1",
51
- "@fabrika/operations-contract": "0.9.0-dev.1",
52
- "@fabrika/provider-contract": "0.9.0-dev.1",
53
- "@fabrika/proxy-core": "0.9.0-dev.1",
47
+ "@fabrika/auth": "0.9.0-dev.2",
48
+ "@fabrika/auth-core": "0.9.0-dev.2",
49
+ "@fabrika/email": "0.9.0-dev.2",
50
+ "@fabrika/iam-contract": "0.9.0-dev.2",
51
+ "@fabrika/installation-init": "0.9.0-dev.2",
52
+ "@fabrika/operations-contract": "0.9.0-dev.2",
53
+ "@fabrika/provider-contract": "0.9.0-dev.2",
54
+ "@fabrika/proxy-core": "0.9.0-dev.2",
54
55
  "yaml": "^2.9.1"
55
56
  }
56
57
  }
package/src/execution.ts CHANGED
@@ -265,13 +265,17 @@ const START_SCRIPT = 'fabrika/start.generated.sh'
265
265
  const DEV_INIT_SCRIPT = 'fabrika/dev-init.generated.sh'
266
266
  const PLATFORM_TSCONFIG = 'fabrika/tsconfig.platform.json'
267
267
 
268
- /** The compiler options of the platform's type check; the application's own `tsconfig.json` and its `paths` are not read. */
268
+ /**
269
+ * The compiler options of the platform's type check; the application's own `tsconfig.json` and its `paths` are not read.
270
+ * It covers the SPA under `web/` too: Bun bundles the SPA without checking its types.
271
+ */
269
272
  const PLATFORM_TSCONFIG_CONTENTS = JSON.stringify({
270
273
  compilerOptions: {
271
274
  target: 'ES2022',
272
275
  module: 'ESNext',
273
276
  moduleResolution: 'bundler',
274
277
  lib: ['ES2022', 'DOM', 'DOM.Iterable'],
278
+ jsx: 'react-jsx',
275
279
  types: ['bun'],
276
280
  strict: true,
277
281
  noUncheckedIndexedAccess: true,
@@ -282,7 +286,7 @@ const PLATFORM_TSCONFIG_CONTENTS = JSON.stringify({
282
286
  isolatedModules: true,
283
287
  noEmit: true,
284
288
  },
285
- include: ['../fabrika.contract.ts', '../src', 'entry.generated.ts'],
289
+ include: ['../fabrika.contract.ts', '../src', '../web', 'entry.generated.ts'],
286
290
  })
287
291
 
288
292
  /** One `printf` writing `lines` to `path`. Each line is single-quoted, so it may hold neither `'` nor an expansion. */
@@ -351,11 +355,11 @@ const writeBase64Command = (path: string, content: string): string => {
351
355
  return `printf '%s' '${encoded}' | base64 -d > ${path}`
352
356
  }
353
357
 
354
- /** The build's check chain as the dev launcher runs it in the application root, on what the container holds. */
358
+ /** The build's check chain, in its order, as the dev launcher runs it in the application root on what the container holds. */
355
359
  const devChecks = (release: string): DevLauncherConfig['checks'] => [
356
- { name: 'tests', command: 'bun test --isolate --pass-with-no-tests' },
357
- { name: 'fabrika-check', command: `cd /tmp && bun x --bun -p @fabrika/check@${release} fabrika-check ${RUNTIME_ROOT}` },
360
+ { name: 'tests', command: TESTS_COMMAND },
358
361
  { name: 'tsc', command: `cd /tmp && bun x --bun -p typescript@${PLATFORM_TYPESCRIPT_VERSION} tsc -p ${RUNTIME_ROOT}/${PLATFORM_TSCONFIG}` },
362
+ { name: 'fabrika-check', command: `cd /tmp && bun x --bun -p @fabrika/check@${release} fabrika-check ${RUNTIME_ROOT}` },
359
363
  ]
360
364
 
361
365
  /** What the dev launcher reads (`DEV_LAUNCHER_CONFIG_FILE`): the platform's, written after the checks. */
@@ -394,6 +398,37 @@ const initCommandScripts = (execution: ZeropsLockedExecution): readonly string[]
394
398
 
395
399
  const INSTALL = 'bun install --frozen-lockfile --ignore-scripts'
396
400
 
401
+ /**
402
+ * What `@fabrika/db/testing` prints after the label of a test file it skips without `FABRIKA_TEST_POSTGRES_URL`. Every
403
+ * framework release prints it, so the platform counts it for any application's release.
404
+ */
405
+ const DATABASE_TEST_SKIP_MARKER = ' skipped: set FABRIKA_TEST_POSTGRES_URL to run the Postgres-backed tests'
406
+
407
+ /** The prefix of the line the tests command prints after the test run. */
408
+ const TESTS_REPORT_PREFIX = 'fabrika-tests:'
409
+
410
+ /** One `bun -e "…"` running `script`, which may hold none of the characters a double-quoted shell word expands. */
411
+ const bunEvalCommand = (script: readonly string[]): string => {
412
+ const source = script.join(' ')
413
+ if (/["$`\\!]/.test(source)) throw new Error('zerops: a generated bun -e script must not contain a quote, an expansion or a backslash')
414
+ return `bun -e "${source}"`
415
+ }
416
+
417
+ // The build has no database, so every Postgres-backed test file skips and the run still passes. This command runs the
418
+ // tests as before and then says how many files did not run, so a green test step does not read as a tested database.
419
+ const TESTS_COMMAND = bunEvalCommand([
420
+ "const child = Bun.spawn([process.execPath, 'test', '--isolate', '--pass-with-no-tests'], { stdout: 'inherit', stderr: 'pipe' });",
421
+ 'const decoder = new TextDecoder();',
422
+ "let output = '';",
423
+ 'for await (const chunk of child.stderr) { process.stderr.write(chunk); output += decoder.decode(chunk, { stream: true }) }',
424
+ 'const code = await child.exited;',
425
+ `const marker = '${DATABASE_TEST_SKIP_MARKER}';`,
426
+ 'const skipped = output.split(String.fromCharCode(10)).filter((line) => line.includes(marker)).map((line) => line.slice(0, line.indexOf(marker)).trim());',
427
+ `const prefix = '${TESTS_REPORT_PREFIX}';`,
428
+ "console.warn(skipped.length === 0 ? prefix + ' no Postgres-backed test file skipped' : prefix + ' ' + skipped.length + ' Postgres-backed test files did not run, because the build has no database: ' + skipped.join(', '));",
429
+ 'process.exit(code);',
430
+ ])
431
+
397
432
  // After every check: a map is uploaded only for a build that can deploy. A failed upload never fails the build; the
398
433
  // provider reads the state from the report line.
399
434
  const sourceMapUpload = (release: string): string => `cd /tmp && bun x --bun -p @fabrika/check@${release} fabrika-source-maps ${SOURCE_ROOT} || true`
@@ -412,19 +447,21 @@ const sourceMapBuildVariables = (upload: OperationsSourceMapBuildUpload): Record
412
447
  /**
413
448
  * The generated build commands, in order; the authored SPA commands run before all of them. The application's tests
414
449
  * run first: they are authored code, so everything after them is reinstalled, regenerated or checked again. They run
415
- * `--isolate`, as the application skill runs them: a test file's DOM globals otherwise leak into the next file.
450
+ * `--isolate`, as the application skill runs them: a test file's DOM globals otherwise leak into the next file. `tsc`
451
+ * runs before the checker, as in the skill's loop: the usual quick fix of a type error is a cast or an `any`, which only
452
+ * the checker refuses, so the checker is the last word on the code.
416
453
  */
417
454
  export function generatedBuildCommands(execution: ZeropsLockedExecution, authoredSpa: readonly string[] = []): readonly string[] {
418
455
  if (!LOCKED_APP_ID_PATTERN.test(execution.appId)) throw new Error('zerops: a contract application id must match [a-z0-9][a-z0-9-]*')
419
456
  if (!FRAMEWORK_RELEASE_PATTERN.test(execution.checkRelease)) throw new Error('zerops: the checker release must be a release version')
420
457
  return [
421
458
  INSTALL,
422
- 'bun test --isolate --pass-with-no-tests',
459
+ TESTS_COMMAND,
423
460
  `rm -rf node_modules && ${INSTALL}`,
424
461
  `bun -e "await import('@fabrika/app/build').then((build) => build.writeGeneratedEntry('.', 'bun'))"`,
425
- `cd /tmp && bun x --bun -p @fabrika/check@${execution.checkRelease} fabrika-check ${SOURCE_ROOT}`,
426
462
  writeFileCommand(PLATFORM_TSCONFIG, [PLATFORM_TSCONFIG_CONTENTS]),
427
463
  `cd /tmp && bun x --bun -p typescript@${PLATFORM_TYPESCRIPT_VERSION} tsc -p ${SOURCE_ROOT}/${PLATFORM_TSCONFIG}`,
464
+ `cd /tmp && bun x --bun -p @fabrika/check@${execution.checkRelease} fabrika-check ${SOURCE_ROOT}`,
428
465
  ...initScripts(execution).map((script) => writeFileCommand(script.path, script.lines)),
429
466
  ...(execution.dev === undefined
430
467
  ? [writeFileCommand(START_SCRIPT, startScript)]
@@ -0,0 +1,5 @@
1
+ import type { ZeropsApi, ZeropsApiOptions } from './types';
2
+ /** Base URL of the Zerops public REST API. */
3
+ export declare const ZEROPS_API_BASE = "https://api.app-prg1.zerops.io/api/rest/public";
4
+ /** Build the real client. Every request carries the bearer and the run's signal. */
5
+ export declare const createZeropsApi: (options: ZeropsApiOptions) => ZeropsApi;
@@ -0,0 +1,24 @@
1
+ export declare const isAppVersionNotFoundResponse: (value: unknown) => boolean;
2
+ /**
3
+ * A non-2xx answer from the Zerops API. `code` is the platform's own error identifier, so a caller can
4
+ * branch on `userDataDuplicateKey` rather than matching a prose message.
5
+ */
6
+ export declare class ZeropsApiError extends Error {
7
+ readonly status: number;
8
+ readonly code: string;
9
+ constructor(message: string, status: number, code: string);
10
+ }
11
+ /**
12
+ * The platform's code for "this service publishes no HTTP port", the answer `enableSubdomainAccess` gives
13
+ * before a service's first deploy. Exported so a caller can say what is missing instead of relaying prose.
14
+ */
15
+ export declare const ZEROPS_SERVICE_NOT_HTTP = "serviceStackIsNotHttp";
16
+ /**
17
+ * Turn a non-2xx response into a `ZeropsApiError`. Zerops answers with `{ error: { code, message, meta } }`
18
+ * (the envelope observed live; the OpenAPI `Error` schema shows the inner `{ code, message }`).
19
+ *
20
+ * `redactDetail` drops the server's MESSAGE, which a validation error can fill with the value it
21
+ * rejected. The CODE is a fixed identifier and is kept either way — without it nothing downstream can
22
+ * tell a duplicate key from a missing service.
23
+ */
24
+ export declare const apiError: (label: string, status: number, body: unknown, redactDetail: boolean) => ZeropsApiError;
@@ -0,0 +1,41 @@
1
+ import type { Sleeper } from '../collaborators';
2
+ import { type ZeropsApi, type ZeropsProcess } from './types';
3
+ /**
4
+ * Poll ONE process to completion.
5
+ *
6
+ * The same loop `deployPlatformService` (`installation/deploy.ts`) runs over `/app-version`, run over `/process`
7
+ * instead: read, decide ONLY on a status this build knows to be terminal, sleep, and give up on a deadline
8
+ * of our own rather than on a coincidence. Returns the finished process so a caller can read
9
+ * `actionName`/`appVersionId` off it.
10
+ *
11
+ * Anything outside `ZEROPS_PROCESS_TERMINAL` means "keep waiting", including a status this build has never
12
+ * seen — which is why an unpublished vocabulary (see that constant) can cost a timeout and never a false
13
+ * success. A non-`FINISHED` terminal status throws, naming the status and nothing else.
14
+ */
15
+ export declare const waitForProcess: (input: {
16
+ api: Pick<ZeropsApi, "getProcess">;
17
+ processId: string;
18
+ sleep: Sleeper;
19
+ signal: AbortSignal;
20
+ /** What to call this process in a failure or timeout message. Defaults to its id. */
21
+ label?: string;
22
+ intervalMs?: number;
23
+ attempts?: number;
24
+ }) => Promise<ZeropsProcess>;
25
+ /**
26
+ * `enableSubdomainAccess`, repeated while the service does not yet publish an HTTP port.
27
+ *
28
+ * Live-verified: right after a service's first app version reads ACTIVE the platform still answers
29
+ * `serviceStackIsNotHttp`, and a minute later the same call is accepted. The ports lag ACTIVE, so that
30
+ * answer means "not yet" for a bounded window. Past it the last refusal is rethrown unchanged, so a caller
31
+ * still names the missing port. Any other failure is rethrown at once. The 2xx still proves nothing: the
32
+ * caller decides by reading `subdomainAccess` back.
33
+ */
34
+ export declare const enableSubdomainAccessWhenHttp: (input: {
35
+ api: Pick<ZeropsApi, "enableSubdomainAccess">;
36
+ serviceId: string;
37
+ sleep: Sleeper;
38
+ signal: AbortSignal;
39
+ intervalMs?: number;
40
+ attempts?: number;
41
+ }) => Promise<void>;