@marinoscar/platform-contract 0.1.0-next.3 → 0.1.0-next.4
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/CHANGELOG.md +173 -0
- package/README.md +23 -1
- package/dist/cjs/ai/capabilities.d.ts +85 -0
- package/dist/cjs/ai/capabilities.d.ts.map +1 -0
- package/dist/cjs/ai/capabilities.js +93 -0
- package/dist/cjs/ai/capabilities.js.map +1 -0
- package/dist/cjs/ai/constants.d.ts +239 -0
- package/dist/cjs/ai/constants.d.ts.map +1 -0
- package/dist/cjs/ai/constants.js +233 -0
- package/dist/cjs/ai/constants.js.map +1 -0
- package/dist/cjs/ai/features.d.ts +24 -0
- package/dist/cjs/ai/features.d.ts.map +1 -0
- package/dist/cjs/ai/features.js +33 -0
- package/dist/cjs/ai/features.js.map +1 -0
- package/dist/cjs/ai/index.d.ts +11 -0
- package/dist/cjs/ai/index.d.ts.map +1 -0
- package/dist/cjs/ai/index.js +81 -0
- package/dist/cjs/ai/index.js.map +1 -0
- package/dist/cjs/ai/org-keys.d.ts +50 -0
- package/dist/cjs/ai/org-keys.d.ts.map +1 -0
- package/dist/cjs/ai/org-keys.js +43 -0
- package/dist/cjs/ai/org-keys.js.map +1 -0
- package/dist/cjs/ai/schemas.d.ts +642 -0
- package/dist/cjs/ai/schemas.d.ts.map +1 -0
- package/dist/cjs/ai/schemas.js +894 -0
- package/dist/cjs/ai/schemas.js.map +1 -0
- package/dist/cjs/android-app/constants.d.ts +337 -0
- package/dist/cjs/android-app/constants.d.ts.map +1 -0
- package/dist/cjs/android-app/constants.js +312 -0
- package/dist/cjs/android-app/constants.js.map +1 -0
- package/dist/cjs/android-app/index.d.ts +5 -0
- package/dist/cjs/android-app/index.d.ts.map +1 -0
- package/dist/cjs/android-app/index.js +57 -0
- package/dist/cjs/android-app/index.js.map +1 -0
- package/dist/cjs/android-app/schemas.d.ts +358 -0
- package/dist/cjs/android-app/schemas.d.ts.map +1 -0
- package/dist/cjs/android-app/schemas.js +310 -0
- package/dist/cjs/android-app/schemas.js.map +1 -0
- package/dist/cjs/credentials/constants.d.ts +35 -0
- package/dist/cjs/credentials/constants.d.ts.map +1 -0
- package/dist/cjs/credentials/constants.js +39 -0
- package/dist/cjs/credentials/constants.js.map +1 -0
- package/dist/cjs/credentials/index.d.ts +5 -0
- package/dist/cjs/credentials/index.d.ts.map +1 -0
- package/dist/cjs/credentials/index.js +17 -0
- package/dist/cjs/credentials/index.js.map +1 -0
- package/dist/cjs/credentials/schemas.d.ts +64 -0
- package/dist/cjs/credentials/schemas.d.ts.map +1 -0
- package/dist/cjs/credentials/schemas.js +82 -0
- package/dist/cjs/credentials/schemas.js.map +1 -0
- package/dist/cjs/db-backup/config.d.ts +76 -0
- package/dist/cjs/db-backup/config.d.ts.map +1 -0
- package/dist/cjs/db-backup/config.js +115 -0
- package/dist/cjs/db-backup/config.js.map +1 -0
- package/dist/cjs/db-backup/constants.d.ts +314 -0
- package/dist/cjs/db-backup/constants.d.ts.map +1 -0
- package/dist/cjs/db-backup/constants.js +243 -0
- package/dist/cjs/db-backup/constants.js.map +1 -0
- package/dist/cjs/db-backup/index.d.ts +19 -0
- package/dist/cjs/db-backup/index.d.ts.map +1 -0
- package/dist/cjs/db-backup/index.js +81 -0
- package/dist/cjs/db-backup/index.js.map +1 -0
- package/dist/cjs/db-backup/node-credential.d.ts +37 -0
- package/dist/cjs/db-backup/node-credential.d.ts.map +1 -0
- package/dist/cjs/db-backup/node-credential.js +107 -0
- package/dist/cjs/db-backup/node-credential.js.map +1 -0
- package/dist/cjs/db-backup/node-result.d.ts +34 -0
- package/dist/cjs/db-backup/node-result.d.ts.map +1 -0
- package/dist/cjs/db-backup/node-result.js +168 -0
- package/dist/cjs/db-backup/node-result.js.map +1 -0
- package/dist/cjs/db-backup/restore.d.ts +405 -0
- package/dist/cjs/db-backup/restore.d.ts.map +1 -0
- package/dist/cjs/db-backup/restore.js +497 -0
- package/dist/cjs/db-backup/restore.js.map +1 -0
- package/dist/cjs/db-backup/run-actions.d.ts +49 -0
- package/dist/cjs/db-backup/run-actions.d.ts.map +1 -0
- package/dist/cjs/db-backup/run-actions.js +121 -0
- package/dist/cjs/db-backup/run-actions.js.map +1 -0
- package/dist/cjs/db-backup/runs-list-query.d.ts +20 -0
- package/dist/cjs/db-backup/runs-list-query.d.ts.map +1 -0
- package/dist/cjs/db-backup/runs-list-query.js +53 -0
- package/dist/cjs/db-backup/runs-list-query.js.map +1 -0
- package/dist/cjs/db-backup/runs.d.ts +46 -0
- package/dist/cjs/db-backup/runs.d.ts.map +1 -0
- package/dist/cjs/db-backup/runs.js +232 -0
- package/dist/cjs/db-backup/runs.js.map +1 -0
- package/dist/cjs/db-backup/schemas.d.ts +9 -0
- package/dist/cjs/db-backup/schemas.d.ts.map +1 -0
- package/dist/cjs/db-backup/schemas.js +31 -0
- package/dist/cjs/db-backup/schemas.js.map +1 -0
- package/dist/cjs/db-backup/settings-schemas.d.ts +217 -0
- package/dist/cjs/db-backup/settings-schemas.d.ts.map +1 -0
- package/dist/cjs/db-backup/settings-schemas.js +319 -0
- package/dist/cjs/db-backup/settings-schemas.js.map +1 -0
- package/dist/cjs/email/constants.d.ts +82 -0
- package/dist/cjs/email/constants.d.ts.map +1 -0
- package/dist/cjs/email/constants.js +82 -0
- package/dist/cjs/email/constants.js.map +1 -0
- package/dist/cjs/email/index.d.ts +5 -0
- package/dist/cjs/email/index.d.ts.map +1 -0
- package/dist/cjs/email/index.js +30 -0
- package/dist/cjs/email/index.js.map +1 -0
- package/dist/cjs/email/schemas.d.ts +276 -0
- package/dist/cjs/email/schemas.d.ts.map +1 -0
- package/dist/cjs/email/schemas.js +280 -0
- package/dist/cjs/email/schemas.js.map +1 -0
- package/dist/cjs/exports/constants.d.ts +123 -0
- package/dist/cjs/exports/constants.d.ts.map +1 -0
- package/dist/cjs/exports/constants.js +109 -0
- package/dist/cjs/exports/constants.js.map +1 -0
- package/dist/cjs/exports/index.d.ts +5 -0
- package/dist/cjs/exports/index.d.ts.map +1 -0
- package/dist/cjs/exports/index.js +42 -0
- package/dist/cjs/exports/index.js.map +1 -0
- package/dist/cjs/exports/schemas.d.ts +386 -0
- package/dist/cjs/exports/schemas.d.ts.map +1 -0
- package/dist/cjs/exports/schemas.js +288 -0
- package/dist/cjs/exports/schemas.js.map +1 -0
- package/dist/cjs/identity/constants.d.ts +273 -0
- package/dist/cjs/identity/constants.d.ts.map +1 -0
- package/dist/cjs/identity/constants.js +248 -0
- package/dist/cjs/identity/constants.js.map +1 -0
- package/dist/cjs/identity/index.d.ts +5 -0
- package/dist/cjs/identity/index.d.ts.map +1 -0
- package/dist/cjs/identity/index.js +73 -0
- package/dist/cjs/identity/index.js.map +1 -0
- package/dist/cjs/identity/schemas.d.ts +784 -0
- package/dist/cjs/identity/schemas.d.ts.map +1 -0
- package/dist/cjs/identity/schemas.js +684 -0
- package/dist/cjs/identity/schemas.js.map +1 -0
- package/dist/cjs/jobs/constants.d.ts +135 -0
- package/dist/cjs/jobs/constants.d.ts.map +1 -0
- package/dist/cjs/jobs/constants.js +130 -0
- package/dist/cjs/jobs/constants.js.map +1 -0
- package/dist/cjs/jobs/index.d.ts +9 -0
- package/dist/cjs/jobs/index.d.ts.map +1 -0
- package/dist/cjs/jobs/index.js +59 -0
- package/dist/cjs/jobs/index.js.map +1 -0
- package/dist/cjs/jobs/retention-schemas.d.ts +252 -0
- package/dist/cjs/jobs/retention-schemas.d.ts.map +1 -0
- package/dist/cjs/jobs/retention-schemas.js +233 -0
- package/dist/cjs/jobs/retention-schemas.js.map +1 -0
- package/dist/cjs/jobs/schemas.d.ts +361 -0
- package/dist/cjs/jobs/schemas.d.ts.map +1 -0
- package/dist/cjs/jobs/schemas.js +706 -0
- package/dist/cjs/jobs/schemas.js.map +1 -0
- package/dist/cjs/jobs/settings-schemas.d.ts +84 -0
- package/dist/cjs/jobs/settings-schemas.d.ts.map +1 -0
- package/dist/cjs/jobs/settings-schemas.js +116 -0
- package/dist/cjs/jobs/settings-schemas.js.map +1 -0
- package/dist/cjs/nodes/admin-schemas.d.ts +204 -0
- package/dist/cjs/nodes/admin-schemas.d.ts.map +1 -0
- package/dist/cjs/nodes/admin-schemas.js +153 -0
- package/dist/cjs/nodes/admin-schemas.js.map +1 -0
- package/dist/cjs/nodes/constants.d.ts +86 -0
- package/dist/cjs/nodes/constants.d.ts.map +1 -0
- package/dist/cjs/nodes/constants.js +102 -0
- package/dist/cjs/nodes/constants.js.map +1 -0
- package/dist/cjs/nodes/index.d.ts +8 -0
- package/dist/cjs/nodes/index.d.ts.map +1 -0
- package/dist/cjs/nodes/index.js +50 -0
- package/dist/cjs/nodes/index.js.map +1 -0
- package/dist/cjs/nodes/schemas.d.ts +332 -0
- package/dist/cjs/nodes/schemas.d.ts.map +1 -0
- package/dist/cjs/nodes/schemas.js +937 -0
- package/dist/cjs/nodes/schemas.js.map +1 -0
- package/dist/cjs/nodes/settings-schemas.d.ts +82 -0
- package/dist/cjs/nodes/settings-schemas.d.ts.map +1 -0
- package/dist/cjs/nodes/settings-schemas.js +106 -0
- package/dist/cjs/nodes/settings-schemas.js.map +1 -0
- package/dist/cjs/notifications/constants.d.ts +197 -0
- package/dist/cjs/notifications/constants.d.ts.map +1 -0
- package/dist/cjs/notifications/constants.js +181 -0
- package/dist/cjs/notifications/constants.js.map +1 -0
- package/dist/cjs/notifications/index.d.ts +5 -0
- package/dist/cjs/notifications/index.d.ts.map +1 -0
- package/dist/cjs/notifications/index.js +86 -0
- package/dist/cjs/notifications/index.js.map +1 -0
- package/dist/cjs/notifications/schemas.d.ts +1016 -0
- package/dist/cjs/notifications/schemas.d.ts.map +1 -0
- package/dist/cjs/notifications/schemas.js +851 -0
- package/dist/cjs/notifications/schemas.js.map +1 -0
- package/dist/cjs/onboarding/constants.d.ts +138 -0
- package/dist/cjs/onboarding/constants.d.ts.map +1 -0
- package/dist/cjs/onboarding/constants.js +123 -0
- package/dist/cjs/onboarding/constants.js.map +1 -0
- package/dist/cjs/onboarding/index.d.ts +5 -0
- package/dist/cjs/onboarding/index.d.ts.map +1 -0
- package/dist/cjs/onboarding/index.js +42 -0
- package/dist/cjs/onboarding/index.js.map +1 -0
- package/dist/cjs/onboarding/schemas.d.ts +360 -0
- package/dist/cjs/onboarding/schemas.d.ts.map +1 -0
- package/dist/cjs/onboarding/schemas.js +260 -0
- package/dist/cjs/onboarding/schemas.js.map +1 -0
- package/dist/cjs/settings/constants.d.ts +206 -0
- package/dist/cjs/settings/constants.d.ts.map +1 -0
- package/dist/cjs/settings/constants.js +200 -0
- package/dist/cjs/settings/constants.js.map +1 -0
- package/dist/cjs/settings/index.d.ts +6 -0
- package/dist/cjs/settings/index.d.ts.map +1 -0
- package/dist/cjs/settings/index.js +62 -0
- package/dist/cjs/settings/index.js.map +1 -0
- package/dist/cjs/settings/schemas.d.ts +574 -0
- package/dist/cjs/settings/schemas.d.ts.map +1 -0
- package/dist/cjs/settings/schemas.js +437 -0
- package/dist/cjs/settings/schemas.js.map +1 -0
- package/dist/cjs/settings/types.d.ts +79 -0
- package/dist/cjs/settings/types.d.ts.map +1 -0
- package/dist/cjs/settings/types.js +6 -0
- package/dist/cjs/settings/types.js.map +1 -0
- package/dist/cjs/sharing/constants.d.ts +216 -0
- package/dist/cjs/sharing/constants.d.ts.map +1 -0
- package/dist/cjs/sharing/constants.js +163 -0
- package/dist/cjs/sharing/constants.js.map +1 -0
- package/dist/cjs/sharing/enum.d.ts +5 -0
- package/dist/cjs/sharing/enum.d.ts.map +1 -0
- package/dist/cjs/sharing/enum.js +9 -0
- package/dist/cjs/sharing/enum.js.map +1 -0
- package/dist/cjs/sharing/grants.d.ts +490 -0
- package/dist/cjs/sharing/grants.d.ts.map +1 -0
- package/dist/cjs/sharing/grants.js +447 -0
- package/dist/cjs/sharing/grants.js.map +1 -0
- package/dist/cjs/sharing/groups.d.ts +410 -0
- package/dist/cjs/sharing/groups.d.ts.map +1 -0
- package/dist/cjs/sharing/groups.js +375 -0
- package/dist/cjs/sharing/groups.js.map +1 -0
- package/dist/cjs/sharing/index.d.ts +5 -0
- package/dist/cjs/sharing/index.d.ts.map +1 -0
- package/dist/cjs/sharing/index.js +77 -0
- package/dist/cjs/sharing/index.js.map +1 -0
- package/dist/cjs/sharing/schemas.d.ts +3 -0
- package/dist/cjs/sharing/schemas.d.ts.map +1 -0
- package/dist/cjs/sharing/schemas.js +21 -0
- package/dist/cjs/sharing/schemas.js.map +1 -0
- package/dist/cjs/storage/constants.d.ts +111 -0
- package/dist/cjs/storage/constants.d.ts.map +1 -0
- package/dist/cjs/storage/constants.js +107 -0
- package/dist/cjs/storage/constants.js.map +1 -0
- package/dist/cjs/storage/index.d.ts +27 -0
- package/dist/cjs/storage/index.d.ts.map +1 -0
- package/dist/cjs/storage/index.js +69 -0
- package/dist/cjs/storage/index.js.map +1 -0
- package/dist/cjs/storage/objects-complete-upload.d.ts +19 -0
- package/dist/cjs/storage/objects-complete-upload.d.ts.map +1 -0
- package/dist/cjs/storage/objects-complete-upload.js +19 -0
- package/dist/cjs/storage/objects-complete-upload.js.map +1 -0
- package/dist/cjs/storage/objects-download-url.d.ts +17 -0
- package/dist/cjs/storage/objects-download-url.d.ts.map +1 -0
- package/dist/cjs/storage/objects-download-url.js +16 -0
- package/dist/cjs/storage/objects-download-url.js.map +1 -0
- package/dist/cjs/storage/objects-init-upload.d.ts +39 -0
- package/dist/cjs/storage/objects-init-upload.d.ts.map +1 -0
- package/dist/cjs/storage/objects-init-upload.js +40 -0
- package/dist/cjs/storage/objects-init-upload.js.map +1 -0
- package/dist/cjs/storage/objects-list-query.d.ts +50 -0
- package/dist/cjs/storage/objects-list-query.d.ts.map +1 -0
- package/dist/cjs/storage/objects-list-query.js +23 -0
- package/dist/cjs/storage/objects-list-query.js.map +1 -0
- package/dist/cjs/storage/objects-object-response.d.ts +49 -0
- package/dist/cjs/storage/objects-object-response.d.ts.map +1 -0
- package/dist/cjs/storage/objects-object-response.js +54 -0
- package/dist/cjs/storage/objects-object-response.js.map +1 -0
- package/dist/cjs/storage/objects-update-metadata.d.ts +16 -0
- package/dist/cjs/storage/objects-update-metadata.d.ts.map +1 -0
- package/dist/cjs/storage/objects-update-metadata.js +14 -0
- package/dist/cjs/storage/objects-update-metadata.js.map +1 -0
- package/dist/cjs/storage/schemas.d.ts +13 -0
- package/dist/cjs/storage/schemas.d.ts.map +1 -0
- package/dist/cjs/storage/schemas.js +35 -0
- package/dist/cjs/storage/schemas.js.map +1 -0
- package/dist/cjs/storage/settings-schemas.d.ts +188 -0
- package/dist/cjs/storage/settings-schemas.d.ts.map +1 -0
- package/dist/cjs/storage/settings-schemas.js +223 -0
- package/dist/cjs/storage/settings-schemas.js.map +1 -0
- package/dist/cjs/storage/storage-bucket-provision.d.ts +152 -0
- package/dist/cjs/storage/storage-bucket-provision.d.ts.map +1 -0
- package/dist/cjs/storage/storage-bucket-provision.js +216 -0
- package/dist/cjs/storage/storage-bucket-provision.js.map +1 -0
- package/dist/cjs/storage/storage-config-response.d.ts +99 -0
- package/dist/cjs/storage/storage-config-response.d.ts.map +1 -0
- package/dist/cjs/storage/storage-config-response.js +173 -0
- package/dist/cjs/storage/storage-config-response.js.map +1 -0
- package/dist/cjs/storage/storage-config-update.d.ts +46 -0
- package/dist/cjs/storage/storage-config-update.d.ts.map +1 -0
- package/dist/cjs/storage/storage-config-update.js +133 -0
- package/dist/cjs/storage/storage-config-update.js.map +1 -0
- package/dist/cjs/storage/storage-connection-test.d.ts +129 -0
- package/dist/cjs/storage/storage-connection-test.d.ts.map +1 -0
- package/dist/cjs/storage/storage-connection-test.js +244 -0
- package/dist/cjs/storage/storage-connection-test.js.map +1 -0
- package/dist/cjs/storage/storage-status.d.ts +16 -0
- package/dist/cjs/storage/storage-status.d.ts.map +1 -0
- package/dist/cjs/storage/storage-status.js +23 -0
- package/dist/cjs/storage/storage-status.js.map +1 -0
- package/dist/cjs/telemetry/config.d.ts +4 -0
- package/dist/cjs/telemetry/config.d.ts.map +1 -1
- package/dist/cjs/telemetry/config.js +16 -2
- package/dist/cjs/telemetry/config.js.map +1 -1
- package/dist/cjs/telemetry/connection.d.ts +1 -1
- package/dist/cjs/telemetry/constants.d.ts +378 -6
- package/dist/cjs/telemetry/constants.d.ts.map +1 -1
- package/dist/cjs/telemetry/constants.js +290 -5
- package/dist/cjs/telemetry/constants.js.map +1 -1
- package/dist/cjs/telemetry/dashboard.d.ts +188 -17
- package/dist/cjs/telemetry/dashboard.d.ts.map +1 -1
- package/dist/cjs/telemetry/dashboard.js +61 -3
- package/dist/cjs/telemetry/dashboard.js.map +1 -1
- package/dist/cjs/telemetry/index.d.ts +4 -4
- package/dist/cjs/telemetry/index.d.ts.map +1 -1
- package/dist/cjs/telemetry/index.js +35 -3
- package/dist/cjs/telemetry/index.js.map +1 -1
- package/dist/cjs/telemetry/presentation.d.ts +243 -0
- package/dist/cjs/telemetry/presentation.d.ts.map +1 -0
- package/dist/cjs/telemetry/presentation.js +300 -0
- package/dist/cjs/telemetry/presentation.js.map +1 -0
- package/dist/cjs/telemetry/query.d.ts +2 -2
- package/dist/cjs/telemetry/schemas.d.ts +5 -2
- package/dist/cjs/telemetry/schemas.d.ts.map +1 -1
- package/dist/cjs/telemetry/schemas.js +21 -1
- package/dist/cjs/telemetry/schemas.js.map +1 -1
- package/dist/cjs/telemetry/stack.d.ts +5 -5
- package/dist/cjs/telemetry/store.d.ts +111 -0
- package/dist/cjs/telemetry/store.d.ts.map +1 -0
- package/dist/cjs/telemetry/store.js +83 -0
- package/dist/cjs/telemetry/store.js.map +1 -0
- package/dist/cjs/user-data/constants.d.ts +157 -0
- package/dist/cjs/user-data/constants.d.ts.map +1 -0
- package/dist/cjs/user-data/constants.js +137 -0
- package/dist/cjs/user-data/constants.js.map +1 -0
- package/dist/cjs/user-data/index.d.ts +5 -0
- package/dist/cjs/user-data/index.d.ts.map +1 -0
- package/dist/cjs/user-data/index.js +46 -0
- package/dist/cjs/user-data/index.js.map +1 -0
- package/dist/cjs/user-data/schemas.d.ts +306 -0
- package/dist/cjs/user-data/schemas.d.ts.map +1 -0
- package/dist/cjs/user-data/schemas.js +333 -0
- package/dist/cjs/user-data/schemas.js.map +1 -0
- package/dist/esm/ai/capabilities.d.ts +85 -0
- package/dist/esm/ai/capabilities.d.ts.map +1 -0
- package/dist/esm/ai/capabilities.js +90 -0
- package/dist/esm/ai/capabilities.js.map +1 -0
- package/dist/esm/ai/constants.d.ts +239 -0
- package/dist/esm/ai/constants.d.ts.map +1 -0
- package/dist/esm/ai/constants.js +229 -0
- package/dist/esm/ai/constants.js.map +1 -0
- package/dist/esm/ai/features.d.ts +24 -0
- package/dist/esm/ai/features.d.ts.map +1 -0
- package/dist/esm/ai/features.js +30 -0
- package/dist/esm/ai/features.js.map +1 -0
- package/dist/esm/ai/index.d.ts +11 -0
- package/dist/esm/ai/index.d.ts.map +1 -0
- package/dist/esm/ai/index.js +16 -0
- package/dist/esm/ai/index.js.map +1 -0
- package/dist/esm/ai/org-keys.d.ts +50 -0
- package/dist/esm/ai/org-keys.d.ts.map +1 -0
- package/dist/esm/ai/org-keys.js +40 -0
- package/dist/esm/ai/org-keys.js.map +1 -0
- package/dist/esm/ai/schemas.d.ts +642 -0
- package/dist/esm/ai/schemas.d.ts.map +1 -0
- package/dist/esm/ai/schemas.js +889 -0
- package/dist/esm/ai/schemas.js.map +1 -0
- package/dist/esm/android-app/constants.d.ts +337 -0
- package/dist/esm/android-app/constants.d.ts.map +1 -0
- package/dist/esm/android-app/constants.js +306 -0
- package/dist/esm/android-app/constants.js.map +1 -0
- package/dist/esm/android-app/index.d.ts +5 -0
- package/dist/esm/android-app/index.d.ts.map +1 -0
- package/dist/esm/android-app/index.js +8 -0
- package/dist/esm/android-app/index.js.map +1 -0
- package/dist/esm/android-app/schemas.d.ts +358 -0
- package/dist/esm/android-app/schemas.d.ts.map +1 -0
- package/dist/esm/android-app/schemas.js +306 -0
- package/dist/esm/android-app/schemas.js.map +1 -0
- package/dist/esm/credentials/constants.d.ts +35 -0
- package/dist/esm/credentials/constants.d.ts.map +1 -0
- package/dist/esm/credentials/constants.js +36 -0
- package/dist/esm/credentials/constants.js.map +1 -0
- package/dist/esm/credentials/index.d.ts +5 -0
- package/dist/esm/credentials/index.d.ts.map +1 -0
- package/dist/esm/credentials/index.js +8 -0
- package/dist/esm/credentials/index.js.map +1 -0
- package/dist/esm/credentials/schemas.d.ts +64 -0
- package/dist/esm/credentials/schemas.d.ts.map +1 -0
- package/dist/esm/credentials/schemas.js +79 -0
- package/dist/esm/credentials/schemas.js.map +1 -0
- package/dist/esm/db-backup/config.d.ts +76 -0
- package/dist/esm/db-backup/config.d.ts.map +1 -0
- package/dist/esm/db-backup/config.js +112 -0
- package/dist/esm/db-backup/config.js.map +1 -0
- package/dist/esm/db-backup/constants.d.ts +314 -0
- package/dist/esm/db-backup/constants.d.ts.map +1 -0
- package/dist/esm/db-backup/constants.js +240 -0
- package/dist/esm/db-backup/constants.js.map +1 -0
- package/dist/esm/db-backup/index.d.ts +19 -0
- package/dist/esm/db-backup/index.d.ts.map +1 -0
- package/dist/esm/db-backup/index.js +25 -0
- package/dist/esm/db-backup/index.js.map +1 -0
- package/dist/esm/db-backup/node-credential.d.ts +37 -0
- package/dist/esm/db-backup/node-credential.d.ts.map +1 -0
- package/dist/esm/db-backup/node-credential.js +104 -0
- package/dist/esm/db-backup/node-credential.js.map +1 -0
- package/dist/esm/db-backup/node-result.d.ts +34 -0
- package/dist/esm/db-backup/node-result.d.ts.map +1 -0
- package/dist/esm/db-backup/node-result.js +165 -0
- package/dist/esm/db-backup/node-result.js.map +1 -0
- package/dist/esm/db-backup/restore.d.ts +405 -0
- package/dist/esm/db-backup/restore.d.ts.map +1 -0
- package/dist/esm/db-backup/restore.js +494 -0
- package/dist/esm/db-backup/restore.js.map +1 -0
- package/dist/esm/db-backup/run-actions.d.ts +49 -0
- package/dist/esm/db-backup/run-actions.d.ts.map +1 -0
- package/dist/esm/db-backup/run-actions.js +118 -0
- package/dist/esm/db-backup/run-actions.js.map +1 -0
- package/dist/esm/db-backup/runs-list-query.d.ts +20 -0
- package/dist/esm/db-backup/runs-list-query.d.ts.map +1 -0
- package/dist/esm/db-backup/runs-list-query.js +50 -0
- package/dist/esm/db-backup/runs-list-query.js.map +1 -0
- package/dist/esm/db-backup/runs.d.ts +46 -0
- package/dist/esm/db-backup/runs.d.ts.map +1 -0
- package/dist/esm/db-backup/runs.js +229 -0
- package/dist/esm/db-backup/runs.js.map +1 -0
- package/dist/esm/db-backup/schemas.d.ts +9 -0
- package/dist/esm/db-backup/schemas.d.ts.map +1 -0
- package/dist/esm/db-backup/schemas.js +15 -0
- package/dist/esm/db-backup/schemas.js.map +1 -0
- package/dist/esm/db-backup/settings-schemas.d.ts +217 -0
- package/dist/esm/db-backup/settings-schemas.d.ts.map +1 -0
- package/dist/esm/db-backup/settings-schemas.js +316 -0
- package/dist/esm/db-backup/settings-schemas.js.map +1 -0
- package/dist/esm/email/constants.d.ts +82 -0
- package/dist/esm/email/constants.d.ts.map +1 -0
- package/dist/esm/email/constants.js +79 -0
- package/dist/esm/email/constants.js.map +1 -0
- package/dist/esm/email/index.d.ts +5 -0
- package/dist/esm/email/index.d.ts.map +1 -0
- package/dist/esm/email/index.js +8 -0
- package/dist/esm/email/index.js.map +1 -0
- package/dist/esm/email/schemas.d.ts +276 -0
- package/dist/esm/email/schemas.d.ts.map +1 -0
- package/dist/esm/email/schemas.js +277 -0
- package/dist/esm/email/schemas.js.map +1 -0
- package/dist/esm/exports/constants.d.ts +123 -0
- package/dist/esm/exports/constants.d.ts.map +1 -0
- package/dist/esm/exports/constants.js +106 -0
- package/dist/esm/exports/constants.js.map +1 -0
- package/dist/esm/exports/index.d.ts +5 -0
- package/dist/esm/exports/index.d.ts.map +1 -0
- package/dist/esm/exports/index.js +7 -0
- package/dist/esm/exports/index.js.map +1 -0
- package/dist/esm/exports/schemas.d.ts +386 -0
- package/dist/esm/exports/schemas.d.ts.map +1 -0
- package/dist/esm/exports/schemas.js +285 -0
- package/dist/esm/exports/schemas.js.map +1 -0
- package/dist/esm/identity/constants.d.ts +273 -0
- package/dist/esm/identity/constants.d.ts.map +1 -0
- package/dist/esm/identity/constants.js +244 -0
- package/dist/esm/identity/constants.js.map +1 -0
- package/dist/esm/identity/index.d.ts +5 -0
- package/dist/esm/identity/index.d.ts.map +1 -0
- package/dist/esm/identity/index.js +10 -0
- package/dist/esm/identity/index.js.map +1 -0
- package/dist/esm/identity/schemas.d.ts +784 -0
- package/dist/esm/identity/schemas.d.ts.map +1 -0
- package/dist/esm/identity/schemas.js +681 -0
- package/dist/esm/identity/schemas.js.map +1 -0
- package/dist/esm/jobs/constants.d.ts +135 -0
- package/dist/esm/jobs/constants.d.ts.map +1 -0
- package/dist/esm/jobs/constants.js +127 -0
- package/dist/esm/jobs/constants.js.map +1 -0
- package/dist/esm/jobs/index.d.ts +9 -0
- package/dist/esm/jobs/index.d.ts.map +1 -0
- package/dist/esm/jobs/index.js +11 -0
- package/dist/esm/jobs/index.js.map +1 -0
- package/dist/esm/jobs/retention-schemas.d.ts +252 -0
- package/dist/esm/jobs/retention-schemas.d.ts.map +1 -0
- package/dist/esm/jobs/retention-schemas.js +229 -0
- package/dist/esm/jobs/retention-schemas.js.map +1 -0
- package/dist/esm/jobs/schemas.d.ts +361 -0
- package/dist/esm/jobs/schemas.d.ts.map +1 -0
- package/dist/esm/jobs/schemas.js +703 -0
- package/dist/esm/jobs/schemas.js.map +1 -0
- package/dist/esm/jobs/settings-schemas.d.ts +84 -0
- package/dist/esm/jobs/settings-schemas.d.ts.map +1 -0
- package/dist/esm/jobs/settings-schemas.js +113 -0
- package/dist/esm/jobs/settings-schemas.js.map +1 -0
- package/dist/esm/nodes/admin-schemas.d.ts +204 -0
- package/dist/esm/nodes/admin-schemas.d.ts.map +1 -0
- package/dist/esm/nodes/admin-schemas.js +150 -0
- package/dist/esm/nodes/admin-schemas.js.map +1 -0
- package/dist/esm/nodes/constants.d.ts +86 -0
- package/dist/esm/nodes/constants.d.ts.map +1 -0
- package/dist/esm/nodes/constants.js +99 -0
- package/dist/esm/nodes/constants.js.map +1 -0
- package/dist/esm/nodes/index.d.ts +8 -0
- package/dist/esm/nodes/index.d.ts.map +1 -0
- package/dist/esm/nodes/index.js +11 -0
- package/dist/esm/nodes/index.js.map +1 -0
- package/dist/esm/nodes/schemas.d.ts +332 -0
- package/dist/esm/nodes/schemas.d.ts.map +1 -0
- package/dist/esm/nodes/schemas.js +934 -0
- package/dist/esm/nodes/schemas.js.map +1 -0
- package/dist/esm/nodes/settings-schemas.d.ts +82 -0
- package/dist/esm/nodes/settings-schemas.d.ts.map +1 -0
- package/dist/esm/nodes/settings-schemas.js +103 -0
- package/dist/esm/nodes/settings-schemas.js.map +1 -0
- package/dist/esm/notifications/constants.d.ts +197 -0
- package/dist/esm/notifications/constants.d.ts.map +1 -0
- package/dist/esm/notifications/constants.js +178 -0
- package/dist/esm/notifications/constants.js.map +1 -0
- package/dist/esm/notifications/index.d.ts +5 -0
- package/dist/esm/notifications/index.d.ts.map +1 -0
- package/dist/esm/notifications/index.js +9 -0
- package/dist/esm/notifications/index.js.map +1 -0
- package/dist/esm/notifications/schemas.d.ts +1016 -0
- package/dist/esm/notifications/schemas.d.ts.map +1 -0
- package/dist/esm/notifications/schemas.js +848 -0
- package/dist/esm/notifications/schemas.js.map +1 -0
- package/dist/esm/onboarding/constants.d.ts +138 -0
- package/dist/esm/onboarding/constants.d.ts.map +1 -0
- package/dist/esm/onboarding/constants.js +120 -0
- package/dist/esm/onboarding/constants.js.map +1 -0
- package/dist/esm/onboarding/index.d.ts +5 -0
- package/dist/esm/onboarding/index.d.ts.map +1 -0
- package/dist/esm/onboarding/index.js +7 -0
- package/dist/esm/onboarding/index.js.map +1 -0
- package/dist/esm/onboarding/schemas.d.ts +360 -0
- package/dist/esm/onboarding/schemas.d.ts.map +1 -0
- package/dist/esm/onboarding/schemas.js +257 -0
- package/dist/esm/onboarding/schemas.js.map +1 -0
- package/dist/esm/settings/constants.d.ts +206 -0
- package/dist/esm/settings/constants.d.ts.map +1 -0
- package/dist/esm/settings/constants.js +197 -0
- package/dist/esm/settings/constants.js.map +1 -0
- package/dist/esm/settings/index.d.ts +6 -0
- package/dist/esm/settings/index.d.ts.map +1 -0
- package/dist/esm/settings/index.js +11 -0
- package/dist/esm/settings/index.js.map +1 -0
- package/dist/esm/settings/schemas.d.ts +574 -0
- package/dist/esm/settings/schemas.d.ts.map +1 -0
- package/dist/esm/settings/schemas.js +434 -0
- package/dist/esm/settings/schemas.js.map +1 -0
- package/dist/esm/settings/types.d.ts +79 -0
- package/dist/esm/settings/types.d.ts.map +1 -0
- package/dist/esm/settings/types.js +5 -0
- package/dist/esm/settings/types.js.map +1 -0
- package/dist/esm/sharing/constants.d.ts +216 -0
- package/dist/esm/sharing/constants.d.ts.map +1 -0
- package/dist/esm/sharing/constants.js +159 -0
- package/dist/esm/sharing/constants.js.map +1 -0
- package/dist/esm/sharing/enum.d.ts +5 -0
- package/dist/esm/sharing/enum.d.ts.map +1 -0
- package/dist/esm/sharing/enum.js +6 -0
- package/dist/esm/sharing/enum.js.map +1 -0
- package/dist/esm/sharing/grants.d.ts +490 -0
- package/dist/esm/sharing/grants.d.ts.map +1 -0
- package/dist/esm/sharing/grants.js +444 -0
- package/dist/esm/sharing/grants.js.map +1 -0
- package/dist/esm/sharing/groups.d.ts +410 -0
- package/dist/esm/sharing/groups.d.ts.map +1 -0
- package/dist/esm/sharing/groups.js +372 -0
- package/dist/esm/sharing/groups.js.map +1 -0
- package/dist/esm/sharing/index.d.ts +5 -0
- package/dist/esm/sharing/index.d.ts.map +1 -0
- package/dist/esm/sharing/index.js +11 -0
- package/dist/esm/sharing/index.js.map +1 -0
- package/dist/esm/sharing/schemas.d.ts +3 -0
- package/dist/esm/sharing/schemas.d.ts.map +1 -0
- package/dist/esm/sharing/schemas.js +5 -0
- package/dist/esm/sharing/schemas.js.map +1 -0
- package/dist/esm/storage/constants.d.ts +111 -0
- package/dist/esm/storage/constants.d.ts.map +1 -0
- package/dist/esm/storage/constants.js +104 -0
- package/dist/esm/storage/constants.js.map +1 -0
- package/dist/esm/storage/index.d.ts +27 -0
- package/dist/esm/storage/index.d.ts.map +1 -0
- package/dist/esm/storage/index.js +23 -0
- package/dist/esm/storage/index.js.map +1 -0
- package/dist/esm/storage/objects-complete-upload.d.ts +19 -0
- package/dist/esm/storage/objects-complete-upload.d.ts.map +1 -0
- package/dist/esm/storage/objects-complete-upload.js +16 -0
- package/dist/esm/storage/objects-complete-upload.js.map +1 -0
- package/dist/esm/storage/objects-download-url.d.ts +17 -0
- package/dist/esm/storage/objects-download-url.d.ts.map +1 -0
- package/dist/esm/storage/objects-download-url.js +13 -0
- package/dist/esm/storage/objects-download-url.js.map +1 -0
- package/dist/esm/storage/objects-init-upload.d.ts +39 -0
- package/dist/esm/storage/objects-init-upload.d.ts.map +1 -0
- package/dist/esm/storage/objects-init-upload.js +37 -0
- package/dist/esm/storage/objects-init-upload.js.map +1 -0
- package/dist/esm/storage/objects-list-query.d.ts +50 -0
- package/dist/esm/storage/objects-list-query.d.ts.map +1 -0
- package/dist/esm/storage/objects-list-query.js +20 -0
- package/dist/esm/storage/objects-list-query.js.map +1 -0
- package/dist/esm/storage/objects-object-response.d.ts +49 -0
- package/dist/esm/storage/objects-object-response.d.ts.map +1 -0
- package/dist/esm/storage/objects-object-response.js +51 -0
- package/dist/esm/storage/objects-object-response.js.map +1 -0
- package/dist/esm/storage/objects-update-metadata.d.ts +16 -0
- package/dist/esm/storage/objects-update-metadata.d.ts.map +1 -0
- package/dist/esm/storage/objects-update-metadata.js +11 -0
- package/dist/esm/storage/objects-update-metadata.js.map +1 -0
- package/dist/esm/storage/schemas.d.ts +13 -0
- package/dist/esm/storage/schemas.d.ts.map +1 -0
- package/dist/esm/storage/schemas.js +19 -0
- package/dist/esm/storage/schemas.js.map +1 -0
- package/dist/esm/storage/settings-schemas.d.ts +188 -0
- package/dist/esm/storage/settings-schemas.d.ts.map +1 -0
- package/dist/esm/storage/settings-schemas.js +220 -0
- package/dist/esm/storage/settings-schemas.js.map +1 -0
- package/dist/esm/storage/storage-bucket-provision.d.ts +152 -0
- package/dist/esm/storage/storage-bucket-provision.d.ts.map +1 -0
- package/dist/esm/storage/storage-bucket-provision.js +213 -0
- package/dist/esm/storage/storage-bucket-provision.js.map +1 -0
- package/dist/esm/storage/storage-config-response.d.ts +99 -0
- package/dist/esm/storage/storage-config-response.d.ts.map +1 -0
- package/dist/esm/storage/storage-config-response.js +170 -0
- package/dist/esm/storage/storage-config-response.js.map +1 -0
- package/dist/esm/storage/storage-config-update.d.ts +46 -0
- package/dist/esm/storage/storage-config-update.d.ts.map +1 -0
- package/dist/esm/storage/storage-config-update.js +130 -0
- package/dist/esm/storage/storage-config-update.js.map +1 -0
- package/dist/esm/storage/storage-connection-test.d.ts +129 -0
- package/dist/esm/storage/storage-connection-test.d.ts.map +1 -0
- package/dist/esm/storage/storage-connection-test.js +241 -0
- package/dist/esm/storage/storage-connection-test.js.map +1 -0
- package/dist/esm/storage/storage-status.d.ts +16 -0
- package/dist/esm/storage/storage-status.d.ts.map +1 -0
- package/dist/esm/storage/storage-status.js +20 -0
- package/dist/esm/storage/storage-status.js.map +1 -0
- package/dist/esm/telemetry/config.d.ts +4 -0
- package/dist/esm/telemetry/config.d.ts.map +1 -1
- package/dist/esm/telemetry/config.js +16 -2
- package/dist/esm/telemetry/config.js.map +1 -1
- package/dist/esm/telemetry/connection.d.ts +1 -1
- package/dist/esm/telemetry/constants.d.ts +378 -6
- package/dist/esm/telemetry/constants.d.ts.map +1 -1
- package/dist/esm/telemetry/constants.js +288 -4
- package/dist/esm/telemetry/constants.js.map +1 -1
- package/dist/esm/telemetry/dashboard.d.ts +188 -17
- package/dist/esm/telemetry/dashboard.d.ts.map +1 -1
- package/dist/esm/telemetry/dashboard.js +61 -3
- package/dist/esm/telemetry/dashboard.js.map +1 -1
- package/dist/esm/telemetry/index.d.ts +4 -4
- package/dist/esm/telemetry/index.d.ts.map +1 -1
- package/dist/esm/telemetry/index.js +2 -2
- package/dist/esm/telemetry/index.js.map +1 -1
- package/dist/esm/telemetry/presentation.d.ts +243 -0
- package/dist/esm/telemetry/presentation.d.ts.map +1 -0
- package/dist/esm/telemetry/presentation.js +297 -0
- package/dist/esm/telemetry/presentation.js.map +1 -0
- package/dist/esm/telemetry/query.d.ts +2 -2
- package/dist/esm/telemetry/schemas.d.ts +5 -2
- package/dist/esm/telemetry/schemas.d.ts.map +1 -1
- package/dist/esm/telemetry/schemas.js +3 -1
- package/dist/esm/telemetry/schemas.js.map +1 -1
- package/dist/esm/telemetry/stack.d.ts +5 -5
- package/dist/esm/telemetry/store.d.ts +111 -0
- package/dist/esm/telemetry/store.d.ts.map +1 -0
- package/dist/esm/telemetry/store.js +80 -0
- package/dist/esm/telemetry/store.js.map +1 -0
- package/dist/esm/user-data/constants.d.ts +157 -0
- package/dist/esm/user-data/constants.d.ts.map +1 -0
- package/dist/esm/user-data/constants.js +134 -0
- package/dist/esm/user-data/constants.js.map +1 -0
- package/dist/esm/user-data/index.d.ts +5 -0
- package/dist/esm/user-data/index.d.ts.map +1 -0
- package/dist/esm/user-data/index.js +7 -0
- package/dist/esm/user-data/index.js.map +1 -0
- package/dist/esm/user-data/schemas.d.ts +306 -0
- package/dist/esm/user-data/schemas.d.ts.map +1 -0
- package/dist/esm/user-data/schemas.js +330 -0
- package/dist/esm/user-data/schemas.js.map +1 -0
- package/package.json +151 -1
|
@@ -0,0 +1,937 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// Nodes: the node routes' request shapes (issue #734, PP-8.2)
|
|
4
|
+
// =============================================================================
|
|
5
|
+
//
|
|
6
|
+
// The node control plane (`register`, `heartbeat`, `claim`, `renew`, `result`,
|
|
7
|
+
// `fail`), the data plane's two URL mints, the per-job secret request and the
|
|
8
|
+
// node credential mint, as zod schemas. Moved verbatim (comments included)
|
|
9
|
+
// from `@marinoscar/platform-api/nodes`'s dto files, which wrap these with
|
|
10
|
+
// `createZodDto`; the response shapes stay there as Swagger classes. The
|
|
11
|
+
// node runner of `@marinoscar/platform-cli` sends exactly these bodies.
|
|
12
|
+
// =============================================================================
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.nodeJobSecretRequestSchema = exports.nodeUploadUrlSchema = exports.nodeDownloadUrlSchema = exports.nodeJobFailureSchema = exports.nodeJobResultSchema = exports.renewLeaseSchema = exports.claimJobsSchema = exports.heartbeatNodeSchema = exports.registerNodeSchema = exports.nodeVitalsSchema = exports.nodeVitalsExtraSchema = exports.nodeVitalsCountersSchema = exports.createNodeCredentialSchema = exports.claimTokenField = void 0;
|
|
15
|
+
const zod_1 = require("zod");
|
|
16
|
+
const constants_js_1 = require("./constants.js");
|
|
17
|
+
// -----------------------------------------------------------------------------
|
|
18
|
+
// From claim-token.field.ts: The claim token, as a node quotes it back (issue #364, epic #254)
|
|
19
|
+
// -----------------------------------------------------------------------------
|
|
20
|
+
// =============================================================================
|
|
21
|
+
// The claim token, as a node quotes it back (issue #364, epic #254)
|
|
22
|
+
// =============================================================================
|
|
23
|
+
//
|
|
24
|
+
// ONE FIELD IN ONE FILE, which in this folder needs a reason — the file beside
|
|
25
|
+
// it argues at length for keeping SIX request bodies together. The reason is
|
|
26
|
+
// that this field is not part of any one of those conversations: it is the
|
|
27
|
+
// same sentence spoken on SIX ROUTES ACROSS THREE DTO FILES — renew, result
|
|
28
|
+
// and failure (`node-control-plane.dto.ts`), download-url and upload-url
|
|
29
|
+
// (`node-data-plane.dto.ts`), and secret (`node-job-secret.dto.ts`) — and the
|
|
30
|
+
// one thing that must never differ between them is what that sentence means.
|
|
31
|
+
// Copied six times it drifts exactly once, in the direction that costs the
|
|
32
|
+
// most: somebody makes it `.nullable()` on one route to accommodate a client
|
|
33
|
+
// that serialises absent fields as `null`, and on that route alone a node
|
|
34
|
+
// asserting "no token" starts matching `claim_token IS NULL` instead of being
|
|
35
|
+
// refused.
|
|
36
|
+
//
|
|
37
|
+
// The alternative was exporting it from `node-control-plane.dto.ts`, and it is
|
|
38
|
+
// rejected for what it would say rather than what it would do: it would make
|
|
39
|
+
// the data plane's and the broker's guards look like borrowings from the
|
|
40
|
+
// control plane, when in fact all six are the same guard. Nothing here is
|
|
41
|
+
// control plane or data plane; it is the identity of a CLAIM.
|
|
42
|
+
// =============================================================================
|
|
43
|
+
/**
|
|
44
|
+
* THE CLAIM THIS MESSAGE IS ABOUT — `jobs.claim_token`, handed to the node in
|
|
45
|
+
* the claim response and quoted back on every route that speaks for a held
|
|
46
|
+
* job (#364).
|
|
47
|
+
*
|
|
48
|
+
* WHY A NODE ID IS NOT ENOUGH, which is the whole of this field. Every guard
|
|
49
|
+
* on the six routes above identified the caller by `claimedByNodeId` alone,
|
|
50
|
+
* which tells one node from another and NOT ONE NODE FROM ITSELF. A node that
|
|
51
|
+
* claims job J, stalls past its lease, is reaped, and then claims J again in a
|
|
52
|
+
* second worker slot has two live slots quoting the same node id, and every
|
|
53
|
+
* one of those six routes will believe the older one:
|
|
54
|
+
*
|
|
55
|
+
* - `renew` — the stale slot extends the lease its OWN newer claim is
|
|
56
|
+
* running under, so a second slot that dies is reaped late, for as long as
|
|
57
|
+
* the first keeps ticking.
|
|
58
|
+
* - `result` / `failure` — the stale slot SETTLES a job its newer claim is
|
|
59
|
+
* still executing, persisting output computed against an earlier attempt
|
|
60
|
+
* or charging a failure against a run that is going fine.
|
|
61
|
+
* - `upload-url` — the sharpest of the six, and the quietest. With
|
|
62
|
+
* `deriveOutputKey` (#348) the key is a function of the JOB, not of the
|
|
63
|
+
* claim, so a stale slot is handed a signed PUT for the exact output key
|
|
64
|
+
* its own later claim is currently writing. Both PUTs "succeed"; the
|
|
65
|
+
* bytes that survive are whichever finished last, and nothing anywhere
|
|
66
|
+
* records that two ran.
|
|
67
|
+
* - `download-url` — a bearer capability for the job's input, minted for a
|
|
68
|
+
* slot that no longer holds the row.
|
|
69
|
+
* - `secret` — a LIVE DATABASE CREDENTIAL handed to a slot that lost the
|
|
70
|
+
* job, valid for the lease of a claim that is not its own.
|
|
71
|
+
*
|
|
72
|
+
* The token is minted per row by the claim statement
|
|
73
|
+
* (`job-claim.service.ts`, `gen_random_uuid()`), so those two claims carry
|
|
74
|
+
* different tokens and the stale one is refused.
|
|
75
|
+
*
|
|
76
|
+
* ⚠ OPTIONAL ON THE WIRE EVERYWHERE, AND THAT IS LOAD-BEARING, not politeness.
|
|
77
|
+
* A fleet is upgraded one machine at a time; a node running older CLI code
|
|
78
|
+
* omits this field, and the server must then behave EXACTLY as it did before —
|
|
79
|
+
* the node id and the lease alone — rather than 400 the request or 409 the
|
|
80
|
+
* job. Same posture as `renewIntervalMs` in #347: additive, ignorable,
|
|
81
|
+
* strictly better when present. The ambiguity above stays open for that node
|
|
82
|
+
* until it is upgraded, which is a rolling-upgrade window rather than a new
|
|
83
|
+
* hole; nothing the server can do closes it earlier, because the only value
|
|
84
|
+
* able to tell two slots of one node apart is one only they hold.
|
|
85
|
+
*
|
|
86
|
+
* ⚠ OMITTED MUST STAY `undefined` AND MUST NOT BECOME `null`. Downstream this
|
|
87
|
+
* value reaches `heldLeaseWhere`, where the two mean opposite things:
|
|
88
|
+
* `undefined` drops the clause entirely ("I am not asserting a claim"), while
|
|
89
|
+
* `null` matches `claim_token IS NULL` ("I assert this row carries no token",
|
|
90
|
+
* which is what a claim taken before the column existed looks like).
|
|
91
|
+
* `.optional()` with no `.nullable()` is what keeps them apart — a body that
|
|
92
|
+
* spells the key as `null` is refused rather than silently reinterpreted as
|
|
93
|
+
* the other statement. Apply `.optional()` at each use site rather than baking
|
|
94
|
+
* it in here, so every body says out loud that the field may be absent.
|
|
95
|
+
*
|
|
96
|
+
* Validated as a uuid rather than as any bounded string because the column is
|
|
97
|
+
* `uuid`: a garbage value reaching a `where` clause is a Postgres cast error
|
|
98
|
+
* (a 500 about "inconsistent column data"), and a clean 400 naming the field
|
|
99
|
+
* is a better answer to a malformed token than a 500 is.
|
|
100
|
+
*
|
|
101
|
+
* @stability experimental
|
|
102
|
+
*/
|
|
103
|
+
exports.claimTokenField = zod_1.z.uuid().describe(
|
|
104
|
+
// ⚠ THE PUBLISHED DESCRIPTION IS PART OF THE ONE DEFINITION, and it is here
|
|
105
|
+
// for the reason the schema is: six routes describing one grant six ways is
|
|
106
|
+
// six chances to describe it differently, and a node's author reads
|
|
107
|
+
// whichever one they happened to open. `.describe()` rides through
|
|
108
|
+
// `.optional()` into every generated body, so `openapi.json` says the same
|
|
109
|
+
// sentence six times by construction.
|
|
110
|
+
'The `claimToken` this assignment was handed in the claim response, quoted back so the ' +
|
|
111
|
+
'server can tell THIS claim of the job from a later one by the same node — the difference ' +
|
|
112
|
+
'between renewing, settling, signing or crediting your own run and one your node started ' +
|
|
113
|
+
'later. Optional: omit it and the request is identified by node id alone, exactly as ' +
|
|
114
|
+
'before, so an older client is refused nothing and stays exactly as ambiguous as it was. ' +
|
|
115
|
+
'Omit the key rather than sending `null`; `null` is a different assertion and is refused.');
|
|
116
|
+
// -----------------------------------------------------------------------------
|
|
117
|
+
// From create-node-credential.dto.ts: The create-credential request body (issue #267, epic #254)
|
|
118
|
+
// -----------------------------------------------------------------------------
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// The create-credential request body (issue #267, epic #254)
|
|
121
|
+
// =============================================================================
|
|
122
|
+
//
|
|
123
|
+
// Deliberately NOT `CreatePatDto`'s `{ durationValue, durationUnit }` pair.
|
|
124
|
+
// That pair exists on a PAT because a PAT MUST expire — `PersonalAccessToken
|
|
125
|
+
// .expiresAt` is a required column — so its request body has to make the
|
|
126
|
+
// caller say when, and the two-field shape ("30" + "days") is friendlier than
|
|
127
|
+
// a raw timestamp for a human filling in a form.
|
|
128
|
+
//
|
|
129
|
+
// A node credential's expiry is OPTIONAL, and the reason is written out in
|
|
130
|
+
// full above `NodeCredential.expiresAt` in `prisma/schema.prisma`: a worker
|
|
131
|
+
// node runs unattended for months, and a mandatory expiry turns a fleet going
|
|
132
|
+
// dark at 3am into the DEFAULT behaviour rather than an incident. So the
|
|
133
|
+
// field is optional here, and its absence is a real, supported answer —
|
|
134
|
+
// "never expires, authenticate indefinitely until revoked" — not a validation
|
|
135
|
+
// hole and not an unset value some later code has to fill in.
|
|
136
|
+
//
|
|
137
|
+
// WHY `expiresInDays` AND NOT AN ISO TIMESTAMP. A caller-supplied absolute
|
|
138
|
+
// `expiresAt` would have to be validated against the server's clock (is it in
|
|
139
|
+
// the past? is it absurdly far in the future?) and would silently encode the
|
|
140
|
+
// CALLER's idea of "now" — a CLI on a box with a skewed clock could mint a
|
|
141
|
+
// credential that is already expired, or one that outlives the deployment. A
|
|
142
|
+
// relative duration is interpreted by the server against the server's own
|
|
143
|
+
// clock, which is the same clock `validateToken` compares against, so the two
|
|
144
|
+
// can never disagree. Days rather than a unit enum because a node credential
|
|
145
|
+
// measured in minutes is not a use case anybody has: this credential exists
|
|
146
|
+
// precisely for the long-lived, unattended case.
|
|
147
|
+
// =============================================================================
|
|
148
|
+
/**
|
|
149
|
+
* The body that mints a node credential (`nod_` token).
|
|
150
|
+
*
|
|
151
|
+
* @stability experimental
|
|
152
|
+
*/
|
|
153
|
+
exports.createNodeCredentialSchema = zod_1.z.object({
|
|
154
|
+
/** The credential's display name, 1 to 100 characters. */
|
|
155
|
+
name: zod_1.z
|
|
156
|
+
.string()
|
|
157
|
+
.trim()
|
|
158
|
+
.min(1, 'Name is required')
|
|
159
|
+
.max(constants_js_1.MAX_NODE_CREDENTIAL_NAME_LENGTH, 'Name must be 100 characters or less'),
|
|
160
|
+
// Optional ON PURPOSE — see the file header. Omitted means `expiresAt: null`
|
|
161
|
+
// in the row, which `validateToken` treats as "no expiry to check", not as
|
|
162
|
+
// "expired" and not as "not configured yet".
|
|
163
|
+
/** Days until it expires, at most `MAX_NODE_CREDENTIAL_DAYS`; omitted, it never expires. */
|
|
164
|
+
expiresInDays: zod_1.z
|
|
165
|
+
.number()
|
|
166
|
+
.int('Expiry must be a whole number of days')
|
|
167
|
+
.min(1, 'Expiry must be at least 1 day')
|
|
168
|
+
.max(constants_js_1.MAX_NODE_CREDENTIAL_DAYS, `Expiry must be at most ${constants_js_1.MAX_NODE_CREDENTIAL_DAYS} days`)
|
|
169
|
+
.optional(),
|
|
170
|
+
});
|
|
171
|
+
// -----------------------------------------------------------------------------
|
|
172
|
+
// From node-control-plane.dto.ts: The node control plane's request bodies (issue #268, epic #254)
|
|
173
|
+
// -----------------------------------------------------------------------------
|
|
174
|
+
// =============================================================================
|
|
175
|
+
// The node control plane's request bodies (issue #268, epic #254)
|
|
176
|
+
// =============================================================================
|
|
177
|
+
//
|
|
178
|
+
// SIX BODIES IN ONE FILE, deliberately, where `create-node-credential.dto.ts`
|
|
179
|
+
// beside it is one body in one file. These six are not six independent
|
|
180
|
+
// shapes; they are one CONVERSATION between a worker node and this server —
|
|
181
|
+
// register, heartbeat, claim, renew, result, failure — and every one of the
|
|
182
|
+
// limits below (`MAX_NODE_CONCURRENCY`, the type-list caps, the error length)
|
|
183
|
+
// has to be the same number in more than one of them or the conversation
|
|
184
|
+
// develops a step that accepts what an earlier step refused. Split across six
|
|
185
|
+
// files, those shared constants become six imports nobody keeps aligned;
|
|
186
|
+
// together, a change to the concurrency ceiling is one line that every body
|
|
187
|
+
// sees — and `claimToken` below is the same argument one level up: the three
|
|
188
|
+
// bodies here that speak for a held job share ONE field definition with the
|
|
189
|
+
// three outside this file that do the same (`node-data-plane.dto.ts`,
|
|
190
|
+
// `node-job-secret.dto.ts`), so "renew accepts a token but failure silently
|
|
191
|
+
// ignores it" is unwritable. That definition lives in `claim-token.field.ts`,
|
|
192
|
+
// which carries its own note on why one field earned a file of its own.
|
|
193
|
+
//
|
|
194
|
+
// -----------------------------------------------------------------------------
|
|
195
|
+
// EVERY FIELD HERE ARRIVES FROM A MACHINE THIS DEPLOYMENT MAY NOT OWN
|
|
196
|
+
// -----------------------------------------------------------------------------
|
|
197
|
+
//
|
|
198
|
+
// That is the whole reason these schemas are as tight as they are. A node is
|
|
199
|
+
// authenticated (a `nod_` credential resolves to its owner) but it is not
|
|
200
|
+
// TRUSTED in the sense a first-party service is: it runs unattended on
|
|
201
|
+
// somebody's spare box, its config file is editable by whoever has that box,
|
|
202
|
+
// and the numbers it reports about itself go straight into a row this server
|
|
203
|
+
// then makes scheduling decisions from. So:
|
|
204
|
+
//
|
|
205
|
+
// - `concurrency` is bounded because it becomes the CLAIM LIMIT. An
|
|
206
|
+
// unbounded value is a node that asks for every runnable row in the queue
|
|
207
|
+
// in one call and holds all of them under one lease — a fleet-wide denial
|
|
208
|
+
// of service written as a config typo.
|
|
209
|
+
// - `eligibleTypes` is bounded in both length and element size because it
|
|
210
|
+
// is stored as an array column and then used as a `text[]` parameter in
|
|
211
|
+
// the claim's `type = ANY(...)`.
|
|
212
|
+
// - `error` is bounded because it lands in `Job.lastError`, which the admin
|
|
213
|
+
// job list renders. `JobTerminalService` truncates too, at 2000 — the
|
|
214
|
+
// same number on purpose, so the wire limit and the storage limit cannot
|
|
215
|
+
// disagree about what "too long" means.
|
|
216
|
+
//
|
|
217
|
+
// -----------------------------------------------------------------------------
|
|
218
|
+
// WHAT IS DELIBERATELY *NOT* IN ANY OF THESE BODIES
|
|
219
|
+
// -----------------------------------------------------------------------------
|
|
220
|
+
//
|
|
221
|
+
// REJECTED: a node-supplied `leaseMs` on claim or renew. It reads as
|
|
222
|
+
// courteous — the node knows how long its work takes — and it hands the one
|
|
223
|
+
// safety property the lease exists for to the least trustworthy participant.
|
|
224
|
+
// A node that asks for a 24-hour lease parks every row it claims for a day:
|
|
225
|
+
// the reaper (#263) will not touch a live lease, so a node that then dies
|
|
226
|
+
// takes its jobs with it until tomorrow, and nothing in the fleet looks
|
|
227
|
+
// broken while it happens. The lease is DERIVED on the server from
|
|
228
|
+
// `JOBS_JOB_TIMEOUT_MS` (`resolveJobLeaseMs`), identically for both
|
|
229
|
+
// executors, and a node cannot influence it.
|
|
230
|
+
//
|
|
231
|
+
// REJECTED: a node-supplied `status: 'disabled' | 'draining'` on heartbeat.
|
|
232
|
+
// Those two are operator decisions — see `WorkerNode.status` in
|
|
233
|
+
// `schema.prisma` — and a node that could report them could also report its
|
|
234
|
+
// way out of them. The union below is the two states a node may claim about
|
|
235
|
+
// itself, and `NodesService.heartbeat` additionally refuses to let even those
|
|
236
|
+
// overwrite an operator's `disabled`/`draining`.
|
|
237
|
+
//
|
|
238
|
+
// REJECTED: `willRetry` being anything but advisory. It is accepted (a node
|
|
239
|
+
// that has just read a provider's response often does know) and it is never
|
|
240
|
+
// acted on: the server's attempt budget decides, in `JobTerminalService`,
|
|
241
|
+
// because a node that could dictate "retry me" could retry itself forever
|
|
242
|
+
// past a budget that exists precisely to bound a job nobody is watching.
|
|
243
|
+
// =============================================================================
|
|
244
|
+
/** Cap on one job-type string, matching what a handler `type` key ever is. */
|
|
245
|
+
const MAX_TYPE_LENGTH = 200;
|
|
246
|
+
/**
|
|
247
|
+
* Cap on a node-reported failure message.
|
|
248
|
+
*
|
|
249
|
+
* The same 2000 as `MAX_LAST_ERROR_LENGTH` in `job-terminal.service.ts`, and
|
|
250
|
+
* that is the point: the terminal service truncates whatever it is given, so
|
|
251
|
+
* a larger limit here would only mean accepting bytes that are guaranteed to
|
|
252
|
+
* be thrown away, and a smaller one would reject messages the storage layer
|
|
253
|
+
* would have kept.
|
|
254
|
+
*/
|
|
255
|
+
const MAX_ERROR_LENGTH = 2000;
|
|
256
|
+
/** A non-empty, bounded job-type key. */
|
|
257
|
+
const jobType = zod_1.z.string().trim().min(1).max(MAX_TYPE_LENGTH);
|
|
258
|
+
/**
|
|
259
|
+
* `jobs.claim_token`, as the node quotes it back — the field three of the
|
|
260
|
+
* bodies below carry, and three more outside this file (the two data-plane
|
|
261
|
+
* mints and the secret broker) carry for the same reason.
|
|
262
|
+
*
|
|
263
|
+
* SHARED, NOT REDECLARED: `claim-token.field.ts` holds the field and the whole
|
|
264
|
+
* argument for it, including why `undefined` and `null` must stay different
|
|
265
|
+
* statements. Six copies of a uuid would drift exactly once, and on one route
|
|
266
|
+
* only, which is the worst shape that drift can take.
|
|
267
|
+
*/
|
|
268
|
+
const claimToken = exports.claimTokenField;
|
|
269
|
+
/**
|
|
270
|
+
* The node's self-reported capability bag.
|
|
271
|
+
*
|
|
272
|
+
* `Record<string, unknown>` and nothing narrower, mirroring
|
|
273
|
+
* `WorkerNode.capabilities` being JSONB: the shape is the FLEET PAGE's
|
|
274
|
+
* business (#276), not this server's, and pinning it here would mean a node
|
|
275
|
+
* that learns to report one new fact needs an API deploy before it may say
|
|
276
|
+
* so. Depth and size are bounded by the global body-size limit, not by this
|
|
277
|
+
* schema.
|
|
278
|
+
*/
|
|
279
|
+
const capabilities = zod_1.z.record(zod_1.z.string(), zod_1.z.unknown());
|
|
280
|
+
// =============================================================================
|
|
281
|
+
// Vitals (issue #604) — carried on the heartbeat
|
|
282
|
+
// =============================================================================
|
|
283
|
+
//
|
|
284
|
+
// WHAT A NODE SAYS ABOUT ITS OWN HEALTH, and the file header's argument
|
|
285
|
+
// applies to every field: these numbers come from a machine this deployment
|
|
286
|
+
// may not own, they are stored verbatim (`WorkerNode.lastVitals`, JSONB) and
|
|
287
|
+
// rendered on the admin fleet page. So the shape is CLOSED and every value is
|
|
288
|
+
// BOUNDED:
|
|
289
|
+
//
|
|
290
|
+
// - `.strict()` at both levels, unlike `capabilities` above. Capabilities
|
|
291
|
+
// are an open bag on purpose (the fleet page's business, free to grow);
|
|
292
|
+
// vitals are a CONTRACT the fleet page reads field by field, and an open
|
|
293
|
+
// bag here would be an unbounded JSONB write on a route every node hits
|
|
294
|
+
// every few seconds. A node that learns a new vital needs an API change
|
|
295
|
+
// first, which is the review this surface should get.
|
|
296
|
+
// - Every number is finite and non-negative with an explicit ceiling, so
|
|
297
|
+
// `NaN`/`Infinity`/negative garbage never reaches the row, and a number
|
|
298
|
+
// too large to be true is refused rather than charted.
|
|
299
|
+
// - Every string is short and version-shaped, because the three it carries
|
|
300
|
+
// are version banners rendered as text — never a free-form message.
|
|
301
|
+
// - Every field is optional. A node reports what it can measure (a node
|
|
302
|
+
// without `pg_dump` has no `pgDumpVersion`), and an old node sends no
|
|
303
|
+
// `vitals` key at all, which leaves the stored snapshot untouched.
|
|
304
|
+
//
|
|
305
|
+
// ⚠ THE CEILINGS ARE GENEROUS ON PURPOSE. A vitals value out of range fails
|
|
306
|
+
// the WHOLE heartbeat with a 400, and a node whose heartbeats fail goes stale
|
|
307
|
+
// on the fleet page and is swept offline — a far worse outcome than one odd
|
|
308
|
+
// number. So each ceiling is "physically implausible", not "unusual": disk
|
|
309
|
+
// sizes in particular allow a network filesystem that reports exabytes free
|
|
310
|
+
// (some do), which is why they are not required to be safe integers.
|
|
311
|
+
//
|
|
312
|
+
// REJECTED: a node-supplied timestamp for the snapshot. `lastVitalsAt` is
|
|
313
|
+
// stamped by the SERVER when the heartbeat lands, for the same reason
|
|
314
|
+
// `lastHeartbeatAt` is — a node's clock is one more thing it could get wrong.
|
|
315
|
+
// =============================================================================
|
|
316
|
+
/** Ceiling on a counter: a trillion events is past any node's plausible lifetime. */
|
|
317
|
+
const MAX_VITALS_COUNTER = 1e12;
|
|
318
|
+
/** Ceiling on a process memory figure (RSS, heap): 1 PiB. */
|
|
319
|
+
const MAX_VITALS_MEMORY_BYTES = 2 ** 50;
|
|
320
|
+
/**
|
|
321
|
+
* Ceiling on a filesystem figure: 2^64 bytes. Not an integer check — a
|
|
322
|
+
* `statfs` total past 2^53 arrives as a (still finite) double.
|
|
323
|
+
*/
|
|
324
|
+
const MAX_VITALS_DISK_BYTES = 2 ** 64;
|
|
325
|
+
/** Ceiling on `cpuPercent`: 100% per core, for up to 128 cores. */
|
|
326
|
+
const MAX_VITALS_CPU_PERCENT = 12_800;
|
|
327
|
+
/** Ceiling on event-loop delay: one hour. A loop blocked longer is not sending heartbeats. */
|
|
328
|
+
const MAX_VITALS_EVENT_LOOP_DELAY_MS = 3_600_000;
|
|
329
|
+
/** Ceiling on uptime: ten years. */
|
|
330
|
+
const MAX_VITALS_UPTIME_SECONDS = 10 * 365 * 24 * 60 * 60;
|
|
331
|
+
/** Cap on a reported version banner (`v24.3.0`, `pg_dump (PostgreSQL) 16.4`). */
|
|
332
|
+
const MAX_VITALS_VERSION_LENGTH = 64;
|
|
333
|
+
/**
|
|
334
|
+
* A finite, non-negative number no larger than `max`. (Zod 4's `z.number()`
|
|
335
|
+
* already refuses `NaN` and `Infinity`; JSON cannot carry them anyway.)
|
|
336
|
+
*/
|
|
337
|
+
const boundedNumber = (max) => zod_1.z.number().nonnegative().max(max);
|
|
338
|
+
/**
|
|
339
|
+
* A non-negative integer no larger than `max`. `.int()` comes FIRST: Zod 4's
|
|
340
|
+
* integer check carries its own safe-integer range, and applied after `.max()`
|
|
341
|
+
* it is that range, not ours, that reaches the generated OpenAPI schema.
|
|
342
|
+
*/
|
|
343
|
+
const boundedInt = (max) => zod_1.z.number().int().nonnegative().max(max);
|
|
344
|
+
/** A non-negative integer counter since the node process started. */
|
|
345
|
+
const vitalsCounter = boundedInt(MAX_VITALS_COUNTER);
|
|
346
|
+
/** A short, version-shaped string: letters, digits, spaces and `. + - _ ( ) ~`. */
|
|
347
|
+
const vitalsVersion = zod_1.z
|
|
348
|
+
.string()
|
|
349
|
+
.trim()
|
|
350
|
+
.min(1)
|
|
351
|
+
.max(MAX_VITALS_VERSION_LENGTH)
|
|
352
|
+
.regex(/^[0-9A-Za-z .+\-_()~]+$/, 'Must be a version string');
|
|
353
|
+
/**
|
|
354
|
+
* Cumulative counters since the node process started; reset on restart.
|
|
355
|
+
*
|
|
356
|
+
* @stability experimental
|
|
357
|
+
*/
|
|
358
|
+
exports.nodeVitalsCountersSchema = zod_1.z
|
|
359
|
+
.object({
|
|
360
|
+
/** Claim calls that returned at least one job. */
|
|
361
|
+
claims: vitalsCounter.optional(),
|
|
362
|
+
/** Claim calls that returned none. */
|
|
363
|
+
emptyPolls: vitalsCounter.optional(),
|
|
364
|
+
/** Claim calls that failed. */
|
|
365
|
+
claimFailures: vitalsCounter.optional(),
|
|
366
|
+
/** Jobs this process completed. */
|
|
367
|
+
succeeded: vitalsCounter.optional(),
|
|
368
|
+
/** Jobs this process reported failed. */
|
|
369
|
+
failed: vitalsCounter.optional(),
|
|
370
|
+
/** Jobs this process reported rate-limited. */
|
|
371
|
+
rateLimited: vitalsCounter.optional(),
|
|
372
|
+
/** Lease renewals that succeeded. */
|
|
373
|
+
leaseRenewals: vitalsCounter.optional(),
|
|
374
|
+
/** Lease renewals that failed. */
|
|
375
|
+
leaseRenewFailures: vitalsCounter.optional(),
|
|
376
|
+
/** Heartbeats that failed. */
|
|
377
|
+
heartbeatFailures: vitalsCounter.optional(),
|
|
378
|
+
/** Times the job watchdog killed a stuck job. */
|
|
379
|
+
watchdogTrips: vitalsCounter.optional(),
|
|
380
|
+
})
|
|
381
|
+
.strict();
|
|
382
|
+
/**
|
|
383
|
+
* App-defined numeric vitals: a bounded bag of `key -> number` an executor or
|
|
384
|
+
* the node's app reports beyond the closed fields (a transcoder's frames per
|
|
385
|
+
* second, a GPU's temperature). Still CLOSED IN SHAPE: at most
|
|
386
|
+
* {@link MAX_NODE_VITALS_EXTRA_KEYS} keys, each key matching
|
|
387
|
+
* {@link NODE_VITALS_EXTRA_KEY_PATTERN}, each value a finite number within
|
|
388
|
+
* +/-{@link MAX_NODE_VITALS_EXTRA_VALUE}. No strings, no nesting, so it stays
|
|
389
|
+
* the unbounded-JSONB-write-free surface the closed fields are. The CLI drops
|
|
390
|
+
* what would not pass before sending (a heartbeat the server refuses costs the
|
|
391
|
+
* node its liveness signal), and the fleet page labels a key through
|
|
392
|
+
* `registerNodeVital`.
|
|
393
|
+
*
|
|
394
|
+
* @stability experimental
|
|
395
|
+
*/
|
|
396
|
+
exports.nodeVitalsExtraSchema = zod_1.z
|
|
397
|
+
.record(zod_1.z.string().regex(constants_js_1.NODE_VITALS_EXTRA_KEY_PATTERN, 'Must be a vital key'), zod_1.z.number().min(-constants_js_1.MAX_NODE_VITALS_EXTRA_VALUE).max(constants_js_1.MAX_NODE_VITALS_EXTRA_VALUE))
|
|
398
|
+
.refine((extra) => Object.keys(extra).length <= constants_js_1.MAX_NODE_VITALS_EXTRA_KEYS, {
|
|
399
|
+
message: `At most ${constants_js_1.MAX_NODE_VITALS_EXTRA_KEYS} extra vitals`,
|
|
400
|
+
});
|
|
401
|
+
/**
|
|
402
|
+
* A node's health snapshot, carried on its heartbeat; closed and bounded.
|
|
403
|
+
*
|
|
404
|
+
* @stability experimental
|
|
405
|
+
*/
|
|
406
|
+
exports.nodeVitalsSchema = zod_1.z
|
|
407
|
+
.object({
|
|
408
|
+
/** Process CPU over the last interval; 100 = one full core. */
|
|
409
|
+
cpuPercent: boundedNumber(MAX_VITALS_CPU_PERCENT).optional(),
|
|
410
|
+
/** Resident set size of the node process, in bytes. */
|
|
411
|
+
rssBytes: boundedInt(MAX_VITALS_MEMORY_BYTES).optional(),
|
|
412
|
+
/** V8 heap in use, in bytes. */
|
|
413
|
+
heapUsedBytes: boundedInt(MAX_VITALS_MEMORY_BYTES).optional(),
|
|
414
|
+
/** V8 heap limit, in bytes. */
|
|
415
|
+
heapLimitBytes: boundedInt(MAX_VITALS_MEMORY_BYTES).optional(),
|
|
416
|
+
/** p99 event-loop delay over the last interval, in milliseconds. */
|
|
417
|
+
eventLoopDelayP99Ms: boundedNumber(MAX_VITALS_EVENT_LOOP_DELAY_MS).optional(),
|
|
418
|
+
/** Free/total bytes on the filesystem holding the node's state directory. */
|
|
419
|
+
stateDirFreeBytes: boundedNumber(MAX_VITALS_DISK_BYTES).optional(),
|
|
420
|
+
/** Total bytes of that filesystem. */
|
|
421
|
+
stateDirTotalBytes: boundedNumber(MAX_VITALS_DISK_BYTES).optional(),
|
|
422
|
+
/** Job slots in use / available. Bounded by the same ceiling as `concurrency`. */
|
|
423
|
+
slotsUsed: boundedInt(constants_js_1.MAX_NODE_CONCURRENCY).optional(),
|
|
424
|
+
/** Job slots available. */
|
|
425
|
+
slotsTotal: boundedInt(constants_js_1.MAX_NODE_CONCURRENCY).optional(),
|
|
426
|
+
/** Seconds since the node process started. */
|
|
427
|
+
uptimeSeconds: boundedNumber(MAX_VITALS_UPTIME_SECONDS).optional(),
|
|
428
|
+
/** Cumulative counters since the process started. */
|
|
429
|
+
counters: exports.nodeVitalsCountersSchema.optional(),
|
|
430
|
+
/** The node CLI's version. */
|
|
431
|
+
cliVersion: vitalsVersion.optional(),
|
|
432
|
+
/** The Node.js runtime version. */
|
|
433
|
+
nodeVersion: vitalsVersion.optional(),
|
|
434
|
+
/** The `pg_dump` version banner, when the node has one. */
|
|
435
|
+
pgDumpVersion: vitalsVersion.optional(),
|
|
436
|
+
/** App-defined numeric vitals; see {@link nodeVitalsExtraSchema}. */
|
|
437
|
+
extra: exports.nodeVitalsExtraSchema.optional(),
|
|
438
|
+
})
|
|
439
|
+
.strict();
|
|
440
|
+
// =============================================================================
|
|
441
|
+
// POST /nodes/register
|
|
442
|
+
// =============================================================================
|
|
443
|
+
/**
|
|
444
|
+
* The body of `POST /api/nodes/register`.
|
|
445
|
+
*
|
|
446
|
+
* @stability experimental
|
|
447
|
+
*/
|
|
448
|
+
exports.registerNodeSchema = zod_1.z.object({
|
|
449
|
+
/**
|
|
450
|
+
* THE IDENTITY HALF OF `@@unique([createdById, name])`. Two registrations
|
|
451
|
+
* with the same name from the same owner are the SAME node — see
|
|
452
|
+
* `NodesService.register`. This is why a node's name belongs in its config
|
|
453
|
+
* file rather than being generated at startup: a generated name makes every
|
|
454
|
+
* container restart a new node row.
|
|
455
|
+
*/
|
|
456
|
+
name: zod_1.z.string().trim().min(1, 'Name is required').max(constants_js_1.MAX_NODE_CREDENTIAL_NAME_LENGTH, 'Name must be 100 characters or less'),
|
|
457
|
+
/** The machine's hostname, as the node reports it. */
|
|
458
|
+
hostname: zod_1.z.string().trim().min(1).max(255),
|
|
459
|
+
/** The OS and architecture (`linux-x64`). */
|
|
460
|
+
platform: zod_1.z.string().trim().min(1).max(100),
|
|
461
|
+
/** The node CLI's version. */
|
|
462
|
+
cliVersion: zod_1.z.string().trim().min(1).max(50),
|
|
463
|
+
/**
|
|
464
|
+
* The job types this node can run. An EMPTY LIST IS LEGAL and means "I can
|
|
465
|
+
* run nothing yet" — a node that registers before its handlers are
|
|
466
|
+
* configured is a real state, and refusing it would push the operator
|
|
467
|
+
* toward declaring a type the node cannot actually execute.
|
|
468
|
+
*/
|
|
469
|
+
eligibleTypes: zod_1.z.array(jobType).max(constants_js_1.MAX_NODE_ELIGIBLE_TYPES).default([]),
|
|
470
|
+
/** How many jobs the node runs at once, 1 to `MAX_NODE_CONCURRENCY`. */
|
|
471
|
+
concurrency: zod_1.z
|
|
472
|
+
.number()
|
|
473
|
+
.int('Concurrency must be a whole number')
|
|
474
|
+
.min(1, 'Concurrency must be at least 1')
|
|
475
|
+
.max(constants_js_1.MAX_NODE_CONCURRENCY, `Concurrency must be at most ${constants_js_1.MAX_NODE_CONCURRENCY}`),
|
|
476
|
+
/** The node's self-reported capability bag (open JSON, shown on the fleet page). */
|
|
477
|
+
capabilities: capabilities.optional(),
|
|
478
|
+
});
|
|
479
|
+
// =============================================================================
|
|
480
|
+
// POST /nodes/:id/heartbeat
|
|
481
|
+
// =============================================================================
|
|
482
|
+
/**
|
|
483
|
+
* The body of `POST /api/nodes/:id/heartbeat`.
|
|
484
|
+
*
|
|
485
|
+
* @stability experimental
|
|
486
|
+
*/
|
|
487
|
+
exports.heartbeatNodeSchema = zod_1.z.object({
|
|
488
|
+
/**
|
|
489
|
+
* The two states a node may report ABOUT ITSELF. `draining` and `disabled`
|
|
490
|
+
* are absent on purpose — see the file header.
|
|
491
|
+
*/
|
|
492
|
+
status: zod_1.z.enum(['online', 'offline']).optional(),
|
|
493
|
+
/**
|
|
494
|
+
* A runtime concurrency change (`appctl node set-concurrency`), which the
|
|
495
|
+
* NEXT claim reads live off the row. This is the whole reason the claim
|
|
496
|
+
* endpoint re-reads the node rather than trusting a value captured at
|
|
497
|
+
* registration.
|
|
498
|
+
*/
|
|
499
|
+
concurrency: zod_1.z.number().int().min(1).max(constants_js_1.MAX_NODE_CONCURRENCY).optional(),
|
|
500
|
+
/** A replacement capability bag, when it changed. */
|
|
501
|
+
capabilities: capabilities.optional(),
|
|
502
|
+
/**
|
|
503
|
+
* A health snapshot (#604), stored as `lastVitals` with a server-stamped
|
|
504
|
+
* `lastVitalsAt`. OMITTED leaves the stored snapshot untouched, which is
|
|
505
|
+
* what every node that predates vitals sends. See "Vitals" above.
|
|
506
|
+
*/
|
|
507
|
+
vitals: exports.nodeVitalsSchema.optional(),
|
|
508
|
+
});
|
|
509
|
+
// =============================================================================
|
|
510
|
+
// POST /nodes/:id/claim
|
|
511
|
+
// =============================================================================
|
|
512
|
+
/**
|
|
513
|
+
* The body of `POST /api/nodes/:id/claim`.
|
|
514
|
+
*
|
|
515
|
+
* @stability experimental
|
|
516
|
+
*/
|
|
517
|
+
exports.claimJobsSchema = zod_1.z.object({
|
|
518
|
+
/**
|
|
519
|
+
* Which of the node's own types it wants right now — a node with free
|
|
520
|
+
* slots for one type and none for another. OMITTED means "anything I
|
|
521
|
+
* declared", which is the common case.
|
|
522
|
+
*
|
|
523
|
+
* NARROWING ONLY. `NodesService.claimJobs` intersects this with the row's
|
|
524
|
+
* `eligibleTypes`; a type here that the node never registered is dropped,
|
|
525
|
+
* not honoured.
|
|
526
|
+
*/
|
|
527
|
+
types: zod_1.z.array(jobType).max(constants_js_1.MAX_NODE_ELIGIBLE_TYPES).optional(),
|
|
528
|
+
/**
|
|
529
|
+
* How many rows to take. CLAMPED DOWN to the node's declared
|
|
530
|
+
* `concurrency`; a larger number is not an error, it is simply capped —
|
|
531
|
+
* a node asking for more than it declared is describing free slots it does
|
|
532
|
+
* not have, and refusing the whole call would stall a fleet over an
|
|
533
|
+
* arithmetic disagreement.
|
|
534
|
+
*/
|
|
535
|
+
limit: zod_1.z.number().int().min(1).max(constants_js_1.MAX_NODE_CONCURRENCY).optional(),
|
|
536
|
+
});
|
|
537
|
+
// =============================================================================
|
|
538
|
+
// POST /nodes/:id/jobs/:jobId/renew
|
|
539
|
+
// =============================================================================
|
|
540
|
+
/**
|
|
541
|
+
* ⚠ THIS BODY EXISTS TO CARRY ONE OPTIONAL FIELD, AND IT MUST SURVIVE HAVING
|
|
542
|
+
* NO BODY AT ALL (#364).
|
|
543
|
+
*
|
|
544
|
+
* Until this change the renew route took no body, so every node in every fleet
|
|
545
|
+
* posts to it with no payload and no `Content-Type` — Fastify hands Nest
|
|
546
|
+
* `undefined`, and a bare `z.object({...})` would reject that outright and
|
|
547
|
+
* fail every renewal from every node that has not been upgraded yet. `.default({})`
|
|
548
|
+
* is what makes "no body" parse to "no assertion", which is the pre-#364
|
|
549
|
+
* behaviour spelled as data. It is the only reason this is a `ZodDefault` and
|
|
550
|
+
* not a plain object schema; do not unwrap it.
|
|
551
|
+
*
|
|
552
|
+
* REJECTED: coercing a `null` body to `{}` as well. That would quietly turn
|
|
553
|
+
* "I assert this row has no token" into "I assert nothing", and those are
|
|
554
|
+
* different statements at the `where` clause (see `claimToken` above).
|
|
555
|
+
*
|
|
556
|
+
* @stability experimental
|
|
557
|
+
*/
|
|
558
|
+
exports.renewLeaseSchema = zod_1.z
|
|
559
|
+
.object({
|
|
560
|
+
/** Which claim of the job is asking (`claimTokenField`). */
|
|
561
|
+
claimToken: claimToken.optional(),
|
|
562
|
+
})
|
|
563
|
+
.default({});
|
|
564
|
+
// =============================================================================
|
|
565
|
+
// POST /nodes/:id/jobs/:jobId/result
|
|
566
|
+
// =============================================================================
|
|
567
|
+
/**
|
|
568
|
+
* The body of `POST /api/nodes/:id/jobs/:jobId/result`.
|
|
569
|
+
*
|
|
570
|
+
* @stability experimental
|
|
571
|
+
*/
|
|
572
|
+
exports.nodeJobResultSchema = zod_1.z.object({
|
|
573
|
+
/**
|
|
574
|
+
* The job type this result is FOR, checked against the row's own `type`
|
|
575
|
+
* before anything is parsed or persisted.
|
|
576
|
+
*
|
|
577
|
+
* It is redundant with the row — which is the point. A node holding two
|
|
578
|
+
* jobs at once and crossing their ids would otherwise post job A's result
|
|
579
|
+
* against job B, and the only thing standing between that and a persisted,
|
|
580
|
+
* plausible, permanently wrong row would be whether B's schema happened to
|
|
581
|
+
* reject A's payload. Two IDs agreeing is a coincidence; an id and a type
|
|
582
|
+
* agreeing is a statement.
|
|
583
|
+
*/
|
|
584
|
+
type: jobType,
|
|
585
|
+
/**
|
|
586
|
+
* The computed result, UNVALIDATED at this layer on purpose.
|
|
587
|
+
*
|
|
588
|
+
* The real validation is `handler.nodeResultSchema`, resolved per job type
|
|
589
|
+
* at runtime and applied manually in `NodesService.submitResult` — the
|
|
590
|
+
* global Zod pipe cannot do it, because which schema applies is not known
|
|
591
|
+
* until the job row has been read. Typing it `unknown` here rather than
|
|
592
|
+
* `Record<string, unknown>` also keeps a handler free to accept a bare
|
|
593
|
+
* array or scalar result if that is what its work produces.
|
|
594
|
+
*/
|
|
595
|
+
result: zod_1.z.unknown(),
|
|
596
|
+
/**
|
|
597
|
+
* WHICH CLAIM computed this result — see `claimToken` above.
|
|
598
|
+
*
|
|
599
|
+
* It matters MORE here than on renew, not less: a stale slot's renewal only
|
|
600
|
+
* delays the reaper, while a stale slot's RESULT settles a job its own later
|
|
601
|
+
* claim is still running, persisting output computed against an earlier
|
|
602
|
+
* attempt over a newer run. Optional for the same rolling-upgrade reason.
|
|
603
|
+
*/
|
|
604
|
+
claimToken: claimToken.optional(),
|
|
605
|
+
});
|
|
606
|
+
// =============================================================================
|
|
607
|
+
// POST /nodes/:id/jobs/:jobId/failure
|
|
608
|
+
// =============================================================================
|
|
609
|
+
/**
|
|
610
|
+
* The body of `POST /api/nodes/:id/jobs/:jobId/failure`.
|
|
611
|
+
*
|
|
612
|
+
* @stability experimental
|
|
613
|
+
*/
|
|
614
|
+
exports.nodeJobFailureSchema = zod_1.z.object({
|
|
615
|
+
/** What went wrong, in the words that will appear in `Job.lastError`. */
|
|
616
|
+
error: zod_1.z.string().trim().min(1, 'An error message is required').max(MAX_ERROR_LENGTH),
|
|
617
|
+
/**
|
|
618
|
+
* "A provider throttled me." Treated IDENTICALLY to a `RateLimitError`
|
|
619
|
+
* thrown by an in-process handler — see `job-terminal.service.ts`'s header
|
|
620
|
+
* on why a flag and a throw must reach the same conclusion.
|
|
621
|
+
*/
|
|
622
|
+
rateLimited: zod_1.z.boolean().optional(),
|
|
623
|
+
/** A provider-requested delay in milliseconds; a FLOOR on the backoff, not an override. */
|
|
624
|
+
retryAfterMs: zod_1.z
|
|
625
|
+
.number()
|
|
626
|
+
.int()
|
|
627
|
+
.min(0)
|
|
628
|
+
// One day. Past this, a "retry after" is a bug in whatever produced it,
|
|
629
|
+
// and honouring it would park a job for longer than most deployments
|
|
630
|
+
// keep their history.
|
|
631
|
+
.max(86_400_000)
|
|
632
|
+
.optional(),
|
|
633
|
+
/**
|
|
634
|
+
* ADVISORY ONLY, and accepted only so a node can say what it believes.
|
|
635
|
+
* The server's attempt budget decides; see the file header.
|
|
636
|
+
*/
|
|
637
|
+
willRetry: zod_1.z.boolean().optional(),
|
|
638
|
+
/**
|
|
639
|
+
* WHICH CLAIM failed — see `claimToken` above.
|
|
640
|
+
*
|
|
641
|
+
* Threaded here as well as on `result` because a failure is just as terminal:
|
|
642
|
+
* an old slot reporting "boom" settles the row (or charges an attempt against
|
|
643
|
+
* it) while a newer claim of the same job is still running fine. Optional for
|
|
644
|
+
* the same rolling-upgrade reason.
|
|
645
|
+
*/
|
|
646
|
+
claimToken: claimToken.optional(),
|
|
647
|
+
});
|
|
648
|
+
// -----------------------------------------------------------------------------
|
|
649
|
+
// From node-data-plane.dto.ts: The data plane's request and response bodies (issue #269, epic #254)
|
|
650
|
+
// -----------------------------------------------------------------------------
|
|
651
|
+
// =============================================================================
|
|
652
|
+
// The data plane's request and response bodies (issue #269, epic #254)
|
|
653
|
+
// =============================================================================
|
|
654
|
+
//
|
|
655
|
+
// #268 gave a node a CONTROL plane: claim a job, renew its lease, report an
|
|
656
|
+
// outcome. What it could not do was read a single byte or write one, because
|
|
657
|
+
// a node holds no storage credentials — by design, and permanently. These
|
|
658
|
+
// bodies are the whole of the answer.
|
|
659
|
+
//
|
|
660
|
+
// -----------------------------------------------------------------------------
|
|
661
|
+
// THE SHAPE OF THE SOLUTION, AND THE TWO ALTERNATIVES IT BEATS
|
|
662
|
+
// -----------------------------------------------------------------------------
|
|
663
|
+
//
|
|
664
|
+
// The server mints a SHORT-LIVED, SINGLE-OBJECT signed URL and the node talks
|
|
665
|
+
// to the storage provider directly. Bytes never pass through the API.
|
|
666
|
+
//
|
|
667
|
+
// REJECTED: PROXYING BYTES THROUGH THE API (`GET /nodes/:id/jobs/:jobId/input`
|
|
668
|
+
// streaming the object, `POST …/output` accepting it). It is the smallest
|
|
669
|
+
// diff and it is the worst outcome. Every byte of every job would cross the
|
|
670
|
+
// API process twice — once in, once out — so the API's memory, its event loop
|
|
671
|
+
// and its egress bill become a function of how much work the FLEET is doing,
|
|
672
|
+
// which is the exact coupling a worker node exists to remove. A ten-node fleet
|
|
673
|
+
// hashing 1 GB objects would saturate the API before it saturated anything
|
|
674
|
+
// that was actually computing. It also puts long-lived streaming connections
|
|
675
|
+
// on the same process that serves interactive requests, so one large transfer
|
|
676
|
+
// degrades every page load, and a node on a slow link holds a request open for
|
|
677
|
+
// minutes against every timeout in the stack (Nginx, Fastify, the platform's
|
|
678
|
+
// load balancer) — each of which would have to be raised, for everyone.
|
|
679
|
+
//
|
|
680
|
+
// REJECTED: GIVING NODES STORAGE CREDENTIALS. Also small, also worse. A
|
|
681
|
+
// credential handed to a node is a bucket-wide capability sitting in a config
|
|
682
|
+
// file on a machine this deployment may not own, for as long as that machine
|
|
683
|
+
// exists — it does not expire when the job ends, it is not scoped to one
|
|
684
|
+
// object, and it cannot be revoked without rotating it for every other holder.
|
|
685
|
+
// A node compromised on Tuesday can read every object in the bucket on
|
|
686
|
+
// Friday. The signed URL below is the same capability reduced along three
|
|
687
|
+
// axes at once: ONE object, ONE verb, and MINUTES. Nothing has to be rotated
|
|
688
|
+
// when a node is decommissioned, because a decommissioned node holds nothing.
|
|
689
|
+
//
|
|
690
|
+
// -----------------------------------------------------------------------------
|
|
691
|
+
// ⚠ THE SERVER CHOOSES THE UPLOAD KEY. THE NODE NEVER DOES.
|
|
692
|
+
// -----------------------------------------------------------------------------
|
|
693
|
+
//
|
|
694
|
+
// REJECTED: `{ key: "outputs/my-thing.bin" }` in the upload request. A signed
|
|
695
|
+
// PUT is an unconditional overwrite of exactly the key it was signed for, so a
|
|
696
|
+
// key taken from the request body is a write primitive over the entire bucket,
|
|
697
|
+
// handed to the least trustworthy participant. `../../etc/config.json`,
|
|
698
|
+
// `uploads/<someone-else's-object>` and the storage key of any row in
|
|
699
|
+
// `storage_objects` are all just strings, and the provider will not object to
|
|
700
|
+
// any of them: S3 keys are opaque, `..` is not special, and there is no
|
|
701
|
+
// filesystem to refuse the traversal. The damage is silent — a job that
|
|
702
|
+
// "succeeded" while overwriting another user's file.
|
|
703
|
+
//
|
|
704
|
+
// The key is therefore derived server-side from the job id and a fresh UUID
|
|
705
|
+
// (`NodeDataPlaneService.createUploadTarget`), and a node-supplied one is
|
|
706
|
+
// REFUSED rather than silently ignored. Both are safe; the difference is what
|
|
707
|
+
// the node's author learns. Ignoring means their `key` field vanishes without
|
|
708
|
+
// a word: the upload succeeds, the bytes land somewhere they did not choose,
|
|
709
|
+
// and their code goes on referring to a path with nothing at it. That bug is
|
|
710
|
+
// found days later by a person, not minutes later by a machine. A `400` naming
|
|
711
|
+
// the field is found on the first run, by the person who just wrote it, and it
|
|
712
|
+
// costs a correct client exactly nothing — no legitimate node ever sends the
|
|
713
|
+
// field.
|
|
714
|
+
// =============================================================================
|
|
715
|
+
/**
|
|
716
|
+
* Cap on a node-declared `Content-Type`.
|
|
717
|
+
*
|
|
718
|
+
* It ends up in a signed header, so it is bounded for the same reason every
|
|
719
|
+
* other node-supplied string in this folder is: it arrives from a machine
|
|
720
|
+
* this deployment may not own.
|
|
721
|
+
*/
|
|
722
|
+
const MAX_CONTENT_TYPE_LENGTH = 255;
|
|
723
|
+
// =============================================================================
|
|
724
|
+
// POST /nodes/:id/jobs/:jobId/download-url
|
|
725
|
+
// =============================================================================
|
|
726
|
+
//
|
|
727
|
+
// ONE FIELD, AND IT IS NOT A REQUEST FOR ANYTHING. This body had none at all
|
|
728
|
+
// until #364, and the distinction that let it acquire one is worth stating,
|
|
729
|
+
// because it is what keeps the next field out: `claimToken` does not ask the
|
|
730
|
+
// server for a different URL, a longer expiry or a different object. It
|
|
731
|
+
// answers "who is asking" — an ASSERTION about which claim of this job the
|
|
732
|
+
// caller is, checked against the row and never used to compute anything. A
|
|
733
|
+
// field that changed what came back would still be refused.
|
|
734
|
+
//
|
|
735
|
+
// So what has NOT changed: the server decides WHICH bytes (the job's
|
|
736
|
+
// `subjectId`, resolved server-side) and FOR HOW LONG. A DTO whose only field
|
|
737
|
+
// was `expiresIn` was considered and dropped for the same reason a
|
|
738
|
+
// node-supplied lease was dropped in #268 — the bound exists to limit the
|
|
739
|
+
// blast radius of a leaked URL, so the party the bound protects against does
|
|
740
|
+
// not get to set it.
|
|
741
|
+
//
|
|
742
|
+
// It is a POST rather than a GET even though it reads nothing, because it
|
|
743
|
+
// MINTS A CREDENTIAL. A GET's URL is the thing every layer between here and
|
|
744
|
+
// the node writes down — proxy access logs, browser history, a CDN cache key,
|
|
745
|
+
// an APM trace's endpoint label — and a response body containing a bearer URL
|
|
746
|
+
// has no business being cacheable by anything. POST is uncacheable by default
|
|
747
|
+
// and carries no such expectation.
|
|
748
|
+
/**
|
|
749
|
+
* What a node may say when asking to read its input: which claim is asking,
|
|
750
|
+
* and nothing else.
|
|
751
|
+
*
|
|
752
|
+
* ⚠ `.default({})` IS THE BACKWARD-COMPATIBILITY GUARANTEE, not a convenience.
|
|
753
|
+
* This route took no body at all until #364, so every node in every fleet
|
|
754
|
+
* posts to it with no payload and no `Content-Type` — Fastify hands Nest
|
|
755
|
+
* `undefined`, and a bare `z.object({...})` would reject that outright and
|
|
756
|
+
* fail every download from every node that has not been upgraded yet. The
|
|
757
|
+
* default is what makes "no body" parse to "no assertion", which is the
|
|
758
|
+
* pre-#364 behaviour spelled as data. Do not unwrap it. `nodeUploadUrlSchema`
|
|
759
|
+
* below and `nodeJobSecretRequestSchema` carry it for the milder version of
|
|
760
|
+
* the same reason — there, an empty body was always legal.
|
|
761
|
+
*
|
|
762
|
+
* A plain object rather than the `z.looseObject` its sibling uses: unknown
|
|
763
|
+
* keys here are stripped, exactly as they were ignored before this body
|
|
764
|
+
* existed. The loose-then-refuse-by-name treatment next door exists for `key`,
|
|
765
|
+
* a field whose silent omission would send a node's bytes somewhere it did not
|
|
766
|
+
* choose; nothing a node can put in THIS body has ever had an effect, so there
|
|
767
|
+
* is no misunderstanding to name.
|
|
768
|
+
*
|
|
769
|
+
* @stability experimental
|
|
770
|
+
*/
|
|
771
|
+
exports.nodeDownloadUrlSchema = zod_1.z
|
|
772
|
+
.object({
|
|
773
|
+
/** Which claim of the job is asking (`claimTokenField`). */
|
|
774
|
+
claimToken: exports.claimTokenField.optional(),
|
|
775
|
+
})
|
|
776
|
+
.default({});
|
|
777
|
+
// =============================================================================
|
|
778
|
+
// POST /nodes/:id/jobs/:jobId/upload-url
|
|
779
|
+
// =============================================================================
|
|
780
|
+
/**
|
|
781
|
+
* What a node may say when asking for somewhere to write.
|
|
782
|
+
*
|
|
783
|
+
* ⚠ `z.looseObject` RATHER THAN `z.strictObject`, AND THE REASON IS THE ERROR
|
|
784
|
+
* MESSAGE. Strict mode rejects an unknown key with a perfectly good Zod issue
|
|
785
|
+
* naming it — and that issue is then DESTROYED on the way out, because
|
|
786
|
+
* `http-exception.filter.ts` rebuilds every error body from a fixed key
|
|
787
|
+
* allowlist (`message`, `code`, `details`) and the validation pipe puts its
|
|
788
|
+
* issues under `errors`. The node would receive a bare
|
|
789
|
+
* `400 "Validation failed"`, which for the one field this endpoint most needs
|
|
790
|
+
* to talk about — `key` — is the least useful answer available.
|
|
791
|
+
*
|
|
792
|
+
* So unknown keys are CAPTURED here and refused in
|
|
793
|
+
* `NodeDataPlaneService.createUploadTarget`, which can raise a
|
|
794
|
+
* `BadRequestException` carrying a message that names the field, explains that
|
|
795
|
+
* the server chooses the key, and survives the filter intact. The security
|
|
796
|
+
* outcome is identical either way (the key is never read); what differs is
|
|
797
|
+
* whether the node's author is told why.
|
|
798
|
+
*
|
|
799
|
+
* `.default({})` so a node with nothing to declare may send an EMPTY BODY
|
|
800
|
+
* rather than being required to send `{}` to satisfy a parser.
|
|
801
|
+
*
|
|
802
|
+
* @stability experimental
|
|
803
|
+
*/
|
|
804
|
+
exports.nodeUploadUrlSchema = zod_1.z
|
|
805
|
+
.looseObject({
|
|
806
|
+
/**
|
|
807
|
+
* The `Content-Type` the node will send on its PUT.
|
|
808
|
+
*
|
|
809
|
+
* ⚠ IT BECOMES PART OF THE SIGNATURE. A node that declares it MUST send
|
|
810
|
+
* exactly this header, or the provider answers `SignatureDoesNotMatch` —
|
|
811
|
+
* an error that names the signature and not the header that broke it. A
|
|
812
|
+
* node that is unsure should omit it and send whatever it likes.
|
|
813
|
+
*/
|
|
814
|
+
contentType: zod_1.z
|
|
815
|
+
.string()
|
|
816
|
+
.trim()
|
|
817
|
+
.min(1)
|
|
818
|
+
.max(MAX_CONTENT_TYPE_LENGTH)
|
|
819
|
+
.optional(),
|
|
820
|
+
/**
|
|
821
|
+
* WHICH CLAIM is asking for somewhere to write — see
|
|
822
|
+
* `claim-token.field.ts`.
|
|
823
|
+
*
|
|
824
|
+
* ⚠ THE SHARPEST OF THE SIX ROUTES THAT CARRY THIS, and the quietest if it
|
|
825
|
+
* is missing. Since #348 a type may derive its output key from the JOB
|
|
826
|
+
* (`deriveOutputKey`), so the key is a function of the row and not of the
|
|
827
|
+
* claim — which means a node's stale worker slot asking here is handed a
|
|
828
|
+
* signed PUT for the EXACT key its own later claim is currently writing.
|
|
829
|
+
* Both PUTs answer 200, the surviving bytes are whichever landed last, and
|
|
830
|
+
* nothing in any log ties the two together. The token is what refuses the
|
|
831
|
+
* first slot before the URL is minted.
|
|
832
|
+
*
|
|
833
|
+
* ⚠ IT IS ALSO A PERMITTED FIELD, which is not automatic here:
|
|
834
|
+
* `NodeDataPlaneService.rejectCallerSuppliedFields` refuses anything
|
|
835
|
+
* outside its allowlist by name, so adding a field to this schema without
|
|
836
|
+
* adding it there would 400 every upgraded node. The allowlist is the
|
|
837
|
+
* authority; this schema only describes.
|
|
838
|
+
*/
|
|
839
|
+
claimToken: exports.claimTokenField.optional(),
|
|
840
|
+
})
|
|
841
|
+
.default({});
|
|
842
|
+
// -----------------------------------------------------------------------------
|
|
843
|
+
// From node-job-secret.dto.ts: The per-job secret request and response bodies (issue #349, epic #345)
|
|
844
|
+
// -----------------------------------------------------------------------------
|
|
845
|
+
// =============================================================================
|
|
846
|
+
// The per-job secret request and response bodies (issue #349, epic #345)
|
|
847
|
+
// =============================================================================
|
|
848
|
+
//
|
|
849
|
+
// #269 gave a node a way to move BYTES with no storage credentials. This gives
|
|
850
|
+
// it a way to hold a CREDENTIAL for exactly one job, for exactly as long as it
|
|
851
|
+
// holds that job's lease. `job-secret-broker.ts` carries the argument for why
|
|
852
|
+
// the credential is brokered per job at all, and what the three rejected
|
|
853
|
+
// alternatives were; this file is about the wire shape, which has two
|
|
854
|
+
// properties worth stating on their own.
|
|
855
|
+
//
|
|
856
|
+
// -----------------------------------------------------------------------------
|
|
857
|
+
// ⚠ THE REQUEST BODY ASKS FOR NOTHING, AND ANY FIELD THAT DOES IS A 400
|
|
858
|
+
// -----------------------------------------------------------------------------
|
|
859
|
+
//
|
|
860
|
+
// Everything the server needs is already on the path (which node) and in the
|
|
861
|
+
// row (which job, which type, which broker, which lease). There is nothing a
|
|
862
|
+
// node could usefully ASK FOR — and, far more importantly, nothing it is
|
|
863
|
+
// ALLOWED to ask for: A NODE MAY NOT REQUEST A SECRET IT WAS NOT ASSIGNED. A
|
|
864
|
+
// `kind`, a `scope`, a `database`, a `ttl` in the body would each be a node
|
|
865
|
+
// choosing some part of a credential's shape, and every one of those is the
|
|
866
|
+
// server's choice derived from the job the node is holding.
|
|
867
|
+
//
|
|
868
|
+
// ⚠ `claimToken` (#364) IS THE ONE PERMITTED FIELD, AND IT IS NOT AN EXCEPTION
|
|
869
|
+
// TO THAT RULE — it is the rule applied to a different question. Every field
|
|
870
|
+
// above asks the server for something; this one ANSWERS something: which claim
|
|
871
|
+
// of this job is asking. It changes nothing about the credential — not its
|
|
872
|
+
// kind, not its scope, not its lifetime, all of which are still derived from
|
|
873
|
+
// the row — and the only thing it can do is get the request REFUSED, which is
|
|
874
|
+
// the whole point. Without it, the ambiguity this route is most exposed to is
|
|
875
|
+
// also its worst: `claimedByNodeId` cannot tell a node's stalled, reaped slot
|
|
876
|
+
// from the slot that re-claimed the job, so the stale one is handed a LIVE
|
|
877
|
+
// DATABASE CREDENTIAL, bounded by a lease belonging to a claim that is not its
|
|
878
|
+
// own. A field that can only ever narrow who may be answered is the one shape
|
|
879
|
+
// of field this body can safely grow.
|
|
880
|
+
//
|
|
881
|
+
// So the refusal is the same one `NodeUploadUrlDto` makes about `key`, applied
|
|
882
|
+
// to a body that permits nothing a node could ask for — including the `ttl`
|
|
883
|
+
// case, which
|
|
884
|
+
// is the one somebody will genuinely want. A node-chosen lifetime is refused
|
|
885
|
+
// for the reason #268 refused a node-chosen lease: the bound exists to limit
|
|
886
|
+
// the blast radius of a leaked credential, so the party the bound protects
|
|
887
|
+
// against does not get to set it. The credential is bounded by the job's lease,
|
|
888
|
+
// which the node is already renewing (#347), and there is deliberately no
|
|
889
|
+
// second clock.
|
|
890
|
+
//
|
|
891
|
+
// `z.looseObject`, NOT `z.strictObject`, and the reason is the error message —
|
|
892
|
+
// the identical reasoning `node-data-plane.dto.ts` records. Strict mode's
|
|
893
|
+
// perfectly good Zod issue is DESTROYED on the way out, because
|
|
894
|
+
// `http-exception.filter.ts` rebuilds every error body from a fixed key
|
|
895
|
+
// allowlist and the validation pipe files its issues under `errors`; the node
|
|
896
|
+
// would receive a bare `400 "Validation failed"` naming nothing. Unknown keys
|
|
897
|
+
// are therefore CAPTURED here and refused in `NodeSecretBrokerService`, which
|
|
898
|
+
// can raise a message that names the field and survives the filter intact. The
|
|
899
|
+
// security outcome is identical either way — no field a node ASKS with is ever
|
|
900
|
+
// read, and the one field that is read (`claimToken`) is declared in the schema
|
|
901
|
+
// rather than swept up as an unknown key — and what differs is whether the
|
|
902
|
+
// node's author is told why.
|
|
903
|
+
//
|
|
904
|
+
// -----------------------------------------------------------------------------
|
|
905
|
+
// POST, NOT GET, AND `Cache-Control: no-store`
|
|
906
|
+
// -----------------------------------------------------------------------------
|
|
907
|
+
//
|
|
908
|
+
// The same reason `worker-nodes.md`, "Data plane", gives for the two data-plane
|
|
909
|
+
// routes, and it applies harder here because what comes back is not a scoped,
|
|
910
|
+
// minutes-long URL but a credential. A `GET`'s URL is what every layer between
|
|
911
|
+
// the server and the node writes down — proxy access logs, a CDN cache key, an
|
|
912
|
+
// APM trace's endpoint label — and a response body containing a credential has
|
|
913
|
+
// no business being cacheable by anything. `POST` is uncacheable by default;
|
|
914
|
+
// `no-store` says so out loud for the intermediary that decides to be clever
|
|
915
|
+
// anyway.
|
|
916
|
+
// =============================================================================
|
|
917
|
+
/**
|
|
918
|
+
* What a node may say when asking for its job's credential: which claim is
|
|
919
|
+
* asking, and nothing else.
|
|
920
|
+
*
|
|
921
|
+
* `.default({})` so a node with nothing to declare may send an empty body
|
|
922
|
+
* rather than being made to send `{}` to satisfy a parser — an empty body is
|
|
923
|
+
* still a correct request, and is what every node sent before #364. Anything
|
|
924
|
+
* beyond `claimToken` is captured by the loose object and refused by name in
|
|
925
|
+
* the service, whose allowlist — not this schema — is the authority on what
|
|
926
|
+
* may be sent; adding a field here without adding it there would 400 the
|
|
927
|
+
* clients that send it.
|
|
928
|
+
*
|
|
929
|
+
* @stability experimental
|
|
930
|
+
*/
|
|
931
|
+
exports.nodeJobSecretRequestSchema = zod_1.z
|
|
932
|
+
.looseObject({
|
|
933
|
+
/** WHICH CLAIM is asking — see `claim-token.field.ts` and the header above. */
|
|
934
|
+
claimToken: exports.claimTokenField.optional(),
|
|
935
|
+
})
|
|
936
|
+
.default({});
|
|
937
|
+
//# sourceMappingURL=schemas.js.map
|