From e6492b7787fa39f8ee5529c8f74091dad564153c Mon Sep 17 00:00:00 2001 From: Tsiry Sandratraina Date: Sun, 3 Dec 2023 08:49:52 +0000 Subject: [PATCH] remove GraphQL, use jsdocs for exported functions --- .fluentci/deno.lock | 27 +- .github/workflows/ci.yml | 2 +- README.md | 56 +- dagger.json | 3 +- deno.lock | 107 +- deps.ts | 47 +- example/.fluentci/dagger.json | 5 +- example/.fluentci/deno.lock | 151 +- example/.fluentci/deps.ts | 47 +- example/.fluentci/sdk/client.gen.ts | 5993 ++++++++++++++++++++++ example/.fluentci/sdk/connect.ts | 89 + example/.fluentci/sdk/utils.ts | 251 + example/.fluentci/src/dagger/jobs.ts | 171 +- example/.fluentci/src/dagger/lib.ts | 13 + example/.fluentci/src/dagger/pipeline.ts | 2 +- example/dagger.json | 3 +- gen/nexus.ts | 162 - schema.graphql | 11 - sdk/client.gen.ts | 5993 ++++++++++++++++++++++ sdk/connect.ts | 89 + sdk/utils.ts | 251 + src/dagger/jobs.ts | 171 +- src/dagger/lib.ts | 13 + src/dagger/pipeline.ts | 2 +- src/dagger/queries.ts | 31 - src/dagger/schema.ts | 67 - 26 files changed, 13206 insertions(+), 551 deletions(-) create mode 100644 example/.fluentci/sdk/client.gen.ts create mode 100644 example/.fluentci/sdk/connect.ts create mode 100644 example/.fluentci/sdk/utils.ts create mode 100644 example/.fluentci/src/dagger/lib.ts delete mode 100644 gen/nexus.ts delete mode 100644 schema.graphql create mode 100644 sdk/client.gen.ts create mode 100644 sdk/connect.ts create mode 100644 sdk/utils.ts create mode 100644 src/dagger/lib.ts delete mode 100644 src/dagger/queries.ts delete mode 100644 src/dagger/schema.ts diff --git a/.fluentci/deno.lock b/.fluentci/deno.lock index 2dbd29d..34de850 100644 --- a/.fluentci/deno.lock +++ b/.fluentci/deno.lock @@ -6,28 +6,9 @@ "https://deno.land/std@0.150.0/media_types/vendor/mime-db.v1.52.0.ts": "724cee25fa40f1a52d3937d6b4fbbfdd7791ff55e1b7ac08d9319d5632c7f5af", "https://deno.land/std@0.191.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", "https://deno.land/x/codecov_pipeline@v0.1.0/src/dagger/jobs.ts": "e980479e0bcd759773286145f3345ce7e1662c7d6734bfc4bbf8e6bfc93b974e", - "https://deno.land/x/fluent_github_actions@v0.2.1/mod.ts": "dc62b622791da77bc27f68e33cba618983a0770a9a12dcc9e0f9a61161bb90e5", - "https://deno.land/x/fluent_github_actions@v0.2.1/src/event.ts": "d44d42356a04aea7ba64ff9e9a12090f477605c27a940bbf80aba612e4e96d1e", - "https://deno.land/x/fluent_github_actions@v0.2.1/src/job_spec.ts": "93aa5b8b79cd8baaf875901322c4c38c27d4458439a831cb0ad86401b207a3dc", - "https://deno.land/x/fluent_github_actions@v0.2.1/src/step_spec.ts": "b399949d1fd9c45873cdda70d82c92e3d9d96ba9a1d5749f3010a1f242b20e35", - "https://deno.land/x/fluent_github_actions@v0.2.1/src/workflow.ts": "c9e3b7b3a59f7edff958eae8f27a8542f2a24889ea27c8aa016d0c0b0ca416c6", - "https://deno.land/x/fluent_github_actions@v0.2.1/src/workflow_spec.ts": "b5c696dc70ee3f777a565197c6a3a379d87d026e12d59942fef5b9dc72124c3a", "https://deno.land/x/nix_installer_pipeline@v0.3.6/src/dagger/steps.ts": "a34aea3753c7079de5877f592ce31f30d05d552155729ff3e695d77326405133", "https://deno.land/x/xhr@0.3.0/mod.ts": "094aacd627fd9635cd942053bf8032b5223b909858fa9dc8ffa583752ff63b20", - "https://deno.land/x/zod@v3.22.1/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea", - "https://deno.land/x/zod@v3.22.1/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.22.1/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.22.1/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.22.1/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.22.1/helpers/parseUtil.ts": "f791e6e65a0340d85ad37d26cd7a3ba67126cd9957eac2b7163162155283abb1", - "https://deno.land/x/zod@v3.22.1/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.22.1/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.22.1/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774", - "https://deno.land/x/zod@v3.22.1/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.22.1/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.22.1/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", - "https://deno.land/x/zod@v3.22.1/types.ts": "4edc1823385f446532c8c9f676d84550c6dc54b17135e34508576647d9612d0e", - "https://esm.sh/stringify-tree@1.1.1": "a0515b0f4fe97a6972047a588b7982592d9079e7aeac3323b0d26448a757cf84", + "https://esm.sh/stringify-tree@1.1.1": "bb68a933167b8d80b88481df0beff172fc9b645db0c32fbe7dc2d822f61ebaea", "https://esm.sh/v128/*@dagger.io/dagger@0.6.3": "cb691a77c0cdaee22f2b8393731b5143c83ce22dbbea204cdbfd203768d15b64", "https://esm.sh/v128/@dagger.io/dagger@0.6.3/X-ZS8q/denonext/dagger.mjs": "fd0901784d75b99615b5409c3654b5c7edfc5ba377c9e1a5a67ffff4f7d3ac32", "https://esm.sh/v128/adm-zip@0.5.10": "d9c54d6d2dd788462781a57d923295bd79304e6fd74b242fd4b30e35b39c5dcf", @@ -81,9 +62,7 @@ "https://esm.sh/v128/web-streams-polyfill@3.2.1/denonext/dist/ponyfill.es2018.js": "a2edb52a93494cda06386b3d6a168016b366e78f02c5eff1f94a0240be12ac96", "https://esm.sh/v128/which@2.0.2/denonext/which.mjs": "86bf76e4937edb7fa3464d7bb9a426ef273684d1cefbec5ba5f1bdcb5cafff91", "https://esm.sh/v128/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", - "https://esm.sh/v132/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", - "https://esm.sh/v132/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "eaa9333a5219638ad170d12e12603ae00ae80fc8bf02cc112cfec7294e6bcb43", - "https://esm.sh/v132/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", - "https://esm.sh/yaml@v2.3.1": "5471fa3592a8a9d1a4a3d8cacf54070b01aedaca82f14fdbbdd056a491db00ec" + "https://esm.sh/v135/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", + "https://esm.sh/v135/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "6cacda15ffe7dc2e1343636549956877e1bd830be5bd56587f40f94ca7becda4" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 88fa889..bffbcdd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,7 +11,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup Fluent CI - uses: fluentci-io/setup-fluentci@v1 + uses: fluentci-io/setup-fluentci@v2 - name: Run Dagger Pipelines run: fluentci run deno_pipeline fmt lint test - name: Upload coverage to Codecov diff --git a/README.md b/README.md index dc9d5e8..11cec7e 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,15 @@ Now you can run the pipeline with: fluentci run . ``` +## Dagger Module + +Use as a [Dagger](https://dagger.io) Module: + +```bash +dagger mod install github.com/fluent-ci-templates/trivy-pipeline@mod +``` + + ## Environment variables | Variable | Description | @@ -46,28 +55,37 @@ fluentci run . | image | Scan a container image | | sbom | Scan a software bill of materials | -```graphql -config(exitCode: Int!, src: String!): String +```typescript +config( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise + +fs( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise -fs(exitCode: Int!, src: String!): String +repo( + src: Directory | string, + exitCode?: number, + repoUrl?: string, + format?: string, + output?: string +): Promise image( - exitCode: Int!, - image: String!, - src: String! -): String + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise + -repo( - exitCode: Int!, - repoUrl: String!, - src: String! -): String - -sbom( - exitCode: Int!, - path: String!, - src: String! -): String ``` ## Programmatic usage @@ -76,5 +94,5 @@ You can also use this pipeline programmatically: ```ts import { fs } from "https://pkg.fluentci.io/trivy_pipeline@v0.2.2/mod.ts"; -await fs(); +await fs("."); ``` diff --git a/dagger.json b/dagger.json index 675fa77..06292be 100644 --- a/dagger.json +++ b/dagger.json @@ -1,5 +1,4 @@ { - "root": "", "name": "trivy", - "sdkRuntime": "tsiry/dagger-sdk-deno" + "sdk": "github.com/fluentci-io/daggerverse/deno-sdk@main" } \ No newline at end of file diff --git a/deno.lock b/deno.lock index 584cbf4..8983d39 100644 --- a/deno.lock +++ b/deno.lock @@ -31,6 +31,8 @@ "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/deps.ts": "096395daebc7ed8a18f0484e4ffcc3a7f70e50946735f7df9611a7fcfd8272cc", "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/mod.ts": "e269d71c72ae68e82c1960e5db2a0c7419c97c9683ef717de0ab75d90f364713", "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/src/tar.ts": "9b02eaaa784b225ad7a23d2769cd492adf113ea7c11c02e3646849e98f4ae43b", + "https://cdn.skypack.dev/-/lodash@v4.17.21-K6GEbP02mWFnLA45zAmi/dist=es2019,mode=imports/optimized/lodash.js": "10c4df47937ffc78548d136dd535a021df5f57182a653260d715c0690dd22978", + "https://cdn.skypack.dev/lodash": "8280de0b3efd87f06ea0eb330d15b8de32c059556023b8c6524e9eb9e4844dc0", "https://deno.land/std@0.129.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", "https://deno.land/std@0.129.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617", "https://deno.land/std@0.129.0/archive/tar.ts": "35ea1baddec7988cc4034765a2cee7613bc8074bd40940d3f5e98f63070a716a", @@ -149,6 +151,9 @@ "https://deno.land/std@0.203.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", "https://deno.land/std@0.203.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", "https://deno.land/std@0.203.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", + "https://deno.land/std@0.205.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.205.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.205.0/flags/mod.ts": "0948466fc437f017f00c0b972a422b3dc3317a790bcf326429d23182977eaf9f", "https://deno.land/std@0.52.0/fmt/colors.ts": "ec9d653672a9a3c7b6eafe53c5bc797364a2db2dcf766ab649c1155fea7a80b2", "https://deno.land/x/crc32@v0.2.0/mod.ts": "de7a3fa2d4ef24b96fc21e1cc4d2d65d1d2b1dcea92f63960e3e11bfa82df0fa", "https://deno.land/x/fluent_aws_codepipeline@v0.2.3/mod.ts": "79cc758901d20a3573d7e3cc2db9f0a5fe56833f4d9befcedc072b94d542eec7", @@ -191,10 +196,11 @@ "https://deno.land/x/zod@v3.22.1/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", "https://deno.land/x/zod@v3.22.1/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", "https://deno.land/x/zod@v3.22.1/types.ts": "4edc1823385f446532c8c9f676d84550c6dc54b17135e34508576647d9612d0e", - "https://esm.sh/@dagger.io/dagger@0.8.8": "615a37f0edf04b25a6efefe7ea8c4cb0f801830b5dbe0a57164919e16a3ef6e6", - "https://esm.sh/graphql-tag@2.12.6": "6e93f81d26bddf63270317b4fce53a03747ec5322a26e5b78fb0abd098a1f6ea", - "https://esm.sh/nanoid@4.0.2": "51031602a4d76c7dd62da9439016cdfd6d1121101e489925e4423d88bf8fa0e1", - "https://esm.sh/stringify-tree@1.1.1": "4d0252ece34f52f7f312a6d270ed2714e57e1610f7a7f71c2fdceceb948e87b2", + "https://esm.sh/@dagger.io/dagger@0.8.8": "15f25b274941de6f12d11de78245bf3d0326ba226212bfea57747b0b2a3e6542", + "https://esm.sh/@dagger.io/dagger@0.9.3": "9bd1df6375031727868e2a7aa24e7517d1eba916b49529a412f9a214a0d58992", + "https://esm.sh/graphql-tag@2.12.6": "132ebb1ed959bb4dac146160b0cd0fa678c7b9e6bd04f349bf4cacbfb46d0b53", + "https://esm.sh/nanoid@4.0.2": "eb872595ebf6390181971c3e477d1b0fe7ea8383d9b66ced7d09ac8f9c4cf2c7", + "https://esm.sh/stringify-tree@1.1.1": "bb68a933167b8d80b88481df0beff172fc9b645db0c32fbe7dc2d822f61ebaea", "https://esm.sh/v128/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", "https://esm.sh/v128/graphql-request@6.1.0": "17f00c323eb825811ce14e2b0e88a0c873acb666c382ac963d1edeb03e01f372", "https://esm.sh/v128/graphql-request@6.1.0/denonext/graphql-request.mjs": "0b15f49d44489423ae6f06004725b6d050b6359da4969e6569bd6ad45065bd94", @@ -203,54 +209,63 @@ "https://esm.sh/v128/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", "https://esm.sh/v131/yaml@2.3.1": "1fe2490feb3d9c6d2c71c64dbdbed90acd4164b00628b3c68a311b6731ca38b5", "https://esm.sh/v131/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", - "https://esm.sh/v133/@dagger.io/dagger@0.8.8/denonext/dagger.mjs": "c4bd80a72add877450ef029ab71091f862f02af8ebc7c4c7f5bb6aab1854095f", - "https://esm.sh/v133/adm-zip@0.5.10/denonext/adm-zip.mjs": "9ccca01e6dea77f3c20386125c0eea2a811aa0f9b73243517b747264df8af046", - "https://esm.sh/v133/chownr@2.0.0/denonext/chownr.mjs": "d7282b2612a9f13c62084c76fc72cdfb20503bccce959178b77b6def14d3ffd2", - "https://esm.sh/v133/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", - "https://esm.sh/v133/cross-spawn@7.0.3/denonext/cross-spawn.mjs": "0a698bfa213c75e5d20176a3f2f65870d31cd26745451d5f56c58e08df138118", - "https://esm.sh/v133/env-paths@3.0.0/denonext/env-paths.mjs": "77984a05eb16450087f25060a070ed500ec546719d471143e16d976ca73ca956", - "https://esm.sh/v133/execa@8.0.1/denonext/execa.mjs": "775e244075c8f23a4caf786116722314a5f2839ee135dba7fde444fc67d5e643", - "https://esm.sh/v133/fs-minipass@2.1.0/denonext/fs-minipass.mjs": "de8b7228c151f04326a852ce57655d36bf9171f8efcd212e34ac8bce3fbd84a0", - "https://esm.sh/v133/get-stream@8.0.1/denonext/get-stream.mjs": "b8ab640bf2638c1ae704a217b79e0a56e7a1f97bb48bbe40d723d5ea87eb0ecb", - "https://esm.sh/v133/graphql-request@6.1.0/denonext/graphql-request.mjs": "7206b27d14333f19f8d2aa3615a81f9e3035f4d33b7a9edff44f990e69fe1964", - "https://esm.sh/v133/graphql-tag@2.12.6/denonext/graphql-tag.mjs": "af56d5f8b96e688f433ccca87d8a2bfcf171686e7f7a3b27cde61df816ad8472", - "https://esm.sh/v133/graphql@16.8.1/denonext/graphql.mjs": "585b84022623b931e27a7a8134cd24ec50b33ea12fd18b43254527628a0fddac", - "https://esm.sh/v133/human-signals@5.0.0/denonext/human-signals.mjs": "8d8663d92280b1ed15bb1b1a0a79601e17f6b165335e85f94c40e56129542077", - "https://esm.sh/v133/is-stream@3.0.0/denonext/is-stream.mjs": "5c8b65f2fa051c4b18e88bbae11dac8bba9caf57752577d69bcea86d1f05c5b7", - "https://esm.sh/v133/isexe@2.0.0/denonext/isexe.mjs": "4675d9d53a332f096efd344cb1418dbda8e6f2effc8a5c81edd43cdd56636be7", - "https://esm.sh/v133/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", - "https://esm.sh/v133/merge-stream@2.0.0/denonext/merge-stream.mjs": "2c2af22401c294158d6bff659d157e3d2c028c218cc1bd2246534a45a4c03c61", - "https://esm.sh/v133/mimic-fn@4.0.0/denonext/mimic-fn.mjs": "10bcf0f2f20cbbba0c289ef7bf4d2422639bbc1c36c247be876afd6fe2d67138", - "https://esm.sh/v133/minipass@3.3.6/denonext/minipass.mjs": "195894c7a7f1fb71de48b4a41af182cd3ad0e357cadc0ad9d8b5340cda895cc0", - "https://esm.sh/v133/minipass@5.0.0/denonext/minipass.mjs": "de0e049728f8c387b58c86439eb9d69a16b6a88756a6bc694e2fecbd7fd00401", - "https://esm.sh/v133/minizlib@2.1.2/denonext/minizlib.mjs": "714b5458f010d3f70aebd738dd14f2099d3f33046bef05cef2db4714b828620a", - "https://esm.sh/v133/mkdirp@1.0.4/denonext/mkdirp.mjs": "53abed4328bbe5c844cbc8363ee1b45b4db2bdcdaec770cd1d08e5917af18de3", - "https://esm.sh/v133/nanoid@4.0.2/denonext/nanoid.mjs": "4f26e89bc0867e6a838069435b3d75af305017d87ce5b51c9d6edc680954b52f", - "https://esm.sh/v133/node-color-log@10.0.2/denonext/node-color-log.mjs": "2504391bd0ce1dd4c2bf0ed0b839b8a3ad84c028d9dd17cc58dccd2e14dacfde", - "https://esm.sh/v133/node_fetch.js": "b11355358cf61343a3c30bd5942df60a3586d13e2c979b515164bfe851662798", - "https://esm.sh/v133/npm-run-path@5.1.0/denonext/npm-run-path.mjs": "0b4d70b3aa79c6f5d9b021d5eaceff7029ebc1b0784b00b572ce4869bcd24cb0", - "https://esm.sh/v133/onetime@6.0.0/denonext/onetime.mjs": "88857d05735668f3e431f95626780c156c7698cfa6bc81175d48ddf4402dffe0", - "https://esm.sh/v133/original-fs@1.2.0/denonext/original-fs.mjs": "2b1098818e54d2c6748ff5b0dd9ea5f6a61b4b6d0f63fb625f21773d11cfc667", - "https://esm.sh/v133/path-key@3.1.1/denonext/path-key.mjs": "add83c631278b7df9b33ae84e41142db88bb291295bcc27eb4e77a1cbdfa71d0", - "https://esm.sh/v133/path-key@4.0.0/denonext/path-key.mjs": "2c2e3922bd0e6e414fa2752ff800bdc6b9208035ce797fa22e49b859f8259417", - "https://esm.sh/v133/shebang-command@2.0.0/denonext/shebang-command.mjs": "23d8e6099e8d3927b5ea0e396d3da92e082dfa32f27d36df9e892a8653b08437", - "https://esm.sh/v133/shebang-regex@3.0.0/denonext/shebang-regex.mjs": "03983ba59dd2cba9402935e21b46d05f5249364cba9f5757aef23c6c2fea65b9", - "https://esm.sh/v133/signal-exit@4.1.0/denonext/signal-exit.mjs": "c450b9024df3b59ded71e7b52aada1ac4b3856aad93e9d64bbc6ea3cdd181824", - "https://esm.sh/v133/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "7640f153ff571180467c1087934154aa2a96acba9e17d5782daeb6e1f6b45759", - "https://esm.sh/v133/strip-final-newline@3.0.0/denonext/strip-final-newline.mjs": "03d9be4e8a249d63cbbddeb2fb675a1bbbcb335283e604d4ce56c88c90e6f102", - "https://esm.sh/v133/tar@6.2.0/denonext/tar.mjs": "e13b28512d8a017442db9665e2c4bf7f134c1b74deb96ba5fd07e5ec6c905617", - "https://esm.sh/v133/tslib@2.6.2/denonext/tslib.mjs": "29782bcd3139f77ec063dc5a9385c0fff4a8d0a23b6765c73d9edeb169a04bf1", - "https://esm.sh/v133/which@2.0.2/denonext/which.mjs": "15c7fcc13cfe719c1854f470278518f158f85fa040aeb0f02ef40676c25f26c0", - "https://esm.sh/v133/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", - "https://esm.sh/v133/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", - "https://esm.sh/yaml@v2.3.1": "1eebb55f799726dfa0698314b3ba178bc478cba64b31c8309284899c96f8ff8f", + "https://esm.sh/v135/@dagger.io/dagger@0.8.8/denonext/dagger.mjs": "417c7cc5b660567bf8cfbac1edc7192ff7c1325abe152611e05fd0bbefc7c010", + "https://esm.sh/v135/@dagger.io/dagger@0.9.3/denonext/dagger.mjs": "998e8e63729621141c0a9b74128db8f81ab7446d1a5d4ff41a6a6b0944db4ddf", + "https://esm.sh/v135/adm-zip@0.5.10/denonext/adm-zip.mjs": "9441de5c60a276046d55945f45775d674a319e8e5fd3a8ab7131d8d192d9abb3", + "https://esm.sh/v135/chownr@2.0.0/denonext/chownr.mjs": "d7282b2612a9f13c62084c76fc72cdfb20503bccce959178b77b6def14d3ffd2", + "https://esm.sh/v135/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", + "https://esm.sh/v135/cross-spawn@7.0.3/denonext/cross-spawn.mjs": "4d5a257de3627fb09c512b23fed30f1b393e29a2c13f8325e89720b8ca6673c1", + "https://esm.sh/v135/env-paths@3.0.0/denonext/env-paths.mjs": "77984a05eb16450087f25060a070ed500ec546719d471143e16d976ca73ca956", + "https://esm.sh/v135/execa@8.0.1/denonext/execa.mjs": "cfcca6be54deae22c8d7c4d8be8df397a9506a54d9af9171519b9eea8daea9a5", + "https://esm.sh/v135/fs-minipass@2.1.0/denonext/fs-minipass.mjs": "4b5b69251541833f5a1035be0e98d46bd6d02843fd7d40720577baf6caca21ce", + "https://esm.sh/v135/get-stream@8.0.1/denonext/get-stream.mjs": "b8ab640bf2638c1ae704a217b79e0a56e7a1f97bb48bbe40d723d5ea87eb0ecb", + "https://esm.sh/v135/graphql-request@6.1.0/denonext/graphql-request.mjs": "c97af0ff1802c36ae6fdf544153140ef4d950bf164f0e5e839e71aa599ea1555", + "https://esm.sh/v135/graphql-tag@2.12.6/denonext/graphql-tag.mjs": "ebaceefc216cba74424ddc55fde9e677f6e5a3e9d556a250faa1b53483574f03", + "https://esm.sh/v135/graphql@16.8.1/denonext/graphql.mjs": "585b84022623b931e27a7a8134cd24ec50b33ea12fd18b43254527628a0fddac", + "https://esm.sh/v135/human-signals@5.0.0/denonext/human-signals.mjs": "ab3130133ac5943273c909d7887e3c16b8374f66d72c38caeea2c44d659af023", + "https://esm.sh/v135/is-stream@3.0.0/denonext/is-stream.mjs": "5c8b65f2fa051c4b18e88bbae11dac8bba9caf57752577d69bcea86d1f05c5b7", + "https://esm.sh/v135/isexe@2.0.0/denonext/isexe.mjs": "4675d9d53a332f096efd344cb1418dbda8e6f2effc8a5c81edd43cdd56636be7", + "https://esm.sh/v135/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", + "https://esm.sh/v135/merge-stream@2.0.0/denonext/merge-stream.mjs": "2c2af22401c294158d6bff659d157e3d2c028c218cc1bd2246534a45a4c03c61", + "https://esm.sh/v135/mimic-fn@4.0.0/denonext/mimic-fn.mjs": "10bcf0f2f20cbbba0c289ef7bf4d2422639bbc1c36c247be876afd6fe2d67138", + "https://esm.sh/v135/minipass@3.3.6/denonext/minipass.mjs": "195894c7a7f1fb71de48b4a41af182cd3ad0e357cadc0ad9d8b5340cda895cc0", + "https://esm.sh/v135/minipass@5.0.0/denonext/minipass.mjs": "de0e049728f8c387b58c86439eb9d69a16b6a88756a6bc694e2fecbd7fd00401", + "https://esm.sh/v135/minizlib@2.1.2/denonext/minizlib.mjs": "67abb7d83dacd0de153cce5d03ee3bfd68988c992306ff843370b68f038b43e0", + "https://esm.sh/v135/mkdirp@1.0.4/denonext/mkdirp.mjs": "41bc43ec9478e772660e2b0edf998f27f0158388c94003b7292d8093e699eb7b", + "https://esm.sh/v135/nanoid@4.0.2/denonext/nanoid.mjs": "4f26e89bc0867e6a838069435b3d75af305017d87ce5b51c9d6edc680954b52f", + "https://esm.sh/v135/node-color-log@10.0.2/denonext/node-color-log.mjs": "2504391bd0ce1dd4c2bf0ed0b839b8a3ad84c028d9dd17cc58dccd2e14dacfde", + "https://esm.sh/v135/node_fetch.js": "b11355358cf61343a3c30bd5942df60a3586d13e2c979b515164bfe851662798", + "https://esm.sh/v135/npm-run-path@5.1.0/denonext/npm-run-path.mjs": "4772cda227b5c18f4293db7edf53998879c75d48e776533009ce1a8daa464bf5", + "https://esm.sh/v135/onetime@6.0.0/denonext/onetime.mjs": "5326fe5207b076a7ebc96740b4c3dcec7a2522a1aa5985e3b4157c1b9cb1e2dd", + "https://esm.sh/v135/original-fs@1.2.0/denonext/original-fs.mjs": "2b1098818e54d2c6748ff5b0dd9ea5f6a61b4b6d0f63fb625f21773d11cfc667", + "https://esm.sh/v135/path-key@3.1.1/denonext/path-key.mjs": "add83c631278b7df9b33ae84e41142db88bb291295bcc27eb4e77a1cbdfa71d0", + "https://esm.sh/v135/path-key@4.0.0/denonext/path-key.mjs": "2c2e3922bd0e6e414fa2752ff800bdc6b9208035ce797fa22e49b859f8259417", + "https://esm.sh/v135/shebang-command@2.0.0/denonext/shebang-command.mjs": "245674cc2dffa2d06fcef0540b81040b626227485e5f41d76e77d386b30b18e0", + "https://esm.sh/v135/shebang-regex@3.0.0/denonext/shebang-regex.mjs": "03983ba59dd2cba9402935e21b46d05f5249364cba9f5757aef23c6c2fea65b9", + "https://esm.sh/v135/signal-exit@4.1.0/denonext/signal-exit.mjs": "c450b9024df3b59ded71e7b52aada1ac4b3856aad93e9d64bbc6ea3cdd181824", + "https://esm.sh/v135/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "6cacda15ffe7dc2e1343636549956877e1bd830be5bd56587f40f94ca7becda4", + "https://esm.sh/v135/strip-final-newline@3.0.0/denonext/strip-final-newline.mjs": "139c0958b1fb9387d8ae5b95941682245a3f3d9ae531f5de9638c2e9109831e0", + "https://esm.sh/v135/tar@6.2.0/denonext/tar.mjs": "e13b56d41286f4935cb29acae60a040148af6e2649326a70e04c5ca6fe5ef04d", + "https://esm.sh/v135/tslib@2.6.2/denonext/tslib.mjs": "29782bcd3139f77ec063dc5a9385c0fff4a8d0a23b6765c73d9edeb169a04bf1", + "https://esm.sh/v135/which@2.0.2/denonext/which.mjs": "360f7d0aa13233975c86f120e2b1aa9695252b16e287ccdc651d3123473a3482", + "https://esm.sh/v135/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", + "https://esm.sh/v135/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", + "https://esm.sh/yaml@v2.3.1": "0b42df3dec58b0999df5639390c02346de67b8dae76717a156189855fb616858", "https://nix.fluentci.io/v0.5.2/deps.ts": "6ccc8510c72998a52c24bc02c848b669413b5ef1d15dccd7e03a25dd0e408564", "https://nix.fluentci.io/v0.5.2/src/dagger/steps.ts": "b766f4fa9624a032e7af884a5ca47bc666a529c4a472d38b74b55ca0d63cf81d", + "https://nix.fluentci.io/v0.5.3/deps.ts": "469c1f084eda8d2ee78135b0bf4f9490b80b36d8d0bdb88594167133a918da8e", + "https://nix.fluentci.io/v0.5.3/src/dagger/steps.ts": "b766f4fa9624a032e7af884a5ca47bc666a529c4a472d38b74b55ca0d63cf81d", "https://sdk.fluentci.io/v0.2.0/deps.ts": "20dd191afaf88662b82c2a42164afe6d06f2e79942f40ce07aa0972719fc858f", "https://sdk.fluentci.io/v0.2.0/mod.ts": "261ba81a4728f5def4e327a5cd80664ea8449515a2f4eea5f3f416acae39a1fa", "https://sdk.fluentci.io/v0.2.0/src/client.ts": "d350d4f59763e32a9b35f3f06f0b1058e5c8e5a3824e6d096cdaf3fc4332dcf6", "https://sdk.fluentci.io/v0.2.0/src/connect.ts": "4aff111c403cf78672384a10214a9885e08319dde579ec458f98a7bb04874101", "https://sdk.fluentci.io/v0.2.0/src/context.ts": "2939ff58d0a79d7377d5553e725c9a2110a0013035a5a57abe9a9a5da975c4ce", - "https://sdk.fluentci.io/v0.2.0/src/utils.ts": "5dcd6d83553930502069d067ff42bc44698e22c23426fdb78630c4b39769d308" + "https://sdk.fluentci.io/v0.2.0/src/utils.ts": "5dcd6d83553930502069d067ff42bc44698e22c23426fdb78630c4b39769d308", + "https://sdk.fluentci.io/v0.3.0/deps.ts": "3a145e76b4345a9a7888f09b1b48cb54523ebfa43247a1abebc40a9e82d555f4", + "https://sdk.fluentci.io/v0.3.0/mod.ts": "261ba81a4728f5def4e327a5cd80664ea8449515a2f4eea5f3f416acae39a1fa", + "https://sdk.fluentci.io/v0.3.0/src/client.ts": "7f1df4b1fee62dd6f946fa9d15d47a37b938ffb4ac91faf3d39b44b83d4f5921", + "https://sdk.fluentci.io/v0.3.0/src/connect.ts": "4aff111c403cf78672384a10214a9885e08319dde579ec458f98a7bb04874101", + "https://sdk.fluentci.io/v0.3.0/src/context.ts": "2939ff58d0a79d7377d5553e725c9a2110a0013035a5a57abe9a9a5da975c4ce", + "https://sdk.fluentci.io/v0.3.0/src/utils.ts": "5dcd6d83553930502069d067ff42bc44698e22c23426fdb78630c4b39769d308" } } diff --git a/deps.ts b/deps.ts index b6da9c3..0601a43 100644 --- a/deps.ts +++ b/deps.ts @@ -1,31 +1,46 @@ export { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; -import Client from "https://sdk.fluentci.io/v0.2.0/mod.ts"; +import { Client } from "./sdk/client.gen.ts"; export default Client; -export { - connect, - uploadContext, - CacheSharingMode, -} from "https://sdk.fluentci.io/v0.2.0/mod.ts"; +export type { DirectoryID, SecretID } from "./sdk/client.gen.ts"; +export { Directory, Secret, File } from "./sdk/client.gen.ts"; +export { connect, uploadContext } from "https://sdk.fluentci.io/v0.3.0/mod.ts"; export { brightGreen } from "https://deno.land/std@0.191.0/fmt/colors.ts"; -export { withDevbox } from "https://nix.fluentci.io/v0.5.2/src/dagger/steps.ts"; +export { withDevbox } from "https://nix.fluentci.io/v0.5.3/src/dagger/steps.ts"; export { stringifyTree } from "https://esm.sh/stringify-tree@1.1.1"; import gql from "https://esm.sh/graphql-tag@2.12.6"; export { gql }; - -export { - arg, - queryType, - stringArg, - intArg, - nonNull, - makeSchema, -} from "npm:nexus"; export { dirname, join, resolve, } from "https://deno.land/std@0.203.0/path/mod.ts"; +export { parse } from "https://deno.land/std@0.205.0/flags/mod.ts"; +export { snakeCase, camelCase } from "https://cdn.skypack.dev/lodash"; + +export { + ClientError, + GraphQLClient, +} from "https://esm.sh/v128/graphql-request@6.1.0"; +export { + DaggerSDKError, + UnknownDaggerError, + DockerImageRefValidationError, + EngineSessionConnectParamsParseError, + ExecError, + GraphQLRequestError, + InitEngineSessionBinaryError, + TooManyNestedObjectsError, + EngineSessionError, + EngineSessionConnectionTimeoutError, + NotAwaitedRequestError, + ERROR_CODES, +} from "https://esm.sh/@dagger.io/dagger@0.9.3"; + +export type { + CallbackFct, + ConnectOpts, +} from "https://sdk.fluentci.io/v0.3.0/mod.ts"; export * as FluentGitlabCI from "https://deno.land/x/fluent_gitlab_ci@v0.4.2/mod.ts"; export * as FluentGithubActions from "https://deno.land/x/fluent_github_actions@v0.2.1/mod.ts"; diff --git a/example/.fluentci/dagger.json b/example/.fluentci/dagger.json index 675fa77..37c1f32 100644 --- a/example/.fluentci/dagger.json +++ b/example/.fluentci/dagger.json @@ -1,5 +1,4 @@ { - "root": "", - "name": "trivy", - "sdkRuntime": "tsiry/dagger-sdk-deno" + "name": "deno", + "sdk": "github.com/fluentci-io/daggerverse/deno-sdk@main" } \ No newline at end of file diff --git a/example/.fluentci/deno.lock b/example/.fluentci/deno.lock index 2d79a93..1a439e8 100644 --- a/example/.fluentci/deno.lock +++ b/example/.fluentci/deno.lock @@ -1,41 +1,11 @@ { "version": "3", - "packages": { - "specifiers": { - "npm:@types/node": "npm:@types/node@18.16.19", - "npm:nexus": "npm:nexus@1.3.0_graphql@16.8.1" - }, - "npm": { - "@types/node@18.16.19": { - "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", - "dependencies": {} - }, - "graphql@16.8.1": { - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", - "dependencies": {} - }, - "iterall@1.3.0": { - "integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==", - "dependencies": {} - }, - "nexus@1.3.0_graphql@16.8.1": { - "integrity": "sha512-w/s19OiNOs0LrtP7pBmD9/FqJHvZLmCipVRt6v1PM8cRUYIbhEswyNKGHVoC4eHZGPSnD+bOf5A3+gnbt0A5/A==", - "dependencies": { - "graphql": "graphql@16.8.1", - "iterall": "iterall@1.3.0", - "tslib": "tslib@2.6.2" - } - }, - "tslib@2.6.2": { - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dependencies": {} - } - } - }, "remote": { "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/deps.ts": "096395daebc7ed8a18f0484e4ffcc3a7f70e50946735f7df9611a7fcfd8272cc", "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/mod.ts": "e269d71c72ae68e82c1960e5db2a0c7419c97c9683ef717de0ab75d90f364713", "https://cdn.jsdelivr.net/gh/tsirysndr/tar@v0.1.1/src/tar.ts": "9b02eaaa784b225ad7a23d2769cd492adf113ea7c11c02e3646849e98f4ae43b", + "https://cdn.skypack.dev/-/lodash@v4.17.21-K6GEbP02mWFnLA45zAmi/dist=es2019,mode=imports/optimized/lodash.js": "10c4df47937ffc78548d136dd535a021df5f57182a653260d715c0690dd22978", + "https://cdn.skypack.dev/lodash": "8280de0b3efd87f06ea0eb330d15b8de32c059556023b8c6524e9eb9e4844dc0", "https://deno.land/std@0.129.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", "https://deno.land/std@0.129.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617", "https://deno.land/std@0.129.0/archive/tar.ts": "35ea1baddec7988cc4034765a2cee7613bc8074bd40940d3f5e98f63070a716a", @@ -154,6 +124,9 @@ "https://deno.land/std@0.203.0/path/to_file_url.ts": "00e6322373dd51ad109956b775e4e72e5f9fa68ce2c6b04e4af2a6eed3825d31", "https://deno.land/std@0.203.0/path/to_namespaced_path.ts": "1b1db3055c343ab389901adfbda34e82b7386bcd1c744d54f9c1496ee0fd0c3d", "https://deno.land/std@0.203.0/path/win32.ts": "8b3f80ef7a462511d5e8020ff490edcaa0a0d118f1b1e9da50e2916bdd73f9dd", + "https://deno.land/std@0.205.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", + "https://deno.land/std@0.205.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", + "https://deno.land/std@0.205.0/flags/mod.ts": "0948466fc437f017f00c0b972a422b3dc3317a790bcf326429d23182977eaf9f", "https://deno.land/std@0.52.0/fmt/colors.ts": "ec9d653672a9a3c7b6eafe53c5bc797364a2db2dcf766ab649c1155fea7a80b2", "https://deno.land/x/crc32@v0.2.0/mod.ts": "de7a3fa2d4ef24b96fc21e1cc4d2d65d1d2b1dcea92f63960e3e11bfa82df0fa", "https://deno.land/x/fluent_aws_codepipeline@v0.2.3/mod.ts": "79cc758901d20a3573d7e3cc2db9f0a5fe56833f4d9befcedc072b94d542eec7", @@ -196,10 +169,10 @@ "https://deno.land/x/zod@v3.22.1/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", "https://deno.land/x/zod@v3.22.1/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", "https://deno.land/x/zod@v3.22.1/types.ts": "4edc1823385f446532c8c9f676d84550c6dc54b17135e34508576647d9612d0e", - "https://esm.sh/@dagger.io/dagger@0.8.4": "424bddc1457c1fc4975c978425730be068b5414e92dca7a64f2d80e2123c4719", - "https://esm.sh/graphql-tag@2.12.6": "2d8f017bc251d9e7346bafc3f3aef4b65f7fdc302c6e0d085e3359f44c893068", - "https://esm.sh/nanoid@4.0.2": "df5af492771eb7ed903cec5e5d8ff721bc75e6c09ddf9fc9263215c8497961f4", - "https://esm.sh/stringify-tree@1.1.1": "a0515b0f4fe97a6972047a588b7982592d9079e7aeac3323b0d26448a757cf84", + "https://esm.sh/@dagger.io/dagger@0.9.3": "9bd1df6375031727868e2a7aa24e7517d1eba916b49529a412f9a214a0d58992", + "https://esm.sh/graphql-tag@2.12.6": "132ebb1ed959bb4dac146160b0cd0fa678c7b9e6bd04f349bf4cacbfb46d0b53", + "https://esm.sh/nanoid@4.0.2": "eb872595ebf6390181971c3e477d1b0fe7ea8383d9b66ced7d09ac8f9c4cf2c7", + "https://esm.sh/stringify-tree@1.1.1": "bb68a933167b8d80b88481df0beff172fc9b645db0c32fbe7dc2d822f61ebaea", "https://esm.sh/v128/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", "https://esm.sh/v128/graphql-request@6.1.0": "17f00c323eb825811ce14e2b0e88a0c873acb666c382ac963d1edeb03e01f372", "https://esm.sh/v128/graphql-request@6.1.0/denonext/graphql-request.mjs": "0b15f49d44489423ae6f06004725b6d050b6359da4969e6569bd6ad45065bd94", @@ -208,62 +181,54 @@ "https://esm.sh/v128/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", "https://esm.sh/v131/yaml@2.3.1": "1fe2490feb3d9c6d2c71c64dbdbed90acd4164b00628b3c68a311b6731ca38b5", "https://esm.sh/v131/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", - "https://esm.sh/v132/@dagger.io/dagger@0.8.4/denonext/dagger.mjs": "a090c18168360a715fcc7ff731cc6cf940e8d08b8a5b18fa80983b47666118a9", - "https://esm.sh/v132/adm-zip@0.5.10/denonext/adm-zip.mjs": "bcdc3b866e0817ac4f1b2a3021dd0a9aafa2c65f1fd254511706b7924fa8b0b7", - "https://esm.sh/v132/chownr@2.0.0/denonext/chownr.mjs": "30b8f17084dfbe475a5052b615f706b06ddd17dca0535103340d485c6b94e952", - "https://esm.sh/v132/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", - "https://esm.sh/v132/cross-spawn@7.0.3/denonext/cross-spawn.mjs": "7c92cdafd952c699fe01eb7a0c29c7cc112c546068ff757cb8832fa110499f11", - "https://esm.sh/v132/env-paths@3.0.0/denonext/env-paths.mjs": "77984a05eb16450087f25060a070ed500ec546719d471143e16d976ca73ca956", - "https://esm.sh/v132/execa@7.2.0/denonext/execa.mjs": "5aa1c5a07843e56fd4ff4e0728d11941122d9f3c4bc37600971aa8e75c86d3a6", - "https://esm.sh/v132/fs-minipass@2.1.0/denonext/fs-minipass.mjs": "18bcb6852f74c79ad50261e900a8c5daf2e7c38ce6662859e4f6f61d18daa6ed", - "https://esm.sh/v132/get-stream@6.0.1/denonext/get-stream.mjs": "a947a16f8cb3052fd654a84f8b36b40ce96b6a5acfb3ad4ab69d814bcf3351fb", - "https://esm.sh/v132/graphql-request@6.1.0/denonext/graphql-request.mjs": "796e05cc81ad339ef182de57452ffc00e9fef874df14fbba41338ca893499733", - "https://esm.sh/v132/graphql-tag@2.12.6/denonext/graphql-tag.mjs": "ca4302aabfeec9e4335103f1a3eeaf26277af50b828a3bcde7f262fcd4e98e1d", - "https://esm.sh/v132/graphql@16.8.0/denonext/graphql.mjs": "e10e0db78cbbef8215b2665e5ed46cbb28fc61ecdb560f9e8d304a610f51f5bc", - "https://esm.sh/v132/human-signals@4.3.1/denonext/human-signals.mjs": "3889110cedd907804443d018cffe0a1d892d5e7467661376caf967feff55cbe9", - "https://esm.sh/v132/is-stream@3.0.0/denonext/is-stream.mjs": "5c8b65f2fa051c4b18e88bbae11dac8bba9caf57752577d69bcea86d1f05c5b7", - "https://esm.sh/v132/isexe@2.0.0/denonext/isexe.mjs": "3cfefd270d1bfdfb864ee98dbb8f41d150cbf480925158f4a8f0ade8a9e17d6c", - "https://esm.sh/v132/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", - "https://esm.sh/v132/merge-stream@2.0.0/denonext/merge-stream.mjs": "2c2af22401c294158d6bff659d157e3d2c028c218cc1bd2246534a45a4c03c61", - "https://esm.sh/v132/mimic-fn@4.0.0/denonext/mimic-fn.mjs": "10bcf0f2f20cbbba0c289ef7bf4d2422639bbc1c36c247be876afd6fe2d67138", - "https://esm.sh/v132/minipass@3.3.6/denonext/minipass.mjs": "59bbe430514455e78cb30c389b21af66efb2bf010cda071820a17d8c76d0d1cf", - "https://esm.sh/v132/minipass@5.0.0/denonext/minipass.mjs": "de0e049728f8c387b58c86439eb9d69a16b6a88756a6bc694e2fecbd7fd00401", - "https://esm.sh/v132/minizlib@2.1.2/denonext/minizlib.mjs": "2e35ea8aa6cb4caa6f9b6c5b3c8684460698c868363e134af26c28d0e76ded5f", - "https://esm.sh/v132/mkdirp@1.0.4/denonext/mkdirp.mjs": "091be31ee8a9c0f5f716b769bf81397ac70a587a5f2b0367e1e3bda26f5a8af7", - "https://esm.sh/v132/nanoid@4.0.2/denonext/nanoid.mjs": "4f26e89bc0867e6a838069435b3d75af305017d87ce5b51c9d6edc680954b52f", - "https://esm.sh/v132/node-color-log@10.0.2/denonext/node-color-log.mjs": "2504391bd0ce1dd4c2bf0ed0b839b8a3ad84c028d9dd17cc58dccd2e14dacfde", - "https://esm.sh/v132/node_fetch.js": "b11355358cf61343a3c30bd5942df60a3586d13e2c979b515164bfe851662798", - "https://esm.sh/v132/npm-run-path@5.1.0/denonext/npm-run-path.mjs": "b97d372a504bcca269c98f5d13ba0671e47230aaaaa36c3554b4a705085044df", - "https://esm.sh/v132/onetime@6.0.0/denonext/onetime.mjs": "c0be3fa6d700bb157f9a710aaf23df049f70c6a7d7e66a7d76568c5177267c51", - "https://esm.sh/v132/original-fs@1.2.0/denonext/original-fs.mjs": "2b1098818e54d2c6748ff5b0dd9ea5f6a61b4b6d0f63fb625f21773d11cfc667", - "https://esm.sh/v132/path-key@3.1.1/denonext/path-key.mjs": "add83c631278b7df9b33ae84e41142db88bb291295bcc27eb4e77a1cbdfa71d0", - "https://esm.sh/v132/path-key@4.0.0/denonext/path-key.mjs": "2c2e3922bd0e6e414fa2752ff800bdc6b9208035ce797fa22e49b859f8259417", - "https://esm.sh/v132/shebang-command@2.0.0/denonext/shebang-command.mjs": "35a3eae8fe5ccaab6598ba16e81bfc06bc1b46128028cd4cf76d63786dcd54aa", - "https://esm.sh/v132/shebang-regex@3.0.0/denonext/shebang-regex.mjs": "03983ba59dd2cba9402935e21b46d05f5249364cba9f5757aef23c6c2fea65b9", - "https://esm.sh/v132/signal-exit@3.0.7/denonext/signal-exit.mjs": "2a176e5f9b351fa8057213c627a1503d63bf308b64447ef47f1ca6fbb2a91c81", - "https://esm.sh/v132/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "eaa9333a5219638ad170d12e12603ae00ae80fc8bf02cc112cfec7294e6bcb43", - "https://esm.sh/v132/strip-final-newline@3.0.0/denonext/strip-final-newline.mjs": "03d9be4e8a249d63cbbddeb2fb675a1bbbcb335283e604d4ce56c88c90e6f102", - "https://esm.sh/v132/tar@6.2.0/denonext/tar.mjs": "f55c2f94c0ba1123048c9e3fa0af3a2bebac3af5a9895610865f05ae4d0b7f58", - "https://esm.sh/v132/tslib@2.6.2/denonext/tslib.mjs": "29782bcd3139f77ec063dc5a9385c0fff4a8d0a23b6765c73d9edeb169a04bf1", - "https://esm.sh/v132/which@2.0.2/denonext/which.mjs": "7482079af785ec16137592b26d53cb2808b05979559f5d0d9d036a80c6b1636e", - "https://esm.sh/v132/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", - "https://esm.sh/v132/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", - "https://esm.sh/yaml@v2.3.1": "5471fa3592a8a9d1a4a3d8cacf54070b01aedaca82f14fdbbdd056a491db00ec", - "https://nix.fluentci.io/v0.5.1/deps.ts": "d2fee07fcb79b609f64f988990ad5d67c7bf17455f75dcbf1b3bbfa5de7c73b2", - "https://nix.fluentci.io/v0.5.1/src/dagger/steps.ts": "b766f4fa9624a032e7af884a5ca47bc666a529c4a472d38b74b55ca0d63cf81d", - "https://nix.fluentci.io/zenith/deps.ts": "a8fd3aa32faea5de2779cc6494471b4fd9588f039d199ff1a1ff1b00343aef26", - "https://nix.fluentci.io/zenith/src/dagger/steps.ts": "b766f4fa9624a032e7af884a5ca47bc666a529c4a472d38b74b55ca0d63cf81d", - "https://sdk.fluentci.io/v0.1.9/deps.ts": "1b036b7614a602b11e062a6911f26a6e2ac4e470cc74ac230125afd466cc77ea", - "https://sdk.fluentci.io/v0.1.9/mod.ts": "a3c03bdb97c5a3b998c7c9f616c7b00d4268013c3b16e8a90c1a36a85529d841", - "https://sdk.fluentci.io/v0.1.9/src/client.ts": "a8dd54861feccd11a53df39b2d45bfb3b2a8a3dff509f5700c41b517d4dff44d", - "https://sdk.fluentci.io/v0.1.9/src/connect.ts": "1bb42b4e0c5073bb2125b90f1d7d08a66fcad9ad8c453924b944be72d3a56c98", - "https://sdk.fluentci.io/v0.1.9/src/context.ts": "2939ff58d0a79d7377d5553e725c9a2110a0013035a5a57abe9a9a5da975c4ce", - "https://sdk.fluentci.io/v0.1.9/src/utils.ts": "394d131cfd465f0f3d8f876237f3bad1ab4dba73b9b7a396ee705d02aee40c16", - "https://sdk.fluentci.io/z1/deps.ts": "1b036b7614a602b11e062a6911f26a6e2ac4e470cc74ac230125afd466cc77ea", - "https://sdk.fluentci.io/z1/mod.ts": "261ba81a4728f5def4e327a5cd80664ea8449515a2f4eea5f3f416acae39a1fa", - "https://sdk.fluentci.io/z1/src/client.ts": "dde6d20c41df43e5bb7763782eb3702a8d830a827444d1fb388fc574b2e6a64c", - "https://sdk.fluentci.io/z1/src/connect.ts": "4aff111c403cf78672384a10214a9885e08319dde579ec458f98a7bb04874101", - "https://sdk.fluentci.io/z1/src/context.ts": "2939ff58d0a79d7377d5553e725c9a2110a0013035a5a57abe9a9a5da975c4ce", - "https://sdk.fluentci.io/z1/src/utils.ts": "5dcd6d83553930502069d067ff42bc44698e22c23426fdb78630c4b39769d308" + "https://esm.sh/v135/@dagger.io/dagger@0.9.3/denonext/dagger.mjs": "998e8e63729621141c0a9b74128db8f81ab7446d1a5d4ff41a6a6b0944db4ddf", + "https://esm.sh/v135/adm-zip@0.5.10/denonext/adm-zip.mjs": "9441de5c60a276046d55945f45775d674a319e8e5fd3a8ab7131d8d192d9abb3", + "https://esm.sh/v135/chownr@2.0.0/denonext/chownr.mjs": "d7282b2612a9f13c62084c76fc72cdfb20503bccce959178b77b6def14d3ffd2", + "https://esm.sh/v135/cross-fetch@3.1.8/denonext/cross-fetch.mjs": "8fba9e7c3fbaf0d2168beb63ce0cd21b5bfbfbd77e2fcbf8d957d533a71222f6", + "https://esm.sh/v135/cross-spawn@7.0.3/denonext/cross-spawn.mjs": "4d5a257de3627fb09c512b23fed30f1b393e29a2c13f8325e89720b8ca6673c1", + "https://esm.sh/v135/env-paths@3.0.0/denonext/env-paths.mjs": "77984a05eb16450087f25060a070ed500ec546719d471143e16d976ca73ca956", + "https://esm.sh/v135/execa@8.0.1/denonext/execa.mjs": "cfcca6be54deae22c8d7c4d8be8df397a9506a54d9af9171519b9eea8daea9a5", + "https://esm.sh/v135/fs-minipass@2.1.0/denonext/fs-minipass.mjs": "4b5b69251541833f5a1035be0e98d46bd6d02843fd7d40720577baf6caca21ce", + "https://esm.sh/v135/get-stream@8.0.1/denonext/get-stream.mjs": "b8ab640bf2638c1ae704a217b79e0a56e7a1f97bb48bbe40d723d5ea87eb0ecb", + "https://esm.sh/v135/graphql-request@6.1.0/denonext/graphql-request.mjs": "c97af0ff1802c36ae6fdf544153140ef4d950bf164f0e5e839e71aa599ea1555", + "https://esm.sh/v135/graphql-tag@2.12.6/denonext/graphql-tag.mjs": "ebaceefc216cba74424ddc55fde9e677f6e5a3e9d556a250faa1b53483574f03", + "https://esm.sh/v135/graphql@16.8.1/denonext/graphql.mjs": "585b84022623b931e27a7a8134cd24ec50b33ea12fd18b43254527628a0fddac", + "https://esm.sh/v135/human-signals@5.0.0/denonext/human-signals.mjs": "ab3130133ac5943273c909d7887e3c16b8374f66d72c38caeea2c44d659af023", + "https://esm.sh/v135/is-stream@3.0.0/denonext/is-stream.mjs": "5c8b65f2fa051c4b18e88bbae11dac8bba9caf57752577d69bcea86d1f05c5b7", + "https://esm.sh/v135/isexe@2.0.0/denonext/isexe.mjs": "4675d9d53a332f096efd344cb1418dbda8e6f2effc8a5c81edd43cdd56636be7", + "https://esm.sh/v135/lodash.flatten@4.4.0/denonext/lodash.flatten.mjs": "8e86ab607deea15cc3c1acfb5eae278ecbc5b80f24167b4e8f4c56df3278cd55", + "https://esm.sh/v135/merge-stream@2.0.0/denonext/merge-stream.mjs": "2c2af22401c294158d6bff659d157e3d2c028c218cc1bd2246534a45a4c03c61", + "https://esm.sh/v135/mimic-fn@4.0.0/denonext/mimic-fn.mjs": "10bcf0f2f20cbbba0c289ef7bf4d2422639bbc1c36c247be876afd6fe2d67138", + "https://esm.sh/v135/minipass@3.3.6/denonext/minipass.mjs": "195894c7a7f1fb71de48b4a41af182cd3ad0e357cadc0ad9d8b5340cda895cc0", + "https://esm.sh/v135/minipass@5.0.0/denonext/minipass.mjs": "de0e049728f8c387b58c86439eb9d69a16b6a88756a6bc694e2fecbd7fd00401", + "https://esm.sh/v135/minizlib@2.1.2/denonext/minizlib.mjs": "67abb7d83dacd0de153cce5d03ee3bfd68988c992306ff843370b68f038b43e0", + "https://esm.sh/v135/mkdirp@1.0.4/denonext/mkdirp.mjs": "41bc43ec9478e772660e2b0edf998f27f0158388c94003b7292d8093e699eb7b", + "https://esm.sh/v135/nanoid@4.0.2/denonext/nanoid.mjs": "4f26e89bc0867e6a838069435b3d75af305017d87ce5b51c9d6edc680954b52f", + "https://esm.sh/v135/node-color-log@10.0.2/denonext/node-color-log.mjs": "2504391bd0ce1dd4c2bf0ed0b839b8a3ad84c028d9dd17cc58dccd2e14dacfde", + "https://esm.sh/v135/node_fetch.js": "b11355358cf61343a3c30bd5942df60a3586d13e2c979b515164bfe851662798", + "https://esm.sh/v135/npm-run-path@5.1.0/denonext/npm-run-path.mjs": "4772cda227b5c18f4293db7edf53998879c75d48e776533009ce1a8daa464bf5", + "https://esm.sh/v135/onetime@6.0.0/denonext/onetime.mjs": "5326fe5207b076a7ebc96740b4c3dcec7a2522a1aa5985e3b4157c1b9cb1e2dd", + "https://esm.sh/v135/original-fs@1.2.0/denonext/original-fs.mjs": "2b1098818e54d2c6748ff5b0dd9ea5f6a61b4b6d0f63fb625f21773d11cfc667", + "https://esm.sh/v135/path-key@3.1.1/denonext/path-key.mjs": "add83c631278b7df9b33ae84e41142db88bb291295bcc27eb4e77a1cbdfa71d0", + "https://esm.sh/v135/path-key@4.0.0/denonext/path-key.mjs": "2c2e3922bd0e6e414fa2752ff800bdc6b9208035ce797fa22e49b859f8259417", + "https://esm.sh/v135/shebang-command@2.0.0/denonext/shebang-command.mjs": "245674cc2dffa2d06fcef0540b81040b626227485e5f41d76e77d386b30b18e0", + "https://esm.sh/v135/shebang-regex@3.0.0/denonext/shebang-regex.mjs": "03983ba59dd2cba9402935e21b46d05f5249364cba9f5757aef23c6c2fea65b9", + "https://esm.sh/v135/signal-exit@4.1.0/denonext/signal-exit.mjs": "c450b9024df3b59ded71e7b52aada1ac4b3856aad93e9d64bbc6ea3cdd181824", + "https://esm.sh/v135/stringify-tree@1.1.1/denonext/stringify-tree.mjs": "6cacda15ffe7dc2e1343636549956877e1bd830be5bd56587f40f94ca7becda4", + "https://esm.sh/v135/strip-final-newline@3.0.0/denonext/strip-final-newline.mjs": "139c0958b1fb9387d8ae5b95941682245a3f3d9ae531f5de9638c2e9109831e0", + "https://esm.sh/v135/tar@6.2.0/denonext/tar.mjs": "e13b56d41286f4935cb29acae60a040148af6e2649326a70e04c5ca6fe5ef04d", + "https://esm.sh/v135/tslib@2.6.2/denonext/tslib.mjs": "29782bcd3139f77ec063dc5a9385c0fff4a8d0a23b6765c73d9edeb169a04bf1", + "https://esm.sh/v135/which@2.0.2/denonext/which.mjs": "360f7d0aa13233975c86f120e2b1aa9695252b16e287ccdc651d3123473a3482", + "https://esm.sh/v135/yallist@4.0.0/denonext/yallist.mjs": "61f180d807dda50bac17028eda05d5722a3fecef6e98a9064e2353ea6864fd82", + "https://esm.sh/v135/yaml@2.3.1/denonext/yaml.mjs": "71f677b4bfc69271af9d98db5194e354f9a1863955e208e26d32a9ef78bd89f5", + "https://esm.sh/yaml@v2.3.1": "0b42df3dec58b0999df5639390c02346de67b8dae76717a156189855fb616858", + "https://nix.fluentci.io/v0.5.3/deps.ts": "469c1f084eda8d2ee78135b0bf4f9490b80b36d8d0bdb88594167133a918da8e", + "https://nix.fluentci.io/v0.5.3/src/dagger/steps.ts": "b766f4fa9624a032e7af884a5ca47bc666a529c4a472d38b74b55ca0d63cf81d", + "https://sdk.fluentci.io/v0.3.0/deps.ts": "3a145e76b4345a9a7888f09b1b48cb54523ebfa43247a1abebc40a9e82d555f4", + "https://sdk.fluentci.io/v0.3.0/mod.ts": "261ba81a4728f5def4e327a5cd80664ea8449515a2f4eea5f3f416acae39a1fa", + "https://sdk.fluentci.io/v0.3.0/src/client.ts": "7f1df4b1fee62dd6f946fa9d15d47a37b938ffb4ac91faf3d39b44b83d4f5921", + "https://sdk.fluentci.io/v0.3.0/src/connect.ts": "4aff111c403cf78672384a10214a9885e08319dde579ec458f98a7bb04874101", + "https://sdk.fluentci.io/v0.3.0/src/context.ts": "2939ff58d0a79d7377d5553e725c9a2110a0013035a5a57abe9a9a5da975c4ce", + "https://sdk.fluentci.io/v0.3.0/src/utils.ts": "5dcd6d83553930502069d067ff42bc44698e22c23426fdb78630c4b39769d308" } } diff --git a/example/.fluentci/deps.ts b/example/.fluentci/deps.ts index 06b55cb..0601a43 100644 --- a/example/.fluentci/deps.ts +++ b/example/.fluentci/deps.ts @@ -1,31 +1,46 @@ export { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; -import Client from "https://sdk.fluentci.io/z1/mod.ts"; +import { Client } from "./sdk/client.gen.ts"; export default Client; -export { - connect, - uploadContext, - CacheSharingMode, -} from "https://sdk.fluentci.io/z1/mod.ts"; +export type { DirectoryID, SecretID } from "./sdk/client.gen.ts"; +export { Directory, Secret, File } from "./sdk/client.gen.ts"; +export { connect, uploadContext } from "https://sdk.fluentci.io/v0.3.0/mod.ts"; export { brightGreen } from "https://deno.land/std@0.191.0/fmt/colors.ts"; -export { withDevbox } from "https://nix.fluentci.io/zenith/src/dagger/steps.ts"; +export { withDevbox } from "https://nix.fluentci.io/v0.5.3/src/dagger/steps.ts"; export { stringifyTree } from "https://esm.sh/stringify-tree@1.1.1"; import gql from "https://esm.sh/graphql-tag@2.12.6"; export { gql }; - -export { - arg, - queryType, - stringArg, - intArg, - nonNull, - makeSchema, -} from "npm:nexus"; export { dirname, join, resolve, } from "https://deno.land/std@0.203.0/path/mod.ts"; +export { parse } from "https://deno.land/std@0.205.0/flags/mod.ts"; +export { snakeCase, camelCase } from "https://cdn.skypack.dev/lodash"; + +export { + ClientError, + GraphQLClient, +} from "https://esm.sh/v128/graphql-request@6.1.0"; +export { + DaggerSDKError, + UnknownDaggerError, + DockerImageRefValidationError, + EngineSessionConnectParamsParseError, + ExecError, + GraphQLRequestError, + InitEngineSessionBinaryError, + TooManyNestedObjectsError, + EngineSessionError, + EngineSessionConnectionTimeoutError, + NotAwaitedRequestError, + ERROR_CODES, +} from "https://esm.sh/@dagger.io/dagger@0.9.3"; + +export type { + CallbackFct, + ConnectOpts, +} from "https://sdk.fluentci.io/v0.3.0/mod.ts"; export * as FluentGitlabCI from "https://deno.land/x/fluent_gitlab_ci@v0.4.2/mod.ts"; export * as FluentGithubActions from "https://deno.land/x/fluent_github_actions@v0.2.1/mod.ts"; diff --git a/example/.fluentci/sdk/client.gen.ts b/example/.fluentci/sdk/client.gen.ts new file mode 100644 index 0000000..d18ad57 --- /dev/null +++ b/example/.fluentci/sdk/client.gen.ts @@ -0,0 +1,5993 @@ +/** + * This file was auto-generated by `client-gen`. + * Do not make direct changes to the file. + */ +import { GraphQLClient } from "../deps.ts" + +import { computeQuery } from "./utils.ts" + +/** + * @hidden + */ +export type QueryTree = { + operation: string + args?: Record +} + +/** + * @hidden + */ +export type Metadata = { + [key: string]: { + is_enum?: boolean + } +} + +interface ClientConfig { + queryTree?: QueryTree[] + host?: string + sessionToken?: string +} + +class BaseClient { + protected _queryTree: QueryTree[] + protected client: GraphQLClient + /** + * @defaultValue `127.0.0.1:8080` + */ + public clientHost: string + public sessionToken: string + + /** + * @hidden + */ + constructor({ queryTree, host, sessionToken }: ClientConfig = {}) { + this._queryTree = queryTree || [] + this.clientHost = host || "127.0.0.1:8080" + this.sessionToken = sessionToken || "" + this.client = new GraphQLClient(`http://${host}/query`, { + headers: { + Authorization: + "Basic " + btoa(sessionToken + ":"), + }, + }) + } + + /** + * @hidden + */ + get queryTree() { + return this._queryTree + } +} + +export type BuildArg = { + /** + * The build argument name. + */ + name: string + + /** + * The build argument value. + */ + value: string +} + +/** + * Sharing mode of the cache volume. + */ +export enum CacheSharingMode { + + /** + * Shares the cache volume amongst many build pipelines, + * but will serialize the writes + */ + Locked = "LOCKED", + + /** + * Keeps a cache volume for a single build pipeline + */ + Private = "PRIVATE", + + /** + * Shares the cache volume amongst many build pipelines + */ + Shared = "SHARED", +} +/** + * A global cache volume identifier. + */ +export type CacheVolumeID = string & {__CacheVolumeID: never} + +export type ContainerAsTarballOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerBuildOpts = { + /** + * Path to the Dockerfile to use. + * + * Default: './Dockerfile'. + */ + dockerfile?: string + + /** + * Additional build arguments. + */ + buildArgs?: BuildArg[] + + /** + * Target build stage to build. + */ + target?: string + + /** + * Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name] in the build container + * + * They can be accessed in the Dockerfile using the "secret" mount type + * and mount path /run/secrets/[secret-name] + * e.g. RUN --mount=type=secret,id=my-secret curl url?token=$(cat /run/secrets/my-secret)" + */ + secrets?: Secret[] +} + +export type ContainerExportOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the exported image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the exported image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerImportOpts = { + /** + * Identifies the tag to import from the archive, if the archive bundles + * multiple tags. + */ + tag?: string +} + +export type ContainerPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type ContainerPublishOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the published image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the published image's layers. Defaults to OCI, which + * is largely compatible with most recent registries, but Docker may be needed for older + * registries without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerWithDefaultArgsOpts = { + /** + * Arguments to prepend to future executions (e.g., ["-v", "--no-cache"]). + */ + args?: string[] +} + +export type ContainerWithDirectoryOpts = { + /** + * Patterns to exclude in the written directory (e.g., ["node_modules/**", ".gitignore", ".git/"]). + */ + exclude?: string[] + + /** + * Patterns to include in the written directory (e.g., ["*.go", "go.mod", "go.sum"]). + */ + include?: string[] + + /** + * A user:group to set for the directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithEnvVariableOpts = { + /** + * Replace ${VAR} or $VAR in the value according to the current environment + * variables defined in the container (e.g., "/opt/bin:$PATH"). + */ + expand?: boolean +} + +export type ContainerWithExecOpts = { + /** + * If the container has an entrypoint, ignore it for args rather than using it to wrap them. + */ + skipEntrypoint?: boolean + + /** + * Content to write to the command's standard input before closing (e.g., "Hello world"). + */ + stdin?: string + + /** + * Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout"). + */ + redirectStdout?: string + + /** + * Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr"). + */ + redirectStderr?: string + + /** + * Provides dagger access to the executed command. + * + * Do not use this option unless you trust the command being executed. + * The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. + */ + experimentalPrivilegedNesting?: boolean + + /** + * Execute the command with all root capabilities. This is similar to running a command + * with "sudo" or executing `docker run` with the `--privileged` flag. Containerization + * does not provide any security guarantees when using this option. It should only be used + * when absolutely necessary and only with trusted commands. + */ + insecureRootCapabilities?: boolean +} + +export type ContainerWithExposedPortOpts = { + /** + * Transport layer network protocol + */ + protocol?: NetworkProtocol + + /** + * Optional port description + */ + description?: string +} + +export type ContainerWithFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number + + /** + * A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedCacheOpts = { + /** + * Identifier of the directory to use as the cache volume's root. + */ + source?: Directory + + /** + * Sharing mode of the cache volume. + */ + sharing?: CacheSharingMode + + /** + * A user:group to set for the mounted cache directory. + * + * Note that this changes the ownership of the specified mount along with the + * initial filesystem provided by source (if any). It does not have any effect + * if/when the cache has already been created. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedDirectoryOpts = { + /** + * A user:group to set for the mounted directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedFileOpts = { + /** + * A user or user:group to set for the mounted file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedSecretOpts = { + /** + * A user:group to set for the mounted secret. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string + + /** + * Permission given to the mounted secret (e.g., 0600). + * This option requires an owner to be set to be active. + * + * Default: 0400. + */ + mode?: number +} + +export type ContainerWithNewFileOpts = { + /** + * Content of the file to write (e.g., "Hello world!"). + */ + contents?: string + + /** + * Permission given to the written file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number + + /** + * A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithUnixSocketOpts = { + /** + * A user:group to set for the mounted socket. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithoutExposedPortOpts = { + /** + * Port protocol to unexpose + */ + protocol?: NetworkProtocol +} + +/** + * A unique container identifier. Null designates an empty container (scratch). + */ +export type ContainerID = string & {__ContainerID: never} + +/** + * The `DateTime` scalar type represents a DateTime. The DateTime is serialized as an RFC 3339 quoted string + */ +export type DateTime = string & {__DateTime: never} + +export type DirectoryAsModuleOpts = { + /** + * An optional subpath of the directory which contains the module's source + * code. + * + * This is needed when the module code is in a subdirectory but requires + * parent directories to be loaded in order to execute. For example, the + * module source code may need a go.mod, project.toml, package.json, etc. file + * from a parent directory. + * + * If not set, the module source code is loaded from the root of the + * directory. + */ + sourceSubpath?: string +} + +export type DirectoryDockerBuildOpts = { + /** + * Path to the Dockerfile to use (e.g., "frontend.Dockerfile"). + * + * Defaults: './Dockerfile'. + */ + dockerfile?: string + + /** + * The platform to build. + */ + platform?: Platform + + /** + * Build arguments to use in the build. + */ + buildArgs?: BuildArg[] + + /** + * Target build stage to build. + */ + target?: string + + /** + * Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name]. + */ + secrets?: Secret[] +} + +export type DirectoryEntriesOpts = { + /** + * Location of the directory to look at (e.g., "/src"). + */ + path?: string +} + +export type DirectoryPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type DirectoryWithDirectoryOpts = { + /** + * Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + */ + exclude?: string[] + + /** + * Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + include?: string[] +} + +export type DirectoryWithFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number +} + +export type DirectoryWithNewDirectoryOpts = { + /** + * Permission granted to the created directory (e.g., 0777). + * + * Default: 0755. + */ + permissions?: number +} + +export type DirectoryWithNewFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number +} + +/** + * A content-addressed directory identifier. + */ +export type DirectoryID = string & {__DirectoryID: never} + +export type FileExportOpts = { + /** + * If allowParentDirPath is true, the path argument can be a directory path, in which case + * the file will be created in that directory. + */ + allowParentDirPath?: boolean +} + +/** + * A file identifier. + */ +export type FileID = string & {__FileID: never} + +export type FunctionWithArgOpts = { + /** + * A doc string for the argument, if any + */ + description?: string + + /** + * A default value to use for this argument if not explicitly set by the caller, if any + */ + defaultValue?: JSON +} + +/** + * A reference to a FunctionArg. + */ +export type FunctionArgID = string & {__FunctionArgID: never} + +/** + * A reference to a Function. + */ +export type FunctionID = string & {__FunctionID: never} + +/** + * A reference to GeneratedCode. + */ +export type GeneratedCodeID = string & {__GeneratedCodeID: never} + +export type GitRefTreeOpts = { + sshKnownHosts?: string + sshAuthSocket?: Socket +} + +export type HostDirectoryOpts = { + /** + * Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + */ + exclude?: string[] + + /** + * Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + include?: string[] +} + +export type HostServiceOpts = { + /** + * Upstream host to forward traffic to. + */ + host?: string +} + +export type HostTunnelOpts = { + /** + * Map each service port to the same port on the host, as if the service were + * running natively. + * + * Note: enabling may result in port conflicts. + */ + native?: boolean + + /** + * Configure explicit port forwarding rules for the tunnel. + * + * If a port's frontend is unspecified or 0, a random port will be chosen by + * the host. + * + * If no ports are given, all of the service's ports are forwarded. If native + * is true, each port maps to the same port on the host. If native is false, + * each port maps to a random port chosen by the host. + * + * If ports are given and native is true, the ports are additive. + */ + ports?: PortForward[] +} + +/** + * The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID. + */ +export type ID = string & {__ID: never} + +/** + * Compression algorithm to use for image layers. + */ +export enum ImageLayerCompression { + Estargz = "EStarGZ", + Gzip = "Gzip", + Uncompressed = "Uncompressed", + Zstd = "Zstd", +} +/** + * Mediatypes to use in published or exported image metadata. + */ +export enum ImageMediaTypes { + Dockermediatypes = "DockerMediaTypes", + Ocimediatypes = "OCIMediaTypes", +} +/** + * An arbitrary JSON-encoded value. + */ +export type JSON = string & {__JSON: never} + +/** + * A reference to a Module. + */ +export type ModuleID = string & {__ModuleID: never} + +/** + * Transport layer network protocol associated to a port. + */ +export enum NetworkProtocol { + + /** + * TCP (Transmission Control Protocol) + */ + Tcp = "TCP", + + /** + * UDP (User Datagram Protocol) + */ + Udp = "UDP", +} +export type PipelineLabel = { + /** + * Label name. + */ + name: string + + /** + * Label value. + */ + value: string +} + +/** + * The platform config OS and architecture in a Container. + * + * The format is [os]/[platform]/[version] (e.g., "darwin/arm64/v7", "windows/amd64", "linux/arm64"). + */ +export type Platform = string & {__Platform: never} + +export type PortForward = { + /** + * Destination port for traffic. + */ + backend: number + + /** + * Port to expose to clients. If unspecified, a default will be chosen. + */ + frontend?: number + + /** + * Protocol to use for traffic. + */ + protocol?: NetworkProtocol +} + +export type ClientContainerOpts = { + id?: ContainerID + platform?: Platform +} + +export type ClientDirectoryOpts = { + id?: DirectoryID +} + +export type ClientGitOpts = { + /** + * Set to true to keep .git directory. + */ + keepGitDir?: boolean + + /** + * Set SSH known hosts + */ + sshKnownHosts?: string + + /** + * Set SSH auth socket + */ + sshAuthSocket?: Socket + + /** + * A service which must be started before the repo is fetched. + */ + experimentalServiceHost?: Service +} + +export type ClientHttpOpts = { + /** + * A service which must be started before the URL is fetched. + */ + experimentalServiceHost?: Service +} + +export type ClientModuleConfigOpts = { + subpath?: string +} + +export type ClientPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type ClientSocketOpts = { + id?: SocketID +} + +/** + * A unique identifier for a secret. + */ +export type SecretID = string & {__SecretID: never} + +export type ServiceEndpointOpts = { + /** + * The exposed port number for the endpoint + */ + port?: number + + /** + * Return a URL with the given scheme, eg. http for http:// + */ + scheme?: string +} + +/** + * A unique service identifier. + */ +export type ServiceID = string & {__ServiceID: never} + +/** + * A content-addressed socket identifier. + */ +export type SocketID = string & {__SocketID: never} + +export type TypeDefWithFieldOpts = { + /** + * A doc string for the field, if any + */ + description?: string +} + +export type TypeDefWithObjectOpts = { + description?: string +} + +/** + * A reference to a TypeDef. + */ +export type TypeDefID = string & {__TypeDefID: never} + +/** + * Distinguishes the different kinds of TypeDefs. + */ +export enum TypeDefKind { + + /** + * A boolean value + */ + Booleankind = "BooleanKind", + + /** + * An integer value + */ + Integerkind = "IntegerKind", + + /** + * A list of values all having the same type. + * + * Always paired with a ListTypeDef. + */ + Listkind = "ListKind", + + /** + * A named type defined in the GraphQL schema, with fields and functions. + * + * Always paired with an ObjectTypeDef. + */ + Objectkind = "ObjectKind", + + /** + * A string value + */ + Stringkind = "StringKind", + + /** + * A special kind used to signify that no value is returned. + * + * This is used for functions that have no return value. The outer TypeDef + * specifying this Kind is always Optional, as the Void is never actually + * represented. + */ + Voidkind = "VoidKind", +} +/** + * The absense of a value. + * + * A Null Void is used as a placeholder for resolvers that do not return anything. + */ +export type Void = string & {__Void: never} + +export type __TypeEnumValuesOpts = { + includeDeprecated?: boolean +} + +export type __TypeFieldsOpts = { + includeDeprecated?: boolean +} + + + + + + + + +/** + * A directory whose contents persist across runs. + */ +export class CacheVolume extends BaseClient { + private readonly _id?: CacheVolumeID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: CacheVolumeID, + ) { + super(parent) + + this._id = _id + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } +} + + + +/** + * An OCI-compatible container, also known as a docker container. + */ +export class Container extends BaseClient { + private readonly _id?: ContainerID = undefined + private readonly _envVariable?: string = undefined + private readonly _export?: boolean = undefined + private readonly _imageRef?: string = undefined + private readonly _label?: string = undefined + private readonly _platform?: Platform = undefined + private readonly _publish?: string = undefined + private readonly _shellEndpoint?: string = undefined + private readonly _stderr?: string = undefined + private readonly _stdout?: string = undefined + private readonly _sync?: ContainerID = undefined + private readonly _user?: string = undefined + private readonly _workdir?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ContainerID, + _envVariable?: string, + _export?: boolean, + _imageRef?: string, + _label?: string, + _platform?: Platform, + _publish?: string, + _shellEndpoint?: string, + _stderr?: string, + _stdout?: string, + _sync?: ContainerID, + _user?: string, + _workdir?: string, + ) { + super(parent) + + this._id = _id + this._envVariable = _envVariable + this._export = _export + this._imageRef = _imageRef + this._label = _label + this._platform = _platform + this._publish = _publish + this._shellEndpoint = _shellEndpoint + this._stderr = _stderr + this._stdout = _stdout + this._sync = _sync + this._user = _user + this._workdir = _workdir + } + + /** + * A unique identifier for this container. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Turn the container into a Service. + * + * Be sure to set any exposed ports before this conversion. + */ + asService(): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "asService", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a File representing the container serialized to a tarball. + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + asTarball(opts?: ContainerAsTarballOpts): File { + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "asTarball", + args: { ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from a Dockerfile build. + * @param context Directory context used by the Dockerfile. + * @param opts.dockerfile Path to the Dockerfile to use. + * + * Default: './Dockerfile'. + * @param opts.buildArgs Additional build arguments. + * @param opts.target Target build stage to build. + * @param opts.secrets Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name] in the build container + * + * They can be accessed in the Dockerfile using the "secret" mount type + * and mount path /run/secrets/[secret-name] + * e.g. RUN --mount=type=secret,id=my-secret curl url?token=$(cat /run/secrets/my-secret)" + */ + build(context: Directory, opts?: ContainerBuildOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "build", + args: { context, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves default arguments for future commands. + */ + async defaultArgs(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultArgs", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a directory at the given path. + * + * Mounts are included. + * @param path The path of the directory to retrieve (e.g., "./src"). + */ + directory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves entrypoint to be prepended to the arguments of all commands. + */ + async entrypoint(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "entrypoint", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the value of the specified environment variable. + * @param name The name of the environment variable to retrieve (e.g., "PATH"). + */ + async envVariable(name: string): Promise { + if (this._envVariable) { + return this._envVariable + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "envVariable", + args: { name }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of environment variables passed to commands. + */ + async envVariables(): Promise { + type envVariables = { + name: string + value: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "envVariables", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new EnvVariable( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * EXPERIMENTAL API! Subject to change/removal at any time. + * + * experimentalWithAllGPUs configures all available GPUs on the host to be accessible to this container. + * This currently works for Nvidia devices only. + */ + experimentalWithAllGPUs(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "experimentalWithAllGPUs", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * EXPERIMENTAL API! Subject to change/removal at any time. + * + * experimentalWithGPU configures the provided list of devices to be accesible to this container. + * This currently works for Nvidia devices only. + */ + experimentalWithGPU(devices: string[]): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "experimentalWithGPU", + args: { devices }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Writes the container as an OCI tarball to the destination file path on the host for the specified platform variants. + * + * Return true on success. + * It can also publishes platform variants. + * @param path Host's destination path (e.g., "./tarball"). + * Path can be relative to the engine's workdir or absolute. + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the exported image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the exported image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + async export(path: string, opts?: ContainerExportOpts): Promise { + if (this._export) { + return this._export + } + + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path, ...opts, __metadata: metadata }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of exposed ports. + * + * This includes ports already exposed by the image, even if not + * explicitly added with dagger. + */ + async exposedPorts(): Promise { + type exposedPorts = { + description: string + port: number + protocol: NetworkProtocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "exposedPorts", + }, + { + operation: "description port protocol" + }, + ], + this.client + ) + + + return response.map( + (r) => new Port( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.port, + r.protocol, + ) + ) + } + + /** + * Retrieves a file at the given path. + * + * Mounts are included. + * @param path The path of the file to retrieve (e.g., "./README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from a pulled base image. + * @param address Image's address from its registry. + * + * Formatted as [host]/[user]/[repo]:[tag] (e.g., "docker.io/dagger/dagger:main"). + */ + from(address: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "from", + args: { address }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The unique image reference which can only be retrieved immediately after the 'Container.From' call. + */ + async imageRef(): Promise { + if (this._imageRef) { + return this._imageRef + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "imageRef", + }, + ], + this.client + ) + + + return response + } + + /** + * Reads the container from an OCI tarball. + * + * NOTE: this involves unpacking the tarball to an OCI store on the host at + * $XDG_CACHE_DIR/dagger/oci. This directory can be removed whenever you like. + * @param source File to read the container from. + * @param opts.tag Identifies the tag to import from the archive, if the archive bundles + * multiple tags. + */ + import_(source: File, opts?: ContainerImportOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "import", + args: { source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves the value of the specified label. + */ + async label(name: string): Promise { + if (this._label) { + return this._label + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "label", + args: { name }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of labels passed to container. + */ + async labels(): Promise { + type labels = { + name: string + value: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "labels", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new Label( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * Retrieves the list of paths where a directory is mounted. + */ + async mounts(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "mounts", + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a named sub-pipeline + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: ContainerPipelineOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The platform this container executes and publishes as. + */ + async platform(): Promise { + if (this._platform) { + return this._platform + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "platform", + }, + ], + this.client + ) + + + return response + } + + /** + * Publishes this container as a new image to the specified address. + * + * Publish returns a fully qualified ref. + * It can also publish platform variants. + * @param address Registry's address to publish the image to. + * + * Formatted as [host]/[user]/[repo]:[tag] (e.g. "docker.io/dagger/dagger:main"). + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the published image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the published image's layers. Defaults to OCI, which + * is largely compatible with most recent registries, but Docker may be needed for older + * registries without OCI support. + */ + async publish(address: string, opts?: ContainerPublishOpts): Promise { + if (this._publish) { + return this._publish + } + + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "publish", + args: { address, ...opts, __metadata: metadata }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves this container's root filesystem. Mounts are not included. + */ + rootfs(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "rootfs", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Return a websocket endpoint that, if connected to, will start the container with a TTY streamed + * over the websocket. + * + * Primarily intended for internal use with the dagger CLI. + */ + async shellEndpoint(): Promise { + if (this._shellEndpoint) { + return this._shellEndpoint + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "shellEndpoint", + }, + ], + this.client + ) + + + return response + } + + /** + * The error stream of the last executed command. + * + * Will execute default command if none is set, or error if there's no default. + */ + async stderr(): Promise { + if (this._stderr) { + return this._stderr + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "stderr", + }, + ], + this.client + ) + + + return response + } + + /** + * The output stream of the last executed command. + * + * Will execute default command if none is set, or error if there's no default. + */ + async stdout(): Promise { + if (this._stdout) { + return this._stdout + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "stdout", + }, + ], + this.client + ) + + + return response + } + + /** + * Forces evaluation of the pipeline in the engine. + * + * It doesn't run the default command if no exec has been set. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves the user to be set for all commands. + */ + async user(): Promise { + if (this._user) { + return this._user + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "user", + }, + ], + this.client + ) + + + return response + } + + /** + * Configures default arguments for future commands. + * @param opts.args Arguments to prepend to future executions (e.g., ["-v", "--no-cache"]). + */ + withDefaultArgs(opts?: ContainerWithDefaultArgsOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withDefaultArgs", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a directory written at the given path. + * @param path Location of the written directory (e.g., "/tmp/directory"). + * @param directory Identifier of the directory to write + * @param opts.exclude Patterns to exclude in the written directory (e.g., ["node_modules/**", ".gitignore", ".git/"]). + * @param opts.include Patterns to include in the written directory (e.g., ["*.go", "go.mod", "go.sum"]). + * @param opts.owner A user:group to set for the directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withDirectory(path: string, directory: Directory, opts?: ContainerWithDirectoryOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withDirectory", + args: { path, directory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container but with a different command entrypoint. + * @param args Entrypoint to use for future executions (e.g., ["go", "run"]). + */ + withEntrypoint(args: string[]): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withEntrypoint", + args: { args }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the given environment variable. + * @param name The name of the environment variable (e.g., "HOST"). + * @param value The value of the environment variable. (e.g., "localhost"). + * @param opts.expand Replace ${VAR} or $VAR in the value according to the current environment + * variables defined in the container (e.g., "/opt/bin:$PATH"). + */ + withEnvVariable(name: string, value: string, opts?: ContainerWithEnvVariableOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withEnvVariable", + args: { name, value, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container after executing the specified command inside it. + * @param args Command to run instead of the container's default command (e.g., ["run", "main.go"]). + * + * If empty, the container's default command is used. + * @param opts.skipEntrypoint If the container has an entrypoint, ignore it for args rather than using it to wrap them. + * @param opts.stdin Content to write to the command's standard input before closing (e.g., "Hello world"). + * @param opts.redirectStdout Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout"). + * @param opts.redirectStderr Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr"). + * @param opts.experimentalPrivilegedNesting Provides dagger access to the executed command. + * + * Do not use this option unless you trust the command being executed. + * The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. + * @param opts.insecureRootCapabilities Execute the command with all root capabilities. This is similar to running a command + * with "sudo" or executing `docker run` with the `--privileged` flag. Containerization + * does not provide any security guarantees when using this option. It should only be used + * when absolutely necessary and only with trusted commands. + */ + withExec(args: string[], opts?: ContainerWithExecOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withExec", + args: { args, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Expose a network port. + * + * Exposed ports serve two purposes: + * - For health checks and introspection, when running services + * - For setting the EXPOSE OCI field when publishing the container + * @param port Port number to expose + * @param opts.protocol Transport layer network protocol + * @param opts.description Optional port description + */ + withExposedPort(port: number, opts?: ContainerWithExposedPortOpts): Container { + const metadata: Metadata = { + protocol: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withExposedPort", + args: { port, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the contents of the given file copied to the given path. + * @param path Location of the copied file (e.g., "/tmp/file.txt"). + * @param source Identifier of the file to copy. + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + * @param opts.owner A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withFile(path: string, source: File, opts?: ContainerWithFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Indicate that subsequent operations should be featured more prominently in + * the UI. + */ + withFocus(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withFocus", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the given label. + * @param name The name of the label (e.g., "org.opencontainers.artifact.created"). + * @param value The value of the label (e.g., "2023-01-01T00:00:00Z"). + */ + withLabel(name: string, value: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withLabel", + args: { name, value }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a cache volume mounted at the given path. + * @param path Location of the cache directory (e.g., "/cache/node_modules"). + * @param cache Identifier of the cache volume to mount. + * @param opts.source Identifier of the directory to use as the cache volume's root. + * @param opts.sharing Sharing mode of the cache volume. + * @param opts.owner A user:group to set for the mounted cache directory. + * + * Note that this changes the ownership of the specified mount along with the + * initial filesystem provided by source (if any). It does not have any effect + * if/when the cache has already been created. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedCache(path: string, cache: CacheVolume, opts?: ContainerWithMountedCacheOpts): Container { + const metadata: Metadata = { + sharing: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedCache", + args: { path, cache, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a directory mounted at the given path. + * @param path Location of the mounted directory (e.g., "/mnt/directory"). + * @param source Identifier of the mounted directory. + * @param opts.owner A user:group to set for the mounted directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedDirectory(path: string, source: Directory, opts?: ContainerWithMountedDirectoryOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedDirectory", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a file mounted at the given path. + * @param path Location of the mounted file (e.g., "/tmp/file.txt"). + * @param source Identifier of the mounted file. + * @param opts.owner A user or user:group to set for the mounted file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedFile(path: string, source: File, opts?: ContainerWithMountedFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a secret mounted into a file at the given path. + * @param path Location of the secret file (e.g., "/tmp/secret.txt"). + * @param source Identifier of the secret to mount. + * @param opts.owner A user:group to set for the mounted secret. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + * @param opts.mode Permission given to the mounted secret (e.g., 0600). + * This option requires an owner to be set to be active. + * + * Default: 0400. + */ + withMountedSecret(path: string, source: Secret, opts?: ContainerWithMountedSecretOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedSecret", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a temporary directory mounted at the given path. + * @param path Location of the temporary directory (e.g., "/tmp/temp_dir"). + */ + withMountedTemp(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedTemp", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a new file written at the given path. + * @param path Location of the written file (e.g., "/tmp/file.txt"). + * @param opts.contents Content of the file to write (e.g., "Hello world!"). + * @param opts.permissions Permission given to the written file (e.g., 0600). + * + * Default: 0644. + * @param opts.owner A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withNewFile(path: string, opts?: ContainerWithNewFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewFile", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a registry authentication for a given address. + * @param address Registry's address to bind the authentication to. + * Formatted as [host]/[user]/[repo]:[tag] (e.g. docker.io/dagger/dagger:main). + * @param username The username of the registry's account (e.g., "Dagger"). + * @param secret The API key, password or token to authenticate to this registry. + */ + withRegistryAuth(address: string, username: string, secret: Secret): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withRegistryAuth", + args: { address, username, secret }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from this DirectoryID. + */ + withRootfs(directory: Directory): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withRootfs", + args: { directory }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus an env variable containing the given secret. + * @param name The name of the secret variable (e.g., "API_SECRET"). + * @param secret The identifier of the secret value. + */ + withSecretVariable(name: string, secret: Secret): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withSecretVariable", + args: { name, secret }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Establish a runtime dependency on a service. + * + * The service will be started automatically when needed and detached when it is + * no longer needed, executing the default command if none is set. + * + * The service will be reachable from the container via the provided hostname alias. + * + * The service dependency will also convey to any files or directories produced by the container. + * @param alias A name that can be used to reach the service from the container + * @param service Identifier of the service container + */ + withServiceBinding(alias: string, service: Service): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withServiceBinding", + args: { alias, service }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a socket forwarded to the given Unix socket path. + * @param path Location of the forwarded Unix socket (e.g., "/tmp/socket"). + * @param source Identifier of the socket to forward. + * @param opts.owner A user:group to set for the mounted socket. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withUnixSocket(path: string, source: Socket, opts?: ContainerWithUnixSocketOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withUnixSocket", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a different command user. + * @param name The user to set (e.g., "root"). + */ + withUser(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withUser", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a different working directory. + * @param path The path to set as the working directory (e.g., "/app"). + */ + withWorkdir(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withWorkdir", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container minus the given environment variable. + * @param name The name of the environment variable (e.g., "HOST"). + */ + withoutEnvVariable(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutEnvVariable", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Unexpose a previously exposed port. + * @param port Port number to unexpose + * @param opts.protocol Port protocol to unexpose + */ + withoutExposedPort(port: number, opts?: ContainerWithoutExposedPortOpts): Container { + const metadata: Metadata = { + protocol: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutExposedPort", + args: { port, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Indicate that subsequent operations should not be featured more prominently + * in the UI. + * + * This is the initial state of all containers. + */ + withoutFocus(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutFocus", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container minus the given environment label. + * @param name The name of the label to remove (e.g., "org.opencontainers.artifact.created"). + */ + withoutLabel(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutLabel", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container after unmounting everything at the given path. + * @param path Location of the cache directory (e.g., "/cache/node_modules"). + */ + withoutMount(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutMount", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container without the registry authentication of a given address. + * @param address Registry's address to remove the authentication from. + * Formatted as [host]/[user]/[repo]:[tag] (e.g. docker.io/dagger/dagger:main). + */ + withoutRegistryAuth(address: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutRegistryAuth", + args: { address }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a previously added Unix socket removed. + * @param path Location of the socket to remove (e.g., "/tmp/socket"). + */ + withoutUnixSocket(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutUnixSocket", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves the working directory for all commands. + */ + async workdir(): Promise { + if (this._workdir) { + return this._workdir + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "workdir", + }, + ], + this.client + ) + + + return response + } + + /** + * Call the provided function with current Container. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Container) => Container) { + return arg(this) + } +} + + + + + +/** + * A directory. + */ +export class Directory extends BaseClient { + private readonly _id?: DirectoryID = undefined + private readonly _export?: boolean = undefined + private readonly _sync?: DirectoryID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: DirectoryID, + _export?: boolean, + _sync?: DirectoryID, + ) { + super(parent) + + this._id = _id + this._export = _export + this._sync = _sync + } + + /** + * The content-addressed identifier of the directory. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Load the directory as a Dagger module + * @param opts.sourceSubpath An optional subpath of the directory which contains the module's source + * code. + * + * This is needed when the module code is in a subdirectory but requires + * parent directories to be loaded in order to execute. For example, the + * module source code may need a go.mod, project.toml, package.json, etc. file + * from a parent directory. + * + * If not set, the module source code is loaded from the root of the + * directory. + */ + asModule(opts?: DirectoryAsModuleOpts): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "asModule", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Gets the difference between this directory and an another directory. + * @param other Identifier of the directory to compare. + */ + diff(other: Directory): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "diff", + args: { other }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves a directory at the given path. + * @param path Location of the directory to retrieve (e.g., "/src"). + */ + directory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Builds a new Docker container from this directory. + * @param opts.dockerfile Path to the Dockerfile to use (e.g., "frontend.Dockerfile"). + * + * Defaults: './Dockerfile'. + * @param opts.platform The platform to build. + * @param opts.buildArgs Build arguments to use in the build. + * @param opts.target Target build stage to build. + * @param opts.secrets Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name]. + */ + dockerBuild(opts?: DirectoryDockerBuildOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "dockerBuild", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a list of files and directories at the given path. + * @param opts.path Location of the directory to look at (e.g., "/src"). + */ + async entries(opts?: DirectoryEntriesOpts): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "entries", + args: { ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Writes the contents of the directory to a path on the host. + * @param path Location of the copied directory (e.g., "logs/"). + */ + async export(path: string): Promise { + if (this._export) { + return this._export + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a file at the given path. + * @param path Location of the file to retrieve (e.g., "README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a list of files and directories that matche the given pattern. + * @param pattern Pattern to match (e.g., "*.md"). + */ + async glob(pattern: string): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "glob", + args: { pattern }, + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a named sub-pipeline + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: DirectoryPipelineOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Force evaluation in the engine. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves this directory plus a directory written at the given path. + * @param path Location of the written directory (e.g., "/src/"). + * @param directory Identifier of the directory to copy. + * @param opts.exclude Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + * @param opts.include Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + withDirectory(path: string, directory: Directory, opts?: DirectoryWithDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withDirectory", + args: { path, directory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus the contents of the given file copied to the given path. + * @param path Location of the copied file (e.g., "/file.txt"). + * @param source Identifier of the file to copy. + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + withFile(path: string, source: File, opts?: DirectoryWithFileOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus a new directory created at the given path. + * @param path Location of the directory created (e.g., "/logs"). + * @param opts.permissions Permission granted to the created directory (e.g., 0777). + * + * Default: 0755. + */ + withNewDirectory(path: string, opts?: DirectoryWithNewDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewDirectory", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus a new file written at the given path. + * @param path Location of the written file (e.g., "/file.txt"). + * @param contents Content of the written file (e.g., "Hello world!"). + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + withNewFile(path: string, contents: string, opts?: DirectoryWithNewFileOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewFile", + args: { path, contents, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with all file/dir timestamps set to the given time. + * @param timestamp Timestamp to set dir/files in. + * + * Formatted in seconds following Unix epoch (e.g., 1672531199). + */ + withTimestamps(timestamp: number): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withTimestamps", + args: { timestamp }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with the directory at the given path removed. + * @param path Location of the directory to remove (e.g., ".github/"). + */ + withoutDirectory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutDirectory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with the file at the given path removed. + * @param path Location of the file to remove (e.g., "/file.txt"). + */ + withoutFile(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutFile", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Directory. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Directory) => Directory) { + return arg(this) + } +} + + + +/** + * A simple key value object that represents an environment variable. + */ +export class EnvVariable extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: string, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The environment variable name. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The environment variable value. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + +/** + * A definition of a field on a custom object defined in a Module. + * A field on an object has a static value, as opposed to a function on an + * object whose value is computed by invoking code (and can accept arguments). + */ +export class FieldTypeDef extends BaseClient { + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _name?: string, + ) { + super(parent) + + this._description = _description + this._name = _name + } + + /** + * A doc string for the field, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the field in the object + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type of the field + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * A file. + */ +export class File extends BaseClient { + private readonly _id?: FileID = undefined + private readonly _contents?: string = undefined + private readonly _export?: boolean = undefined + private readonly _size?: number = undefined + private readonly _sync?: FileID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FileID, + _contents?: string, + _export?: boolean, + _size?: number, + _sync?: FileID, + ) { + super(parent) + + this._id = _id + this._contents = _contents + this._export = _export + this._size = _size + this._sync = _sync + } + + /** + * Retrieves the content-addressed identifier of the file. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the contents of the file. + */ + async contents(): Promise { + if (this._contents) { + return this._contents + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "contents", + }, + ], + this.client + ) + + + return response + } + + /** + * Writes the file to a file path on the host. + * @param path Location of the written directory (e.g., "output.txt"). + * @param opts.allowParentDirPath If allowParentDirPath is true, the path argument can be a directory path, in which case + * the file will be created in that directory. + */ + async export(path: string, opts?: FileExportOpts): Promise { + if (this._export) { + return this._export + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path, ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Gets the size of the file, in bytes. + */ + async size(): Promise { + if (this._size) { + return this._size + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "size", + }, + ], + this.client + ) + + + return response + } + + /** + * Force evaluation in the engine. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves this file with its created/modified timestamps set to the given time. + * @param timestamp Timestamp to set dir/files in. + * + * Formatted in seconds following Unix epoch (e.g., 1672531199). + */ + withTimestamps(timestamp: number): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "withTimestamps", + args: { timestamp }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current File. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: File) => File) { + return arg(this) + } +} + + + + + +/** + * Function represents a resolver provided by a Module. + * + * A function always evaluates against a parent object and is given a set of + * named arguments. + */ +export class Function_ extends BaseClient { + private readonly _id?: FunctionID = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FunctionID, + _description?: string, + _name?: string, + ) { + super(parent) + + this._id = _id + this._description = _description + this._name = _name + } + + /** + * The ID of the function + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Arguments accepted by this function, if any + */ + async args(): Promise { + type args = { + id: FunctionArgID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "args", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new FunctionArg( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * A doc string for the function, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the function + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type returned by this function + */ + returnType(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "returnType", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns the function with the provided argument + * @param name The name of the argument + * @param typeDef The type of the argument + * @param opts.description A doc string for the argument, if any + * @param opts.defaultValue A default value to use for this argument if not explicitly set by the caller, if any + */ + withArg(name: string, typeDef: TypeDef, opts?: FunctionWithArgOpts): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "withArg", + args: { name, typeDef, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns the function with the doc string + */ + withDescription(description: string): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "withDescription", + args: { description }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Function. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Function_) => Function_) { + return arg(this) + } +} + +/** + * An argument accepted by a function. + * + * This is a specification for an argument at function definition time, not an + * argument passed at function call time. + */ +export class FunctionArg extends BaseClient { + private readonly _id?: FunctionArgID = undefined + private readonly _defaultValue?: JSON = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FunctionArgID, + _defaultValue?: JSON, + _description?: string, + _name?: string, + ) { + super(parent) + + this._id = _id + this._defaultValue = _defaultValue + this._description = _description + this._name = _name + } + + /** + * The ID of the argument + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * A default value to use for this argument when not explicitly set by the caller, if any + */ + async defaultValue(): Promise { + if (this._defaultValue) { + return this._defaultValue + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultValue", + }, + ], + this.client + ) + + + return response + } + + /** + * A doc string for the argument, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the argument + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type of the argument + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + + + +export class FunctionCall extends BaseClient { + private readonly _name?: string = undefined + private readonly _parent?: JSON = undefined + private readonly _parentName?: string = undefined + private readonly _returnValue?: Void = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _parent?: JSON, + _parentName?: string, + _returnValue?: Void, + ) { + super(parent) + + this._name = _name + this._parent = _parent + this._parentName = _parentName + this._returnValue = _returnValue + } + + /** + * The argument values the function is being invoked with. + */ + async inputArgs(): Promise { + type inputArgs = { + name: string + value: JSON + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "inputArgs", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new FunctionCallArgValue( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * The name of the function being called. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of the parent object of the function being called. + * If the function is "top-level" to the module, this is always an empty object. + */ + async parent(): Promise { + if (this._parent) { + return this._parent + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "parent", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the parent object of the function being called. + * If the function is "top-level" to the module, this is the name of the module. + */ + async parentName(): Promise { + if (this._parentName) { + return this._parentName + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "parentName", + }, + ], + this.client + ) + + + return response + } + + /** + * Set the return value of the function call to the provided value. + * The value should be a string of the JSON serialization of the return value. + */ + async returnValue(value: JSON): Promise { + if (this._returnValue) { + return this._returnValue + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "returnValue", + args: { value }, + }, + ], + this.client + ) + + + return response + } +} + + +export class FunctionCallArgValue extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: JSON = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: JSON, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The name of the argument. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of the argument represented as a string of the JSON serialization. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class GeneratedCode extends BaseClient { + private readonly _id?: GeneratedCodeID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: GeneratedCodeID, + ) { + super(parent) + + this._id = _id + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * The directory containing the generated code + */ + code(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "code", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * List of paths to mark generated in version control (i.e. .gitattributes) + */ + async vcsGeneratedPaths(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "vcsGeneratedPaths", + }, + ], + this.client + ) + + + return response + } + + /** + * List of paths to ignore in version control (i.e. .gitignore) + */ + async vcsIgnoredPaths(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "vcsIgnoredPaths", + }, + ], + this.client + ) + + + return response + } + + /** + * Set the list of paths to mark generated in version control + */ + withVCSGeneratedPaths(paths: string[]): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "withVCSGeneratedPaths", + args: { paths }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Set the list of paths to ignore in version control + */ + withVCSIgnoredPaths(paths: string[]): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "withVCSIgnoredPaths", + args: { paths }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current GeneratedCode. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: GeneratedCode) => GeneratedCode) { + return arg(this) + } +} + + + +/** + * A git ref (tag, branch or commit). + */ +export class GitRef extends BaseClient { + private readonly _commit?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _commit?: string, + ) { + super(parent) + + this._commit = _commit + } + + /** + * The resolved commit id at this ref. + */ + async commit(): Promise { + if (this._commit) { + return this._commit + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "commit", + }, + ], + this.client + ) + + + return response + } + + /** + * The filesystem tree at this ref. + */ + tree(opts?: GitRefTreeOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "tree", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * A git repository. + */ +export class GitRepository extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * Returns details on one branch. + * @param name Branch's name (e.g., "main"). + */ + branch(name: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "branch", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns details on one commit. + * @param id Identifier of the commit (e.g., "b6315d8f2810962c601af73f86831f6866ea798b"). + */ + commit(id: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "commit", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns details on one tag. + * @param name Tag's name (e.g., "v0.3.9"). + */ + tag(name: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "tag", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * Information about the host execution environment. + */ +export class Host extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * Accesses a directory on the host. + * @param path Location of the directory to access (e.g., "."). + * @param opts.exclude Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + * @param opts.include Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + directory(path: string, opts?: HostDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Accesses a file on the host. + * @param path Location of the file to retrieve (e.g., "README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a service that forwards traffic to a specified address via the host. + * @param ports Ports to expose via the service, forwarding through the host network. + * + * If a port's frontend is unspecified or 0, it defaults to the same as the + * backend port. + * + * An empty set of ports is not valid; an error will be returned. + * @param opts.host Upstream host to forward traffic to. + */ + service(ports: PortForward[], opts?: HostServiceOpts): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "service", + args: { ports, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets a secret given a user-defined name and the file path on the host, and returns the secret. + * The file is limited to a size of 512000 bytes. + * @param name The user defined name for this secret. + * @param path Location of the file to set as a secret. + */ + setSecretFile(name: string, path: string): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "setSecretFile", + args: { name, path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a tunnel that forwards traffic from the host to a service. + * @param service Service to send traffic from the tunnel. + * @param opts.native Map each service port to the same port on the host, as if the service were + * running natively. + * + * Note: enabling may result in port conflicts. + * @param opts.ports Configure explicit port forwarding rules for the tunnel. + * + * If a port's frontend is unspecified or 0, a random port will be chosen by + * the host. + * + * If no ports are given, all of the service's ports are forwarded. If native + * is true, each port maps to the same port on the host. If native is false, + * each port maps to a random port chosen by the host. + * + * If ports are given and native is true, the ports are additive. + */ + tunnel(service: Service, opts?: HostTunnelOpts): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "tunnel", + args: { service, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Accesses a Unix socket on the host. + * @param path Location of the Unix socket (e.g., "/var/run/docker.sock"). + */ + unixSocket(path: string): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "unixSocket", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + + + + + + + + + + +/** + * A simple key value object that represents a label. + */ +export class Label extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: string, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The label name. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The label value. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + +/** + * A definition of a list type in a Module. + */ +export class ListTypeDef extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * The type of the elements in the list + */ + elementTypeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "elementTypeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + +export class Module_ extends BaseClient { + private readonly _id?: ModuleID = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + private readonly _sdk?: string = undefined + private readonly _serve?: Void = undefined + private readonly _sourceDirectorySubPath?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ModuleID, + _description?: string, + _name?: string, + _sdk?: string, + _serve?: Void, + _sourceDirectorySubPath?: string, + ) { + super(parent) + + this._id = _id + this._description = _description + this._name = _name + this._sdk = _sdk + this._serve = _serve + this._sourceDirectorySubPath = _sourceDirectorySubPath + } + + /** + * The ID of the module + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Modules used by this module + */ + async dependencies(): Promise { + type dependencies = { + id: ModuleID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencies", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new Module_( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The dependencies as configured by the module + */ + async dependencyConfig(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencyConfig", + }, + ], + this.client + ) + + + return response + } + + /** + * The doc string of the module, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The code generated by the SDK's runtime + */ + generatedCode(): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "generatedCode", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The name of the module + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * Objects served by this module + */ + async objects(): Promise { + type objects = { + id: TypeDefID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "objects", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new TypeDef( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The SDK used by this module. Either a name of a builtin SDK or a module ref pointing to the SDK's implementation. + */ + async sdk(): Promise { + if (this._sdk) { + return this._sdk + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sdk", + }, + ], + this.client + ) + + + return response + } + + /** + * Serve a module's API in the current session. + * Note: this can only be called once per session. + * In the future, it could return a stream or service to remove the side effect. + */ + async serve(): Promise { + if (this._serve) { + return this._serve + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "serve", + }, + ], + this.client + ) + + + return response + } + + /** + * The directory containing the module's source code + */ + sourceDirectory(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "sourceDirectory", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The module's subpath within the source directory + */ + async sourceDirectorySubPath(): Promise { + if (this._sourceDirectorySubPath) { + return this._sourceDirectorySubPath + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sourceDirectorySubPath", + }, + ], + this.client + ) + + + return response + } + + /** + * This module plus the given Object type and associated functions + */ + withObject(object: TypeDef): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "withObject", + args: { object }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Module. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Module_) => Module_) { + return arg(this) + } +} + +/** + * Static configuration for a module (e.g. parsed contents of dagger.json) + */ +export class ModuleConfig extends BaseClient { + private readonly _name?: string = undefined + private readonly _root?: string = undefined + private readonly _sdk?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _root?: string, + _sdk?: string, + ) { + super(parent) + + this._name = _name + this._root = _root + this._sdk = _sdk + } + + /** + * Modules that this module depends on. + */ + async dependencies(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencies", + }, + ], + this.client + ) + + + return response + } + + /** + * Exclude these file globs when loading the module root. + */ + async exclude(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "exclude", + }, + ], + this.client + ) + + + return response + } + + /** + * Include only these file globs when loading the module root. + */ + async include(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "include", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the module. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The root directory of the module's project, which may be above the module source code. + */ + async root(): Promise { + if (this._root) { + return this._root + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "root", + }, + ], + this.client + ) + + + return response + } + + /** + * Either the name of a built-in SDK ('go', 'python', etc.) OR a module reference pointing to the SDK's module implementation. + */ + async sdk(): Promise { + if (this._sdk) { + return this._sdk + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sdk", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A definition of a custom object defined in a Module. + */ +export class ObjectTypeDef extends BaseClient { + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _name?: string, + ) { + super(parent) + + this._description = _description + this._name = _name + } + + /** + * The doc string for the object, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * Static fields defined on this object, if any + */ + async fields(): Promise { + type fields = { + description: string + name: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "fields", + }, + { + operation: "description name" + }, + ], + this.client + ) + + + return response.map( + (r) => new FieldTypeDef( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.name, + ) + ) + } + + /** + * Functions defined on this object, if any + */ + async functions(): Promise { + type functions = { + id: FunctionID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "functions", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new Function_( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The name of the object + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A port exposed by a container. + */ +export class Port extends BaseClient { + private readonly _description?: string = undefined + private readonly _port?: number = undefined + private readonly _protocol?: NetworkProtocol = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _port?: number, + _protocol?: NetworkProtocol, + ) { + super(parent) + + this._description = _description + this._port = _port + this._protocol = _protocol + } + + /** + * The port description. + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The port number. + */ + async port(): Promise { + if (this._port) { + return this._port + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "port", + }, + ], + this.client + ) + + + return response + } + + /** + * The transport layer network protocol. + */ + async protocol(): Promise { + if (this._protocol) { + return this._protocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "protocol", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class Client extends BaseClient { + private readonly _checkVersionCompatibility?: boolean = undefined + private readonly _defaultPlatform?: Platform = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _checkVersionCompatibility?: boolean, + _defaultPlatform?: Platform, + ) { + super(parent) + + this._checkVersionCompatibility = _checkVersionCompatibility + this._defaultPlatform = _defaultPlatform + } + + /** + * Constructs a cache volume for a given cache key. + * @param key A string identifier to target this cache volume (e.g., "modules-cache"). + */ + cacheVolume(key: string): CacheVolume { + return new CacheVolume({ + queryTree: [ + ...this._queryTree, + { + operation: "cacheVolume", + args: { key }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Checks if the current Dagger Engine is compatible with an SDK's required version. + * @param version The SDK's required version. + */ + async checkVersionCompatibility(version: string): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "checkVersionCompatibility", + args: { version }, + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a scratch container or loads one by ID. + * + * Optional platform argument initializes new containers to execute and publish + * as that platform. Platform defaults to that of the builder's host. + */ + container(opts?: ClientContainerOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "container", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The FunctionCall context that the SDK caller is currently executing in. + * If the caller is not currently executing in a function, this will return + * an error. + */ + currentFunctionCall(): FunctionCall { + return new FunctionCall({ + queryTree: [ + ...this._queryTree, + { + operation: "currentFunctionCall", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The module currently being served in the session, if any. + */ + currentModule(): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "currentModule", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The default platform of the builder. + */ + async defaultPlatform(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultPlatform", + }, + ], + this.client + ) + + + return response + } + + /** + * Creates an empty directory or loads one by ID. + */ + directory(opts?: ClientDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a file by ID. + * @deprecated Use loadFileFromID instead. + */ + file(id: FileID): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a function. + */ + function_(name: string, returnType: TypeDef): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "function", + args: { name, returnType }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a code generation result, given a directory containing the generated + * code. + */ + generatedCode(code: Directory): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "generatedCode", + args: { code }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Queries a git repository. + * @param url Url of the git repository. + * Can be formatted as https://{host}/{owner}/{repo}, git@{host}:{owner}/{repo} + * Suffix ".git" is optional. + * @param opts.keepGitDir Set to true to keep .git directory. + * @param opts.sshKnownHosts Set SSH known hosts + * @param opts.sshAuthSocket Set SSH auth socket + * @param opts.experimentalServiceHost A service which must be started before the repo is fetched. + */ + git(url: string, opts?: ClientGitOpts): GitRepository { + return new GitRepository({ + queryTree: [ + ...this._queryTree, + { + operation: "git", + args: { url, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Queries the host environment. + */ + host(): Host { + return new Host({ + queryTree: [ + ...this._queryTree, + { + operation: "host", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a file containing an http remote url content. + * @param url HTTP url to get the content from (e.g., "https://docs.dagger.io"). + * @param opts.experimentalServiceHost A service which must be started before the URL is fetched. + */ + http(url: string, opts?: ClientHttpOpts): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "http", + args: { url, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a CacheVolume from its ID. + */ + loadCacheVolumeFromID(id: CacheVolumeID): CacheVolume { + return new CacheVolume({ + queryTree: [ + ...this._queryTree, + { + operation: "loadCacheVolumeFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a container from an ID. + */ + loadContainerFromID(id: ContainerID): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "loadContainerFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Directory from its ID. + */ + loadDirectoryFromID(id: DirectoryID): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "loadDirectoryFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a File from its ID. + */ + loadFileFromID(id: FileID): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFileFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a function argument by ID. + */ + loadFunctionArgFromID(id: FunctionArgID): FunctionArg { + return new FunctionArg({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFunctionArgFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a function by ID. + */ + loadFunctionFromID(id: FunctionID): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFunctionFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a GeneratedCode by ID. + */ + loadGeneratedCodeFromID(id: GeneratedCodeID): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "loadGeneratedCodeFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a module by ID. + */ + loadModuleFromID(id: ModuleID): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "loadModuleFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Secret from its ID. + */ + loadSecretFromID(id: SecretID): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "loadSecretFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a service from ID. + */ + loadServiceFromID(id: ServiceID): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "loadServiceFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Socket from its ID. + */ + loadSocketFromID(id: SocketID): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "loadSocketFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a TypeDef by ID. + */ + loadTypeDefFromID(id: TypeDefID): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "loadTypeDefFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a new module. + */ + module_(): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "module", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load the static configuration for a module from the given source directory and optional subpath. + */ + moduleConfig(sourceDirectory: Directory, opts?: ClientModuleConfigOpts): ModuleConfig { + return new ModuleConfig({ + queryTree: [ + ...this._queryTree, + { + operation: "moduleConfig", + args: { sourceDirectory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a named sub-pipeline. + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: ClientPipelineOpts): Client { + return new Client({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a secret from its ID. + * @deprecated Use loadSecretFromID instead + */ + secret(id: SecretID): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "secret", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets a secret given a user defined name to its plaintext and returns the secret. + * The plaintext value is limited to a size of 128000 bytes. + * @param name The user defined name for this secret + * @param plaintext The plaintext of the secret + */ + setSecret(name: string, plaintext: string): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "setSecret", + args: { name, plaintext }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a socket by its ID. + * @deprecated Use loadSocketFromID instead. + */ + socket(opts?: ClientSocketOpts): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "socket", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a new TypeDef. + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Client. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Client) => Client) { + return arg(this) + } +} + +/** + * A reference to a secret value, which can be handled more safely than the value itself. + */ +export class Secret extends BaseClient { + private readonly _id?: SecretID = undefined + private readonly _plaintext?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: SecretID, + _plaintext?: string, + ) { + super(parent) + + this._id = _id + this._plaintext = _plaintext + } + + /** + * The identifier for this secret. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of this secret. + */ + async plaintext(): Promise { + if (this._plaintext) { + return this._plaintext + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "plaintext", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class Service extends BaseClient { + private readonly _id?: ServiceID = undefined + private readonly _endpoint?: string = undefined + private readonly _hostname?: string = undefined + private readonly _start?: ServiceID = undefined + private readonly _stop?: ServiceID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ServiceID, + _endpoint?: string, + _hostname?: string, + _start?: ServiceID, + _stop?: ServiceID, + ) { + super(parent) + + this._id = _id + this._endpoint = _endpoint + this._hostname = _hostname + this._start = _start + this._stop = _stop + } + + /** + * A unique identifier for this service. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves an endpoint that clients can use to reach this container. + * + * If no port is specified, the first exposed port is used. If none exist an error is returned. + * + * If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned. + * @param opts.port The exposed port number for the endpoint + * @param opts.scheme Return a URL with the given scheme, eg. http for http:// + */ + async endpoint(opts?: ServiceEndpointOpts): Promise { + if (this._endpoint) { + return this._endpoint + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "endpoint", + args: { ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a hostname which can be used by clients to reach this container. + */ + async hostname(): Promise { + if (this._hostname) { + return this._hostname + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "hostname", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of ports provided by the service. + */ + async ports(): Promise { + type ports = { + description: string + port: number + protocol: NetworkProtocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "ports", + }, + { + operation: "description port protocol" + }, + ], + this.client + ) + + + return response.map( + (r) => new Port( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.port, + r.protocol, + ) + ) + } + + /** + * Start the service and wait for its health checks to succeed. + * + * Services bound to a Container do not need to be manually started. + */ + async start(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "start", + }, + ], + this.client + ) + + return this + } + + /** + * Stop the service. + */ + async stop(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "stop", + }, + ], + this.client + ) + + return this + } +} + + + + +export class Socket extends BaseClient { + private readonly _id?: SocketID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: SocketID, + ) { + super(parent) + + this._id = _id + } + + /** + * The content-addressed identifier of the socket. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A definition of a parameter or return type in a Module. + */ +export class TypeDef extends BaseClient { + private readonly _id?: TypeDefID = undefined + private readonly _kind?: TypeDefKind = undefined + private readonly _optional?: boolean = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: TypeDefID, + _kind?: TypeDefKind, + _optional?: boolean, + ) { + super(parent) + + this._id = _id + this._kind = _kind + this._optional = _optional + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * If kind is LIST, the list-specific type definition. + * If kind is not LIST, this will be null. + */ + asList(): ListTypeDef { + return new ListTypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "asList", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * If kind is OBJECT, the object-specific type definition. + * If kind is not OBJECT, this will be null. + */ + asObject(): ObjectTypeDef { + return new ObjectTypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "asObject", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The kind of type this is (e.g. primitive, list, object) + */ + async kind(): Promise { + if (this._kind) { + return this._kind + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "kind", + }, + ], + this.client + ) + + + return response + } + + /** + * Whether this type can be set to null. Defaults to false. + */ + async optional(): Promise { + if (this._optional) { + return this._optional + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "optional", + }, + ], + this.client + ) + + + return response + } + + /** + * Adds a static field for an Object TypeDef, failing if the type is not an object. + * @param name The name of the field in the object + * @param typeDef The type of the field + * @param opts.description A doc string for the field, if any + */ + withField(name: string, typeDef: TypeDef, opts?: TypeDefWithFieldOpts): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withField", + args: { name, typeDef, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Adds a function for an Object TypeDef, failing if the type is not an object. + */ + withFunction(function_: Function_): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withFunction", + args: { function_ }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets the kind of the type. + */ + withKind(kind: TypeDefKind): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withKind", + args: { kind }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a TypeDef of kind List with the provided type for its elements. + */ + withListOf(elementType: TypeDef): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withListOf", + args: { elementType }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a TypeDef of kind Object with the provided name. + * + * Note that an object's fields and functions may be omitted if the intent is + * only to refer to an object. This is how functions are able to return their + * own object, or any other circular reference. + */ + withObject(name: string, opts?: TypeDefWithObjectOpts): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withObject", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets whether this type can be set to null. + */ + withOptional(optional: boolean): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withOptional", + args: { optional }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current TypeDef. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: TypeDef) => TypeDef) { + return arg(this) + } +} + + + + + + + diff --git a/example/.fluentci/sdk/connect.ts b/example/.fluentci/sdk/connect.ts new file mode 100644 index 0000000..bd26cf7 --- /dev/null +++ b/example/.fluentci/sdk/connect.ts @@ -0,0 +1,89 @@ +import { Writable } from "node:stream"; + +import { Client } from "./client.gen.ts"; + +/** + * ConnectOpts defines option used to connect to an engine. + */ +export interface ConnectOpts { + /** + * Use to overwrite Dagger workdir + * @defaultValue process.cwd() + */ + Workdir?: string; + /** + * Enable logs output + * @example + * LogOutput + * ```ts + * connect(async (client: Client) => { + const source = await client.host().workdir().id() + ... + }, {LogOutput: process.stdout}) + ``` + */ + LogOutput?: Writable; +} + +export type CallbackFct = (client: Client) => Promise; + +export interface ConnectParams { + port: number; + session_token: string; +} + +/** + * connect runs GraphQL server and initializes a + * GraphQL client to execute query on it through its callback. + * This implementation is based on the existing Go SDK. + */ +export async function connect( + cb: CallbackFct, + config: ConnectOpts = {} +): Promise { + let client: Client; + // let close: null | (() => void) = null; + + if (Deno.env.has("FLUENTCI_TOKEN") && Deno.env.has("FLUENTCI_SESSION_ID")) { + const client = new Client({ + host: Deno.env.get("FLUENTCI_HOST") || "vm.fluentci.io", + sessionToken: Deno.env.get("FLUENTCI_TOKEN"), + }); + await cb(client).finally(() => { + if (close) { + close(); + } + }); + return; + } + + // Prefer DAGGER_SESSION_PORT if set + const daggerSessionPort = Deno.env.get("DAGGER_SESSION_PORT"); + if (daggerSessionPort) { + const sessionToken = Deno.env.get("DAGGER_SESSION_TOKEN"); + if (!sessionToken) { + throw new Error( + "DAGGER_SESSION_TOKEN must be set when using DAGGER_SESSION_PORT" + ); + } + + if (config.Workdir && config.Workdir !== "") { + throw new Error( + "cannot configure workdir for existing session (please use --workdir or host.directory with absolute paths instead)" + ); + } + + client = new Client({ + host: `127.0.0.1:${daggerSessionPort}`, + sessionToken: sessionToken, + }); + } else { + throw new Error("DAGGER_SESSION_PORT must be set"); + } + + await cb(client).finally(() => { + if (close) { + close(); + } + }); +} diff --git a/example/.fluentci/sdk/utils.ts b/example/.fluentci/sdk/utils.ts new file mode 100644 index 0000000..075e278 --- /dev/null +++ b/example/.fluentci/sdk/utils.ts @@ -0,0 +1,251 @@ +// deno-lint-ignore-file no-explicit-any +import { + ClientError, + gql, + GraphQLClient, + GraphQLRequestError, + TooManyNestedObjectsError, + UnknownDaggerError, + NotAwaitedRequestError, + ExecError, +} from "../deps.ts"; + +import { Metadata, QueryTree } from "./client.gen.ts"; + +/** + * Format argument into GraphQL query format. + */ +function buildArgs(args: any): string { + const metadata: Metadata = args.__metadata || {}; + + // Remove unwanted quotes + const formatValue = (key: string, value: string) => { + // Special treatment for enumeration, they must be inserted without quotes + if (metadata[key]?.is_enum) { + return JSON.stringify(value).replace(/['"]+/g, ""); + } + + return JSON.stringify(value).replace( + /\{"[a-zA-Z]+":|,"[a-zA-Z]+":/gi, + (str) => { + return str.replace(/"/g, ""); + } + ); + }; + + if (args === undefined || args === null) { + return ""; + } + + const formattedArgs = Object.entries(args).reduce( + (acc: any, [key, value]) => { + // Ignore internal metadata key + if (key === "__metadata") { + return acc; + } + + if (value !== undefined && value !== null) { + acc.push(`${key}: ${formatValue(key, value as string)}`); + } + + return acc; + }, + [] + ); + + if (formattedArgs.length === 0) { + return ""; + } + + return `(${formattedArgs})`; +} + +/** + * Find QueryTree, convert them into GraphQl query + * then compute and return the result to the appropriate field + */ +async function computeNestedQuery( + query: QueryTree[], + client: GraphQLClient +): Promise { + // Check if there is a nested queryTree to be executed + const isQueryTree = (value: any) => value["_queryTree"] !== undefined; + + // Check if there is a nested array of queryTree to be executed + const isArrayQueryTree = (value: any[]) => + value.every((v) => v instanceof Object && isQueryTree(v)); + + // Prepare query tree for final query by computing nested queries + // and building it with their results. + const computeQueryTree = async (value: any): Promise => { + // Resolve sub queries if operation's args is a subquery + for (const op of value["_queryTree"]) { + await computeNestedQuery([op], client); + } + + // push an id that will be used by the container + return buildQuery([ + ...value["_queryTree"], + { + operation: "id", + }, + ]); + }; + + // Remove all undefined args and assert args type + const queryToExec = query.filter((q): q is Required => !!q.args); + + for (const q of queryToExec) { + await Promise.all( + // Compute nested query for single object + Object.entries(q.args).map(async ([key, value]: any) => { + if (value instanceof Object && isQueryTree(value)) { + // push an id that will be used by the container + const getQueryTree = await computeQueryTree(value); + + q.args[key] = await compute(getQueryTree, client); + } + + // Compute nested query for array of object + if (Array.isArray(value) && isArrayQueryTree(value)) { + const tmp: any = q.args[key]; + + for (let i = 0; i < value.length; i++) { + // push an id that will be used by the container + const getQueryTree = await computeQueryTree(value[i]); + + tmp[i] = await compute(getQueryTree, client); + } + + q.args[key] = tmp; + } + }) + ); + } +} + +/** + * Convert the queryTree into a GraphQL query + * @param q + * @returns + */ +export function buildQuery(q: QueryTree[]): string { + const query = q.reduce((acc, { operation, args }, i) => { + const qLen = q.length; + + acc += ` ${operation} ${args ? `${buildArgs(args)}` : ""} ${ + qLen - 1 !== i ? "{" : "}".repeat(qLen - 1) + }`; + + return acc; + }, ""); + + return `{${query + .replaceAll('"StringKind"', "StringKind") + .replaceAll('"VoidKind"', "VoidKind") + .replaceAll('"IntegerKind"', "IntegerKind") + .replaceAll('"BooleanKind"', "BooleanKind") + .replaceAll('"ObjectKind"', "ObjectKind") + .replaceAll('"ListKind"', "ListKind") + .replaceAll("function_", "function")} }`; +} + +/** + * Convert querytree into a Graphql query then compute it + * @param q | QueryTree[] + * @param client | GraphQLClient + * @returns + */ +export async function computeQuery( + q: QueryTree[], + client: GraphQLClient +): Promise { + await computeNestedQuery(q, client); + + const query = buildQuery(q); + + return await compute(query, client); +} + +/** + * Return a Graphql query result flattened + * @param response any + * @returns + */ +export function queryFlatten(response: any): T { + // Recursion break condition + // If our response is not an object or an array we assume we reached the value + if (!(response instanceof Object) || Array.isArray(response)) { + return response; + } + + const keys = Object.keys(response); + + if (keys.length != 1) { + // Dagger is currently expecting to only return one value + // If the response is nested in a way were more than one object is nested inside throw an error + throw new TooManyNestedObjectsError( + "Too many nested objects inside graphql response", + { response: response } + ); + } + + const nestedKey = keys[0]; + + return queryFlatten(response[nestedKey]); +} + +/** + * Send a GraphQL document to the server + * return a flatten result + * @hidden + */ +export async function compute( + query: string, + client: GraphQLClient +): Promise { + let computeQuery: Awaited; + try { + computeQuery = await client.request( + gql` + ${query} + ` + ); + } catch (e: any) { + if (e instanceof ClientError) { + const msg = e.response.errors?.[0]?.message ?? `API Error`; + const ext = e.response.errors?.[0]?.extensions; + + if (ext?._type === "EXEC_ERROR") { + throw new ExecError(msg, { + cmd: (ext.cmd as string[]) ?? [], + exitCode: (ext.exitCode as number) ?? -1, + stdout: (ext.stdout as string) ?? "", + stderr: (ext.stderr as string) ?? "", + }); + } + + throw new GraphQLRequestError(msg, { + request: e.request, + response: e.response, + cause: e, + }); + } + + // Looking for connection error in case the function has not been awaited. + if (e.errno === "ECONNREFUSED") { + throw new NotAwaitedRequestError( + "Encountered an error while requesting data via graphql through a synchronous call. Make sure the function called is awaited.", + { cause: e } + ); + } + + // Just throw the unknown error + throw new UnknownDaggerError( + "Encountered an unknown error while requesting data via graphql", + { cause: e } + ); + } + + return queryFlatten(computeQuery); +} diff --git a/example/.fluentci/src/dagger/jobs.ts b/example/.fluentci/src/dagger/jobs.ts index 249058b..cd39e3a 100644 --- a/example/.fluentci/src/dagger/jobs.ts +++ b/example/.fluentci/src/dagger/jobs.ts @@ -1,4 +1,6 @@ -import Client, { connect } from "../../deps.ts"; +import Client, { Directory } from "../../deps.ts"; +import { connect } from "../../sdk/connect.ts"; +import { getDirectory } from "./lib.ts"; export enum Job { config = "config", @@ -10,13 +12,34 @@ export enum Job { export const exclude = [".fluentci"]; -export const config = async (src = ".", exitCode?: number) => { +/** + * @function + * @description Scan a configuration file + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function config( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["config", src]; + const context = getDirectory(client, src); + const args = ["config", "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.config) .container() @@ -30,15 +53,36 @@ export const config = async (src = ".", exitCode?: number) => { console.log(result); }); return "Done"; -}; +} -export const fs = async (src = ".", exitCode?: number) => { +/** + * @function + * @description Scan a local filesystem + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function fs( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["fs", src]; + const context = getDirectory(client, src); + const args = ["fs", "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.fs) .container() @@ -52,15 +96,38 @@ export const fs = async (src = ".", exitCode?: number) => { console.log(result); }); return "Done"; -}; +} -export const repo = async (src = ".", exitCode?: number, repoUrl?: string) => { +/** + * @function + * @description Scan a repository + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} repoUrl + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function repo( + src: Directory | string, + exitCode?: number, + repoUrl?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["repo", Deno.env.get("TRIVY_REPO_URL") || repoUrl || src]; + const context = getDirectory(client, src); + const args = ["repo", Deno.env.get("TRIVY_REPO_URL") || repoUrl || "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.repo) .container() @@ -74,16 +141,41 @@ export const repo = async (src = ".", exitCode?: number, repoUrl?: string) => { console.log(result); }); return "Done"; -}; +} -export const image = async (src = ".", exitCode?: number, image?: string) => { +/** + * @function + * @description Scan a container image + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} image + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function image( + src: Directory | string, + exitCode?: number, + image?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); + const context = getDirectory(client, src); if (!Deno.env.has("TRIVY_IMAGE") && !image) { - throw new Error("TRIVY_IMAGE is not set"); + console.log("TRIVY_IMAGE is not set"); + Deno.exit(1); } const args = ["image", Deno.env.get("TRIVY_IMAGE") || image!]; + + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); @@ -100,19 +192,43 @@ export const image = async (src = ".", exitCode?: number, image?: string) => { console.log(result); }); return "Done"; -}; +} -export const sbom = async (src = ".", exitCode?: number, path?: string) => { +/** + * @function + * @description Scan a software bill of materials + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} path + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function sbom( + src: Directory | string, + exitCode?: number, + path?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); + const context = getDirectory(client, src); if (!Deno.env.has("TRIVY_SBOM_PATH") && !path) { - throw new Error("TRIVY_SBOM_PATH is not set"); + console.error("TRIVY_SBOM_PATH is not set"); + Deno.exit(1); } const args = ["sbom", Deno.env.get("TRIVY_SBOM_PATH") || path!]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.config) .container() @@ -126,16 +242,15 @@ export const sbom = async (src = ".", exitCode?: number, path?: string) => { console.log(result); }); return "Done"; -}; +} export type JobExec = ( - src?: string, - exitCode?: number -) => - | Promise - | ((src?: string, exitCode?: number, path?: string) => Promise) - | ((src?: string, exitCode?: number, repoUrl?: string) => Promise) - | ((src?: string, exitCode?: number, image?: string) => Promise); + src: Directory | string, + exitCode?: number, + path?: string, + format?: string, + output?: string +) => Promise; export const runnableJobs: Record = { [Job.config]: config, diff --git a/example/.fluentci/src/dagger/lib.ts b/example/.fluentci/src/dagger/lib.ts new file mode 100644 index 0000000..5106de1 --- /dev/null +++ b/example/.fluentci/src/dagger/lib.ts @@ -0,0 +1,13 @@ +import Client, { Directory, DirectoryID } from "../../deps.ts"; + +export const getDirectory = ( + client: Client, + src: string | Directory | undefined = "." +) => { + if (typeof src === "string" && src.startsWith("core.Directory")) { + return client.directory({ + id: src as DirectoryID, + }); + } + return src instanceof Directory ? src : client.host().directory(src); +}; diff --git a/example/.fluentci/src/dagger/pipeline.ts b/example/.fluentci/src/dagger/pipeline.ts index 9dc7a64..dbc9adc 100644 --- a/example/.fluentci/src/dagger/pipeline.ts +++ b/example/.fluentci/src/dagger/pipeline.ts @@ -21,6 +21,6 @@ async function runSpecificJobs(args: jobs.Job[]) { if (!job) { throw new Error(`Job ${name} not found`); } - await job(); + await job("."); } } diff --git a/example/dagger.json b/example/dagger.json index 675fa77..06292be 100644 --- a/example/dagger.json +++ b/example/dagger.json @@ -1,5 +1,4 @@ { - "root": "", "name": "trivy", - "sdkRuntime": "tsiry/dagger-sdk-deno" + "sdk": "github.com/fluentci-io/daggerverse/deno-sdk@main" } \ No newline at end of file diff --git a/gen/nexus.ts b/gen/nexus.ts deleted file mode 100644 index 93f27f4..0000000 --- a/gen/nexus.ts +++ /dev/null @@ -1,162 +0,0 @@ -/** - * This file was generated by Nexus Schema - * Do not make changes to this file directly - */ - - - - - - - -declare global { - interface NexusGen extends NexusGenTypes {} -} - -export interface NexusGenInputs { -} - -export interface NexusGenEnums { -} - -export interface NexusGenScalars { - String: string - Int: number - Float: number - Boolean: boolean - ID: string -} - -export interface NexusGenObjects { - Query: {}; -} - -export interface NexusGenInterfaces { -} - -export interface NexusGenUnions { -} - -export type NexusGenRootTypes = NexusGenObjects - -export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars - -export interface NexusGenFieldTypes { - Query: { // field return type - config: string | null; // String - fs: string | null; // String - image: string | null; // String - repo: string | null; // String - sbom: string | null; // String - } -} - -export interface NexusGenFieldTypeNames { - Query: { // field return type name - config: 'String' - fs: 'String' - image: 'String' - repo: 'String' - sbom: 'String' - } -} - -export interface NexusGenArgTypes { - Query: { - config: { // args - exitCode: number; // Int! - src: string; // String! - } - fs: { // args - exitCode: number; // Int! - src: string; // String! - } - image: { // args - exitCode: number; // Int! - image: string; // String! - src: string; // String! - } - repo: { // args - exitCode: number; // Int! - repoUrl: string; // String! - src: string; // String! - } - sbom: { // args - exitCode: number; // Int! - path: string; // String! - src: string; // String! - } - } -} - -export interface NexusGenAbstractTypeMembers { -} - -export interface NexusGenTypeInterfaces { -} - -export type NexusGenObjectNames = keyof NexusGenObjects; - -export type NexusGenInputNames = never; - -export type NexusGenEnumNames = never; - -export type NexusGenInterfaceNames = never; - -export type NexusGenScalarNames = keyof NexusGenScalars; - -export type NexusGenUnionNames = never; - -export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; - -export type NexusGenAbstractsUsingStrategyResolveType = never; - -export type NexusGenFeaturesConfig = { - abstractTypeStrategies: { - isTypeOf: false - resolveType: true - __typename: false - } -} - -export interface NexusGenTypes { - context: any; - inputTypes: NexusGenInputs; - rootTypes: NexusGenRootTypes; - inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars; - argTypes: NexusGenArgTypes; - fieldTypes: NexusGenFieldTypes; - fieldTypeNames: NexusGenFieldTypeNames; - allTypes: NexusGenAllTypes; - typeInterfaces: NexusGenTypeInterfaces; - objectNames: NexusGenObjectNames; - inputNames: NexusGenInputNames; - enumNames: NexusGenEnumNames; - interfaceNames: NexusGenInterfaceNames; - scalarNames: NexusGenScalarNames; - unionNames: NexusGenUnionNames; - allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames']; - allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames']; - allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes'] - abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames']; - abstractTypeMembers: NexusGenAbstractTypeMembers; - objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf; - abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType; - features: NexusGenFeaturesConfig; -} - - -declare global { - interface NexusGenPluginTypeConfig { - } - interface NexusGenPluginInputTypeConfig { - } - interface NexusGenPluginFieldConfig { - } - interface NexusGenPluginInputFieldConfig { - } - interface NexusGenPluginSchemaConfig { - } - interface NexusGenPluginArgConfig { - } -} \ No newline at end of file diff --git a/schema.graphql b/schema.graphql deleted file mode 100644 index cdc7f70..0000000 --- a/schema.graphql +++ /dev/null @@ -1,11 +0,0 @@ -### This file was generated by Nexus Schema -### Do not make changes to this file directly - - -type Query { - config(exitCode: Int!, src: String!): String - fs(exitCode: Int!, src: String!): String - image(exitCode: Int!, image: String!, src: String!): String - repo(exitCode: Int!, repoUrl: String!, src: String!): String - sbom(exitCode: Int!, path: String!, src: String!): String -} \ No newline at end of file diff --git a/sdk/client.gen.ts b/sdk/client.gen.ts new file mode 100644 index 0000000..d18ad57 --- /dev/null +++ b/sdk/client.gen.ts @@ -0,0 +1,5993 @@ +/** + * This file was auto-generated by `client-gen`. + * Do not make direct changes to the file. + */ +import { GraphQLClient } from "../deps.ts" + +import { computeQuery } from "./utils.ts" + +/** + * @hidden + */ +export type QueryTree = { + operation: string + args?: Record +} + +/** + * @hidden + */ +export type Metadata = { + [key: string]: { + is_enum?: boolean + } +} + +interface ClientConfig { + queryTree?: QueryTree[] + host?: string + sessionToken?: string +} + +class BaseClient { + protected _queryTree: QueryTree[] + protected client: GraphQLClient + /** + * @defaultValue `127.0.0.1:8080` + */ + public clientHost: string + public sessionToken: string + + /** + * @hidden + */ + constructor({ queryTree, host, sessionToken }: ClientConfig = {}) { + this._queryTree = queryTree || [] + this.clientHost = host || "127.0.0.1:8080" + this.sessionToken = sessionToken || "" + this.client = new GraphQLClient(`http://${host}/query`, { + headers: { + Authorization: + "Basic " + btoa(sessionToken + ":"), + }, + }) + } + + /** + * @hidden + */ + get queryTree() { + return this._queryTree + } +} + +export type BuildArg = { + /** + * The build argument name. + */ + name: string + + /** + * The build argument value. + */ + value: string +} + +/** + * Sharing mode of the cache volume. + */ +export enum CacheSharingMode { + + /** + * Shares the cache volume amongst many build pipelines, + * but will serialize the writes + */ + Locked = "LOCKED", + + /** + * Keeps a cache volume for a single build pipeline + */ + Private = "PRIVATE", + + /** + * Shares the cache volume amongst many build pipelines + */ + Shared = "SHARED", +} +/** + * A global cache volume identifier. + */ +export type CacheVolumeID = string & {__CacheVolumeID: never} + +export type ContainerAsTarballOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerBuildOpts = { + /** + * Path to the Dockerfile to use. + * + * Default: './Dockerfile'. + */ + dockerfile?: string + + /** + * Additional build arguments. + */ + buildArgs?: BuildArg[] + + /** + * Target build stage to build. + */ + target?: string + + /** + * Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name] in the build container + * + * They can be accessed in the Dockerfile using the "secret" mount type + * and mount path /run/secrets/[secret-name] + * e.g. RUN --mount=type=secret,id=my-secret curl url?token=$(cat /run/secrets/my-secret)" + */ + secrets?: Secret[] +} + +export type ContainerExportOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the exported image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the exported image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerImportOpts = { + /** + * Identifies the tag to import from the archive, if the archive bundles + * multiple tags. + */ + tag?: string +} + +export type ContainerPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type ContainerPublishOpts = { + /** + * Identifiers for other platform specific containers. + * Used for multi-platform image. + */ + platformVariants?: Container[] + + /** + * Force each layer of the published image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + */ + forcedCompression?: ImageLayerCompression + + /** + * Use the specified media types for the published image's layers. Defaults to OCI, which + * is largely compatible with most recent registries, but Docker may be needed for older + * registries without OCI support. + */ + mediaTypes?: ImageMediaTypes +} + +export type ContainerWithDefaultArgsOpts = { + /** + * Arguments to prepend to future executions (e.g., ["-v", "--no-cache"]). + */ + args?: string[] +} + +export type ContainerWithDirectoryOpts = { + /** + * Patterns to exclude in the written directory (e.g., ["node_modules/**", ".gitignore", ".git/"]). + */ + exclude?: string[] + + /** + * Patterns to include in the written directory (e.g., ["*.go", "go.mod", "go.sum"]). + */ + include?: string[] + + /** + * A user:group to set for the directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithEnvVariableOpts = { + /** + * Replace ${VAR} or $VAR in the value according to the current environment + * variables defined in the container (e.g., "/opt/bin:$PATH"). + */ + expand?: boolean +} + +export type ContainerWithExecOpts = { + /** + * If the container has an entrypoint, ignore it for args rather than using it to wrap them. + */ + skipEntrypoint?: boolean + + /** + * Content to write to the command's standard input before closing (e.g., "Hello world"). + */ + stdin?: string + + /** + * Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout"). + */ + redirectStdout?: string + + /** + * Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr"). + */ + redirectStderr?: string + + /** + * Provides dagger access to the executed command. + * + * Do not use this option unless you trust the command being executed. + * The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. + */ + experimentalPrivilegedNesting?: boolean + + /** + * Execute the command with all root capabilities. This is similar to running a command + * with "sudo" or executing `docker run` with the `--privileged` flag. Containerization + * does not provide any security guarantees when using this option. It should only be used + * when absolutely necessary and only with trusted commands. + */ + insecureRootCapabilities?: boolean +} + +export type ContainerWithExposedPortOpts = { + /** + * Transport layer network protocol + */ + protocol?: NetworkProtocol + + /** + * Optional port description + */ + description?: string +} + +export type ContainerWithFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number + + /** + * A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedCacheOpts = { + /** + * Identifier of the directory to use as the cache volume's root. + */ + source?: Directory + + /** + * Sharing mode of the cache volume. + */ + sharing?: CacheSharingMode + + /** + * A user:group to set for the mounted cache directory. + * + * Note that this changes the ownership of the specified mount along with the + * initial filesystem provided by source (if any). It does not have any effect + * if/when the cache has already been created. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedDirectoryOpts = { + /** + * A user:group to set for the mounted directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedFileOpts = { + /** + * A user or user:group to set for the mounted file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithMountedSecretOpts = { + /** + * A user:group to set for the mounted secret. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string + + /** + * Permission given to the mounted secret (e.g., 0600). + * This option requires an owner to be set to be active. + * + * Default: 0400. + */ + mode?: number +} + +export type ContainerWithNewFileOpts = { + /** + * Content of the file to write (e.g., "Hello world!"). + */ + contents?: string + + /** + * Permission given to the written file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number + + /** + * A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithUnixSocketOpts = { + /** + * A user:group to set for the mounted socket. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + owner?: string +} + +export type ContainerWithoutExposedPortOpts = { + /** + * Port protocol to unexpose + */ + protocol?: NetworkProtocol +} + +/** + * A unique container identifier. Null designates an empty container (scratch). + */ +export type ContainerID = string & {__ContainerID: never} + +/** + * The `DateTime` scalar type represents a DateTime. The DateTime is serialized as an RFC 3339 quoted string + */ +export type DateTime = string & {__DateTime: never} + +export type DirectoryAsModuleOpts = { + /** + * An optional subpath of the directory which contains the module's source + * code. + * + * This is needed when the module code is in a subdirectory but requires + * parent directories to be loaded in order to execute. For example, the + * module source code may need a go.mod, project.toml, package.json, etc. file + * from a parent directory. + * + * If not set, the module source code is loaded from the root of the + * directory. + */ + sourceSubpath?: string +} + +export type DirectoryDockerBuildOpts = { + /** + * Path to the Dockerfile to use (e.g., "frontend.Dockerfile"). + * + * Defaults: './Dockerfile'. + */ + dockerfile?: string + + /** + * The platform to build. + */ + platform?: Platform + + /** + * Build arguments to use in the build. + */ + buildArgs?: BuildArg[] + + /** + * Target build stage to build. + */ + target?: string + + /** + * Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name]. + */ + secrets?: Secret[] +} + +export type DirectoryEntriesOpts = { + /** + * Location of the directory to look at (e.g., "/src"). + */ + path?: string +} + +export type DirectoryPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type DirectoryWithDirectoryOpts = { + /** + * Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + */ + exclude?: string[] + + /** + * Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + include?: string[] +} + +export type DirectoryWithFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number +} + +export type DirectoryWithNewDirectoryOpts = { + /** + * Permission granted to the created directory (e.g., 0777). + * + * Default: 0755. + */ + permissions?: number +} + +export type DirectoryWithNewFileOpts = { + /** + * Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + permissions?: number +} + +/** + * A content-addressed directory identifier. + */ +export type DirectoryID = string & {__DirectoryID: never} + +export type FileExportOpts = { + /** + * If allowParentDirPath is true, the path argument can be a directory path, in which case + * the file will be created in that directory. + */ + allowParentDirPath?: boolean +} + +/** + * A file identifier. + */ +export type FileID = string & {__FileID: never} + +export type FunctionWithArgOpts = { + /** + * A doc string for the argument, if any + */ + description?: string + + /** + * A default value to use for this argument if not explicitly set by the caller, if any + */ + defaultValue?: JSON +} + +/** + * A reference to a FunctionArg. + */ +export type FunctionArgID = string & {__FunctionArgID: never} + +/** + * A reference to a Function. + */ +export type FunctionID = string & {__FunctionID: never} + +/** + * A reference to GeneratedCode. + */ +export type GeneratedCodeID = string & {__GeneratedCodeID: never} + +export type GitRefTreeOpts = { + sshKnownHosts?: string + sshAuthSocket?: Socket +} + +export type HostDirectoryOpts = { + /** + * Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + */ + exclude?: string[] + + /** + * Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + include?: string[] +} + +export type HostServiceOpts = { + /** + * Upstream host to forward traffic to. + */ + host?: string +} + +export type HostTunnelOpts = { + /** + * Map each service port to the same port on the host, as if the service were + * running natively. + * + * Note: enabling may result in port conflicts. + */ + native?: boolean + + /** + * Configure explicit port forwarding rules for the tunnel. + * + * If a port's frontend is unspecified or 0, a random port will be chosen by + * the host. + * + * If no ports are given, all of the service's ports are forwarded. If native + * is true, each port maps to the same port on the host. If native is false, + * each port maps to a random port chosen by the host. + * + * If ports are given and native is true, the ports are additive. + */ + ports?: PortForward[] +} + +/** + * The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID. + */ +export type ID = string & {__ID: never} + +/** + * Compression algorithm to use for image layers. + */ +export enum ImageLayerCompression { + Estargz = "EStarGZ", + Gzip = "Gzip", + Uncompressed = "Uncompressed", + Zstd = "Zstd", +} +/** + * Mediatypes to use in published or exported image metadata. + */ +export enum ImageMediaTypes { + Dockermediatypes = "DockerMediaTypes", + Ocimediatypes = "OCIMediaTypes", +} +/** + * An arbitrary JSON-encoded value. + */ +export type JSON = string & {__JSON: never} + +/** + * A reference to a Module. + */ +export type ModuleID = string & {__ModuleID: never} + +/** + * Transport layer network protocol associated to a port. + */ +export enum NetworkProtocol { + + /** + * TCP (Transmission Control Protocol) + */ + Tcp = "TCP", + + /** + * UDP (User Datagram Protocol) + */ + Udp = "UDP", +} +export type PipelineLabel = { + /** + * Label name. + */ + name: string + + /** + * Label value. + */ + value: string +} + +/** + * The platform config OS and architecture in a Container. + * + * The format is [os]/[platform]/[version] (e.g., "darwin/arm64/v7", "windows/amd64", "linux/arm64"). + */ +export type Platform = string & {__Platform: never} + +export type PortForward = { + /** + * Destination port for traffic. + */ + backend: number + + /** + * Port to expose to clients. If unspecified, a default will be chosen. + */ + frontend?: number + + /** + * Protocol to use for traffic. + */ + protocol?: NetworkProtocol +} + +export type ClientContainerOpts = { + id?: ContainerID + platform?: Platform +} + +export type ClientDirectoryOpts = { + id?: DirectoryID +} + +export type ClientGitOpts = { + /** + * Set to true to keep .git directory. + */ + keepGitDir?: boolean + + /** + * Set SSH known hosts + */ + sshKnownHosts?: string + + /** + * Set SSH auth socket + */ + sshAuthSocket?: Socket + + /** + * A service which must be started before the repo is fetched. + */ + experimentalServiceHost?: Service +} + +export type ClientHttpOpts = { + /** + * A service which must be started before the URL is fetched. + */ + experimentalServiceHost?: Service +} + +export type ClientModuleConfigOpts = { + subpath?: string +} + +export type ClientPipelineOpts = { + /** + * Pipeline description. + */ + description?: string + + /** + * Pipeline labels. + */ + labels?: PipelineLabel[] +} + +export type ClientSocketOpts = { + id?: SocketID +} + +/** + * A unique identifier for a secret. + */ +export type SecretID = string & {__SecretID: never} + +export type ServiceEndpointOpts = { + /** + * The exposed port number for the endpoint + */ + port?: number + + /** + * Return a URL with the given scheme, eg. http for http:// + */ + scheme?: string +} + +/** + * A unique service identifier. + */ +export type ServiceID = string & {__ServiceID: never} + +/** + * A content-addressed socket identifier. + */ +export type SocketID = string & {__SocketID: never} + +export type TypeDefWithFieldOpts = { + /** + * A doc string for the field, if any + */ + description?: string +} + +export type TypeDefWithObjectOpts = { + description?: string +} + +/** + * A reference to a TypeDef. + */ +export type TypeDefID = string & {__TypeDefID: never} + +/** + * Distinguishes the different kinds of TypeDefs. + */ +export enum TypeDefKind { + + /** + * A boolean value + */ + Booleankind = "BooleanKind", + + /** + * An integer value + */ + Integerkind = "IntegerKind", + + /** + * A list of values all having the same type. + * + * Always paired with a ListTypeDef. + */ + Listkind = "ListKind", + + /** + * A named type defined in the GraphQL schema, with fields and functions. + * + * Always paired with an ObjectTypeDef. + */ + Objectkind = "ObjectKind", + + /** + * A string value + */ + Stringkind = "StringKind", + + /** + * A special kind used to signify that no value is returned. + * + * This is used for functions that have no return value. The outer TypeDef + * specifying this Kind is always Optional, as the Void is never actually + * represented. + */ + Voidkind = "VoidKind", +} +/** + * The absense of a value. + * + * A Null Void is used as a placeholder for resolvers that do not return anything. + */ +export type Void = string & {__Void: never} + +export type __TypeEnumValuesOpts = { + includeDeprecated?: boolean +} + +export type __TypeFieldsOpts = { + includeDeprecated?: boolean +} + + + + + + + + +/** + * A directory whose contents persist across runs. + */ +export class CacheVolume extends BaseClient { + private readonly _id?: CacheVolumeID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: CacheVolumeID, + ) { + super(parent) + + this._id = _id + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } +} + + + +/** + * An OCI-compatible container, also known as a docker container. + */ +export class Container extends BaseClient { + private readonly _id?: ContainerID = undefined + private readonly _envVariable?: string = undefined + private readonly _export?: boolean = undefined + private readonly _imageRef?: string = undefined + private readonly _label?: string = undefined + private readonly _platform?: Platform = undefined + private readonly _publish?: string = undefined + private readonly _shellEndpoint?: string = undefined + private readonly _stderr?: string = undefined + private readonly _stdout?: string = undefined + private readonly _sync?: ContainerID = undefined + private readonly _user?: string = undefined + private readonly _workdir?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ContainerID, + _envVariable?: string, + _export?: boolean, + _imageRef?: string, + _label?: string, + _platform?: Platform, + _publish?: string, + _shellEndpoint?: string, + _stderr?: string, + _stdout?: string, + _sync?: ContainerID, + _user?: string, + _workdir?: string, + ) { + super(parent) + + this._id = _id + this._envVariable = _envVariable + this._export = _export + this._imageRef = _imageRef + this._label = _label + this._platform = _platform + this._publish = _publish + this._shellEndpoint = _shellEndpoint + this._stderr = _stderr + this._stdout = _stdout + this._sync = _sync + this._user = _user + this._workdir = _workdir + } + + /** + * A unique identifier for this container. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Turn the container into a Service. + * + * Be sure to set any exposed ports before this conversion. + */ + asService(): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "asService", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a File representing the container serialized to a tarball. + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + asTarball(opts?: ContainerAsTarballOpts): File { + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "asTarball", + args: { ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from a Dockerfile build. + * @param context Directory context used by the Dockerfile. + * @param opts.dockerfile Path to the Dockerfile to use. + * + * Default: './Dockerfile'. + * @param opts.buildArgs Additional build arguments. + * @param opts.target Target build stage to build. + * @param opts.secrets Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name] in the build container + * + * They can be accessed in the Dockerfile using the "secret" mount type + * and mount path /run/secrets/[secret-name] + * e.g. RUN --mount=type=secret,id=my-secret curl url?token=$(cat /run/secrets/my-secret)" + */ + build(context: Directory, opts?: ContainerBuildOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "build", + args: { context, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves default arguments for future commands. + */ + async defaultArgs(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultArgs", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a directory at the given path. + * + * Mounts are included. + * @param path The path of the directory to retrieve (e.g., "./src"). + */ + directory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves entrypoint to be prepended to the arguments of all commands. + */ + async entrypoint(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "entrypoint", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the value of the specified environment variable. + * @param name The name of the environment variable to retrieve (e.g., "PATH"). + */ + async envVariable(name: string): Promise { + if (this._envVariable) { + return this._envVariable + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "envVariable", + args: { name }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of environment variables passed to commands. + */ + async envVariables(): Promise { + type envVariables = { + name: string + value: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "envVariables", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new EnvVariable( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * EXPERIMENTAL API! Subject to change/removal at any time. + * + * experimentalWithAllGPUs configures all available GPUs on the host to be accessible to this container. + * This currently works for Nvidia devices only. + */ + experimentalWithAllGPUs(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "experimentalWithAllGPUs", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * EXPERIMENTAL API! Subject to change/removal at any time. + * + * experimentalWithGPU configures the provided list of devices to be accesible to this container. + * This currently works for Nvidia devices only. + */ + experimentalWithGPU(devices: string[]): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "experimentalWithGPU", + args: { devices }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Writes the container as an OCI tarball to the destination file path on the host for the specified platform variants. + * + * Return true on success. + * It can also publishes platform variants. + * @param path Host's destination path (e.g., "./tarball"). + * Path can be relative to the engine's workdir or absolute. + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the exported image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the exported image's layers. Defaults to OCI, which + * is largely compatible with most recent container runtimes, but Docker may be needed + * for older runtimes without OCI support. + */ + async export(path: string, opts?: ContainerExportOpts): Promise { + if (this._export) { + return this._export + } + + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path, ...opts, __metadata: metadata }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of exposed ports. + * + * This includes ports already exposed by the image, even if not + * explicitly added with dagger. + */ + async exposedPorts(): Promise { + type exposedPorts = { + description: string + port: number + protocol: NetworkProtocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "exposedPorts", + }, + { + operation: "description port protocol" + }, + ], + this.client + ) + + + return response.map( + (r) => new Port( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.port, + r.protocol, + ) + ) + } + + /** + * Retrieves a file at the given path. + * + * Mounts are included. + * @param path The path of the file to retrieve (e.g., "./README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from a pulled base image. + * @param address Image's address from its registry. + * + * Formatted as [host]/[user]/[repo]:[tag] (e.g., "docker.io/dagger/dagger:main"). + */ + from(address: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "from", + args: { address }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The unique image reference which can only be retrieved immediately after the 'Container.From' call. + */ + async imageRef(): Promise { + if (this._imageRef) { + return this._imageRef + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "imageRef", + }, + ], + this.client + ) + + + return response + } + + /** + * Reads the container from an OCI tarball. + * + * NOTE: this involves unpacking the tarball to an OCI store on the host at + * $XDG_CACHE_DIR/dagger/oci. This directory can be removed whenever you like. + * @param source File to read the container from. + * @param opts.tag Identifies the tag to import from the archive, if the archive bundles + * multiple tags. + */ + import_(source: File, opts?: ContainerImportOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "import", + args: { source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves the value of the specified label. + */ + async label(name: string): Promise { + if (this._label) { + return this._label + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "label", + args: { name }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of labels passed to container. + */ + async labels(): Promise { + type labels = { + name: string + value: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "labels", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new Label( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * Retrieves the list of paths where a directory is mounted. + */ + async mounts(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "mounts", + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a named sub-pipeline + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: ContainerPipelineOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The platform this container executes and publishes as. + */ + async platform(): Promise { + if (this._platform) { + return this._platform + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "platform", + }, + ], + this.client + ) + + + return response + } + + /** + * Publishes this container as a new image to the specified address. + * + * Publish returns a fully qualified ref. + * It can also publish platform variants. + * @param address Registry's address to publish the image to. + * + * Formatted as [host]/[user]/[repo]:[tag] (e.g. "docker.io/dagger/dagger:main"). + * @param opts.platformVariants Identifiers for other platform specific containers. + * Used for multi-platform image. + * @param opts.forcedCompression Force each layer of the published image to use the specified compression algorithm. + * If this is unset, then if a layer already has a compressed blob in the engine's + * cache, that will be used (this can result in a mix of compression algorithms for + * different layers). If this is unset and a layer has no compressed blob in the + * engine's cache, then it will be compressed using Gzip. + * @param opts.mediaTypes Use the specified media types for the published image's layers. Defaults to OCI, which + * is largely compatible with most recent registries, but Docker may be needed for older + * registries without OCI support. + */ + async publish(address: string, opts?: ContainerPublishOpts): Promise { + if (this._publish) { + return this._publish + } + + const metadata: Metadata = { + forcedCompression: { is_enum: true }, + mediaTypes: { is_enum: true }, + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "publish", + args: { address, ...opts, __metadata: metadata }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves this container's root filesystem. Mounts are not included. + */ + rootfs(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "rootfs", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Return a websocket endpoint that, if connected to, will start the container with a TTY streamed + * over the websocket. + * + * Primarily intended for internal use with the dagger CLI. + */ + async shellEndpoint(): Promise { + if (this._shellEndpoint) { + return this._shellEndpoint + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "shellEndpoint", + }, + ], + this.client + ) + + + return response + } + + /** + * The error stream of the last executed command. + * + * Will execute default command if none is set, or error if there's no default. + */ + async stderr(): Promise { + if (this._stderr) { + return this._stderr + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "stderr", + }, + ], + this.client + ) + + + return response + } + + /** + * The output stream of the last executed command. + * + * Will execute default command if none is set, or error if there's no default. + */ + async stdout(): Promise { + if (this._stdout) { + return this._stdout + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "stdout", + }, + ], + this.client + ) + + + return response + } + + /** + * Forces evaluation of the pipeline in the engine. + * + * It doesn't run the default command if no exec has been set. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves the user to be set for all commands. + */ + async user(): Promise { + if (this._user) { + return this._user + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "user", + }, + ], + this.client + ) + + + return response + } + + /** + * Configures default arguments for future commands. + * @param opts.args Arguments to prepend to future executions (e.g., ["-v", "--no-cache"]). + */ + withDefaultArgs(opts?: ContainerWithDefaultArgsOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withDefaultArgs", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a directory written at the given path. + * @param path Location of the written directory (e.g., "/tmp/directory"). + * @param directory Identifier of the directory to write + * @param opts.exclude Patterns to exclude in the written directory (e.g., ["node_modules/**", ".gitignore", ".git/"]). + * @param opts.include Patterns to include in the written directory (e.g., ["*.go", "go.mod", "go.sum"]). + * @param opts.owner A user:group to set for the directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withDirectory(path: string, directory: Directory, opts?: ContainerWithDirectoryOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withDirectory", + args: { path, directory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container but with a different command entrypoint. + * @param args Entrypoint to use for future executions (e.g., ["go", "run"]). + */ + withEntrypoint(args: string[]): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withEntrypoint", + args: { args }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the given environment variable. + * @param name The name of the environment variable (e.g., "HOST"). + * @param value The value of the environment variable. (e.g., "localhost"). + * @param opts.expand Replace ${VAR} or $VAR in the value according to the current environment + * variables defined in the container (e.g., "/opt/bin:$PATH"). + */ + withEnvVariable(name: string, value: string, opts?: ContainerWithEnvVariableOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withEnvVariable", + args: { name, value, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container after executing the specified command inside it. + * @param args Command to run instead of the container's default command (e.g., ["run", "main.go"]). + * + * If empty, the container's default command is used. + * @param opts.skipEntrypoint If the container has an entrypoint, ignore it for args rather than using it to wrap them. + * @param opts.stdin Content to write to the command's standard input before closing (e.g., "Hello world"). + * @param opts.redirectStdout Redirect the command's standard output to a file in the container (e.g., "/tmp/stdout"). + * @param opts.redirectStderr Redirect the command's standard error to a file in the container (e.g., "/tmp/stderr"). + * @param opts.experimentalPrivilegedNesting Provides dagger access to the executed command. + * + * Do not use this option unless you trust the command being executed. + * The command being executed WILL BE GRANTED FULL ACCESS TO YOUR HOST FILESYSTEM. + * @param opts.insecureRootCapabilities Execute the command with all root capabilities. This is similar to running a command + * with "sudo" or executing `docker run` with the `--privileged` flag. Containerization + * does not provide any security guarantees when using this option. It should only be used + * when absolutely necessary and only with trusted commands. + */ + withExec(args: string[], opts?: ContainerWithExecOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withExec", + args: { args, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Expose a network port. + * + * Exposed ports serve two purposes: + * - For health checks and introspection, when running services + * - For setting the EXPOSE OCI field when publishing the container + * @param port Port number to expose + * @param opts.protocol Transport layer network protocol + * @param opts.description Optional port description + */ + withExposedPort(port: number, opts?: ContainerWithExposedPortOpts): Container { + const metadata: Metadata = { + protocol: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withExposedPort", + args: { port, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the contents of the given file copied to the given path. + * @param path Location of the copied file (e.g., "/tmp/file.txt"). + * @param source Identifier of the file to copy. + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + * @param opts.owner A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withFile(path: string, source: File, opts?: ContainerWithFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Indicate that subsequent operations should be featured more prominently in + * the UI. + */ + withFocus(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withFocus", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus the given label. + * @param name The name of the label (e.g., "org.opencontainers.artifact.created"). + * @param value The value of the label (e.g., "2023-01-01T00:00:00Z"). + */ + withLabel(name: string, value: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withLabel", + args: { name, value }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a cache volume mounted at the given path. + * @param path Location of the cache directory (e.g., "/cache/node_modules"). + * @param cache Identifier of the cache volume to mount. + * @param opts.source Identifier of the directory to use as the cache volume's root. + * @param opts.sharing Sharing mode of the cache volume. + * @param opts.owner A user:group to set for the mounted cache directory. + * + * Note that this changes the ownership of the specified mount along with the + * initial filesystem provided by source (if any). It does not have any effect + * if/when the cache has already been created. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedCache(path: string, cache: CacheVolume, opts?: ContainerWithMountedCacheOpts): Container { + const metadata: Metadata = { + sharing: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedCache", + args: { path, cache, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a directory mounted at the given path. + * @param path Location of the mounted directory (e.g., "/mnt/directory"). + * @param source Identifier of the mounted directory. + * @param opts.owner A user:group to set for the mounted directory and its contents. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedDirectory(path: string, source: Directory, opts?: ContainerWithMountedDirectoryOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedDirectory", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a file mounted at the given path. + * @param path Location of the mounted file (e.g., "/tmp/file.txt"). + * @param source Identifier of the mounted file. + * @param opts.owner A user or user:group to set for the mounted file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withMountedFile(path: string, source: File, opts?: ContainerWithMountedFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a secret mounted into a file at the given path. + * @param path Location of the secret file (e.g., "/tmp/secret.txt"). + * @param source Identifier of the secret to mount. + * @param opts.owner A user:group to set for the mounted secret. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + * @param opts.mode Permission given to the mounted secret (e.g., 0600). + * This option requires an owner to be set to be active. + * + * Default: 0400. + */ + withMountedSecret(path: string, source: Secret, opts?: ContainerWithMountedSecretOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedSecret", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a temporary directory mounted at the given path. + * @param path Location of the temporary directory (e.g., "/tmp/temp_dir"). + */ + withMountedTemp(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withMountedTemp", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a new file written at the given path. + * @param path Location of the written file (e.g., "/tmp/file.txt"). + * @param opts.contents Content of the file to write (e.g., "Hello world!"). + * @param opts.permissions Permission given to the written file (e.g., 0600). + * + * Default: 0644. + * @param opts.owner A user:group to set for the file. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withNewFile(path: string, opts?: ContainerWithNewFileOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewFile", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a registry authentication for a given address. + * @param address Registry's address to bind the authentication to. + * Formatted as [host]/[user]/[repo]:[tag] (e.g. docker.io/dagger/dagger:main). + * @param username The username of the registry's account (e.g., "Dagger"). + * @param secret The API key, password or token to authenticate to this registry. + */ + withRegistryAuth(address: string, username: string, secret: Secret): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withRegistryAuth", + args: { address, username, secret }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Initializes this container from this DirectoryID. + */ + withRootfs(directory: Directory): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withRootfs", + args: { directory }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus an env variable containing the given secret. + * @param name The name of the secret variable (e.g., "API_SECRET"). + * @param secret The identifier of the secret value. + */ + withSecretVariable(name: string, secret: Secret): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withSecretVariable", + args: { name, secret }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Establish a runtime dependency on a service. + * + * The service will be started automatically when needed and detached when it is + * no longer needed, executing the default command if none is set. + * + * The service will be reachable from the container via the provided hostname alias. + * + * The service dependency will also convey to any files or directories produced by the container. + * @param alias A name that can be used to reach the service from the container + * @param service Identifier of the service container + */ + withServiceBinding(alias: string, service: Service): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withServiceBinding", + args: { alias, service }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container plus a socket forwarded to the given Unix socket path. + * @param path Location of the forwarded Unix socket (e.g., "/tmp/socket"). + * @param source Identifier of the socket to forward. + * @param opts.owner A user:group to set for the mounted socket. + * + * The user and group can either be an ID (1000:1000) or a name (foo:bar). + * + * If the group is omitted, it defaults to the same as the user. + */ + withUnixSocket(path: string, source: Socket, opts?: ContainerWithUnixSocketOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withUnixSocket", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a different command user. + * @param name The user to set (e.g., "root"). + */ + withUser(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withUser", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a different working directory. + * @param path The path to set as the working directory (e.g., "/app"). + */ + withWorkdir(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withWorkdir", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container minus the given environment variable. + * @param name The name of the environment variable (e.g., "HOST"). + */ + withoutEnvVariable(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutEnvVariable", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Unexpose a previously exposed port. + * @param port Port number to unexpose + * @param opts.protocol Port protocol to unexpose + */ + withoutExposedPort(port: number, opts?: ContainerWithoutExposedPortOpts): Container { + const metadata: Metadata = { + protocol: { is_enum: true }, + } + + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutExposedPort", + args: { port, ...opts, __metadata: metadata }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Indicate that subsequent operations should not be featured more prominently + * in the UI. + * + * This is the initial state of all containers. + */ + withoutFocus(): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutFocus", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container minus the given environment label. + * @param name The name of the label to remove (e.g., "org.opencontainers.artifact.created"). + */ + withoutLabel(name: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutLabel", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container after unmounting everything at the given path. + * @param path Location of the cache directory (e.g., "/cache/node_modules"). + */ + withoutMount(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutMount", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container without the registry authentication of a given address. + * @param address Registry's address to remove the authentication from. + * Formatted as [host]/[user]/[repo]:[tag] (e.g. docker.io/dagger/dagger:main). + */ + withoutRegistryAuth(address: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutRegistryAuth", + args: { address }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this container with a previously added Unix socket removed. + * @param path Location of the socket to remove (e.g., "/tmp/socket"). + */ + withoutUnixSocket(path: string): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutUnixSocket", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves the working directory for all commands. + */ + async workdir(): Promise { + if (this._workdir) { + return this._workdir + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "workdir", + }, + ], + this.client + ) + + + return response + } + + /** + * Call the provided function with current Container. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Container) => Container) { + return arg(this) + } +} + + + + + +/** + * A directory. + */ +export class Directory extends BaseClient { + private readonly _id?: DirectoryID = undefined + private readonly _export?: boolean = undefined + private readonly _sync?: DirectoryID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: DirectoryID, + _export?: boolean, + _sync?: DirectoryID, + ) { + super(parent) + + this._id = _id + this._export = _export + this._sync = _sync + } + + /** + * The content-addressed identifier of the directory. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Load the directory as a Dagger module + * @param opts.sourceSubpath An optional subpath of the directory which contains the module's source + * code. + * + * This is needed when the module code is in a subdirectory but requires + * parent directories to be loaded in order to execute. For example, the + * module source code may need a go.mod, project.toml, package.json, etc. file + * from a parent directory. + * + * If not set, the module source code is loaded from the root of the + * directory. + */ + asModule(opts?: DirectoryAsModuleOpts): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "asModule", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Gets the difference between this directory and an another directory. + * @param other Identifier of the directory to compare. + */ + diff(other: Directory): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "diff", + args: { other }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves a directory at the given path. + * @param path Location of the directory to retrieve (e.g., "/src"). + */ + directory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Builds a new Docker container from this directory. + * @param opts.dockerfile Path to the Dockerfile to use (e.g., "frontend.Dockerfile"). + * + * Defaults: './Dockerfile'. + * @param opts.platform The platform to build. + * @param opts.buildArgs Build arguments to use in the build. + * @param opts.target Target build stage to build. + * @param opts.secrets Secrets to pass to the build. + * + * They will be mounted at /run/secrets/[secret-name]. + */ + dockerBuild(opts?: DirectoryDockerBuildOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "dockerBuild", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a list of files and directories at the given path. + * @param opts.path Location of the directory to look at (e.g., "/src"). + */ + async entries(opts?: DirectoryEntriesOpts): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "entries", + args: { ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Writes the contents of the directory to a path on the host. + * @param path Location of the copied directory (e.g., "logs/"). + */ + async export(path: string): Promise { + if (this._export) { + return this._export + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a file at the given path. + * @param path Location of the file to retrieve (e.g., "README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a list of files and directories that matche the given pattern. + * @param pattern Pattern to match (e.g., "*.md"). + */ + async glob(pattern: string): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "glob", + args: { pattern }, + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a named sub-pipeline + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: DirectoryPipelineOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Force evaluation in the engine. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves this directory plus a directory written at the given path. + * @param path Location of the written directory (e.g., "/src/"). + * @param directory Identifier of the directory to copy. + * @param opts.exclude Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + * @param opts.include Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + withDirectory(path: string, directory: Directory, opts?: DirectoryWithDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withDirectory", + args: { path, directory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus the contents of the given file copied to the given path. + * @param path Location of the copied file (e.g., "/file.txt"). + * @param source Identifier of the file to copy. + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + withFile(path: string, source: File, opts?: DirectoryWithFileOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withFile", + args: { path, source, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus a new directory created at the given path. + * @param path Location of the directory created (e.g., "/logs"). + * @param opts.permissions Permission granted to the created directory (e.g., 0777). + * + * Default: 0755. + */ + withNewDirectory(path: string, opts?: DirectoryWithNewDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewDirectory", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory plus a new file written at the given path. + * @param path Location of the written file (e.g., "/file.txt"). + * @param contents Content of the written file (e.g., "Hello world!"). + * @param opts.permissions Permission given to the copied file (e.g., 0600). + * + * Default: 0644. + */ + withNewFile(path: string, contents: string, opts?: DirectoryWithNewFileOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withNewFile", + args: { path, contents, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with all file/dir timestamps set to the given time. + * @param timestamp Timestamp to set dir/files in. + * + * Formatted in seconds following Unix epoch (e.g., 1672531199). + */ + withTimestamps(timestamp: number): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withTimestamps", + args: { timestamp }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with the directory at the given path removed. + * @param path Location of the directory to remove (e.g., ".github/"). + */ + withoutDirectory(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutDirectory", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Retrieves this directory with the file at the given path removed. + * @param path Location of the file to remove (e.g., "/file.txt"). + */ + withoutFile(path: string): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "withoutFile", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Directory. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Directory) => Directory) { + return arg(this) + } +} + + + +/** + * A simple key value object that represents an environment variable. + */ +export class EnvVariable extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: string, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The environment variable name. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The environment variable value. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + +/** + * A definition of a field on a custom object defined in a Module. + * A field on an object has a static value, as opposed to a function on an + * object whose value is computed by invoking code (and can accept arguments). + */ +export class FieldTypeDef extends BaseClient { + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _name?: string, + ) { + super(parent) + + this._description = _description + this._name = _name + } + + /** + * A doc string for the field, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the field in the object + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type of the field + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * A file. + */ +export class File extends BaseClient { + private readonly _id?: FileID = undefined + private readonly _contents?: string = undefined + private readonly _export?: boolean = undefined + private readonly _size?: number = undefined + private readonly _sync?: FileID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FileID, + _contents?: string, + _export?: boolean, + _size?: number, + _sync?: FileID, + ) { + super(parent) + + this._id = _id + this._contents = _contents + this._export = _export + this._size = _size + this._sync = _sync + } + + /** + * Retrieves the content-addressed identifier of the file. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the contents of the file. + */ + async contents(): Promise { + if (this._contents) { + return this._contents + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "contents", + }, + ], + this.client + ) + + + return response + } + + /** + * Writes the file to a file path on the host. + * @param path Location of the written directory (e.g., "output.txt"). + * @param opts.allowParentDirPath If allowParentDirPath is true, the path argument can be a directory path, in which case + * the file will be created in that directory. + */ + async export(path: string, opts?: FileExportOpts): Promise { + if (this._export) { + return this._export + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "export", + args: { path, ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Gets the size of the file, in bytes. + */ + async size(): Promise { + if (this._size) { + return this._size + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "size", + }, + ], + this.client + ) + + + return response + } + + /** + * Force evaluation in the engine. + */ + async sync(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "sync", + }, + ], + this.client + ) + + return this + } + + /** + * Retrieves this file with its created/modified timestamps set to the given time. + * @param timestamp Timestamp to set dir/files in. + * + * Formatted in seconds following Unix epoch (e.g., 1672531199). + */ + withTimestamps(timestamp: number): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "withTimestamps", + args: { timestamp }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current File. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: File) => File) { + return arg(this) + } +} + + + + + +/** + * Function represents a resolver provided by a Module. + * + * A function always evaluates against a parent object and is given a set of + * named arguments. + */ +export class Function_ extends BaseClient { + private readonly _id?: FunctionID = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FunctionID, + _description?: string, + _name?: string, + ) { + super(parent) + + this._id = _id + this._description = _description + this._name = _name + } + + /** + * The ID of the function + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Arguments accepted by this function, if any + */ + async args(): Promise { + type args = { + id: FunctionArgID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "args", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new FunctionArg( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * A doc string for the function, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the function + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type returned by this function + */ + returnType(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "returnType", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns the function with the provided argument + * @param name The name of the argument + * @param typeDef The type of the argument + * @param opts.description A doc string for the argument, if any + * @param opts.defaultValue A default value to use for this argument if not explicitly set by the caller, if any + */ + withArg(name: string, typeDef: TypeDef, opts?: FunctionWithArgOpts): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "withArg", + args: { name, typeDef, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns the function with the doc string + */ + withDescription(description: string): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "withDescription", + args: { description }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Function. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Function_) => Function_) { + return arg(this) + } +} + +/** + * An argument accepted by a function. + * + * This is a specification for an argument at function definition time, not an + * argument passed at function call time. + */ +export class FunctionArg extends BaseClient { + private readonly _id?: FunctionArgID = undefined + private readonly _defaultValue?: JSON = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: FunctionArgID, + _defaultValue?: JSON, + _description?: string, + _name?: string, + ) { + super(parent) + + this._id = _id + this._defaultValue = _defaultValue + this._description = _description + this._name = _name + } + + /** + * The ID of the argument + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * A default value to use for this argument when not explicitly set by the caller, if any + */ + async defaultValue(): Promise { + if (this._defaultValue) { + return this._defaultValue + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultValue", + }, + ], + this.client + ) + + + return response + } + + /** + * A doc string for the argument, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the argument + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The type of the argument + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + + + +export class FunctionCall extends BaseClient { + private readonly _name?: string = undefined + private readonly _parent?: JSON = undefined + private readonly _parentName?: string = undefined + private readonly _returnValue?: Void = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _parent?: JSON, + _parentName?: string, + _returnValue?: Void, + ) { + super(parent) + + this._name = _name + this._parent = _parent + this._parentName = _parentName + this._returnValue = _returnValue + } + + /** + * The argument values the function is being invoked with. + */ + async inputArgs(): Promise { + type inputArgs = { + name: string + value: JSON + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "inputArgs", + }, + { + operation: "name value" + }, + ], + this.client + ) + + + return response.map( + (r) => new FunctionCallArgValue( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.name, + r.value, + ) + ) + } + + /** + * The name of the function being called. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of the parent object of the function being called. + * If the function is "top-level" to the module, this is always an empty object. + */ + async parent(): Promise { + if (this._parent) { + return this._parent + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "parent", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the parent object of the function being called. + * If the function is "top-level" to the module, this is the name of the module. + */ + async parentName(): Promise { + if (this._parentName) { + return this._parentName + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "parentName", + }, + ], + this.client + ) + + + return response + } + + /** + * Set the return value of the function call to the provided value. + * The value should be a string of the JSON serialization of the return value. + */ + async returnValue(value: JSON): Promise { + if (this._returnValue) { + return this._returnValue + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "returnValue", + args: { value }, + }, + ], + this.client + ) + + + return response + } +} + + +export class FunctionCallArgValue extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: JSON = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: JSON, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The name of the argument. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of the argument represented as a string of the JSON serialization. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class GeneratedCode extends BaseClient { + private readonly _id?: GeneratedCodeID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: GeneratedCodeID, + ) { + super(parent) + + this._id = _id + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * The directory containing the generated code + */ + code(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "code", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * List of paths to mark generated in version control (i.e. .gitattributes) + */ + async vcsGeneratedPaths(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "vcsGeneratedPaths", + }, + ], + this.client + ) + + + return response + } + + /** + * List of paths to ignore in version control (i.e. .gitignore) + */ + async vcsIgnoredPaths(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "vcsIgnoredPaths", + }, + ], + this.client + ) + + + return response + } + + /** + * Set the list of paths to mark generated in version control + */ + withVCSGeneratedPaths(paths: string[]): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "withVCSGeneratedPaths", + args: { paths }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Set the list of paths to ignore in version control + */ + withVCSIgnoredPaths(paths: string[]): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "withVCSIgnoredPaths", + args: { paths }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current GeneratedCode. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: GeneratedCode) => GeneratedCode) { + return arg(this) + } +} + + + +/** + * A git ref (tag, branch or commit). + */ +export class GitRef extends BaseClient { + private readonly _commit?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _commit?: string, + ) { + super(parent) + + this._commit = _commit + } + + /** + * The resolved commit id at this ref. + */ + async commit(): Promise { + if (this._commit) { + return this._commit + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "commit", + }, + ], + this.client + ) + + + return response + } + + /** + * The filesystem tree at this ref. + */ + tree(opts?: GitRefTreeOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "tree", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * A git repository. + */ +export class GitRepository extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * Returns details on one branch. + * @param name Branch's name (e.g., "main"). + */ + branch(name: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "branch", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns details on one commit. + * @param id Identifier of the commit (e.g., "b6315d8f2810962c601af73f86831f6866ea798b"). + */ + commit(id: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "commit", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns details on one tag. + * @param name Tag's name (e.g., "v0.3.9"). + */ + tag(name: string): GitRef { + return new GitRef({ + queryTree: [ + ...this._queryTree, + { + operation: "tag", + args: { name }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + +/** + * Information about the host execution environment. + */ +export class Host extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * Accesses a directory on the host. + * @param path Location of the directory to access (e.g., "."). + * @param opts.exclude Exclude artifacts that match the given pattern (e.g., ["node_modules/", ".git*"]). + * @param opts.include Include only artifacts that match the given pattern (e.g., ["app/", "package.*"]). + */ + directory(path: string, opts?: HostDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { path, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Accesses a file on the host. + * @param path Location of the file to retrieve (e.g., "README.md"). + */ + file(path: string): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a service that forwards traffic to a specified address via the host. + * @param ports Ports to expose via the service, forwarding through the host network. + * + * If a port's frontend is unspecified or 0, it defaults to the same as the + * backend port. + * + * An empty set of ports is not valid; an error will be returned. + * @param opts.host Upstream host to forward traffic to. + */ + service(ports: PortForward[], opts?: HostServiceOpts): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "service", + args: { ports, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets a secret given a user-defined name and the file path on the host, and returns the secret. + * The file is limited to a size of 512000 bytes. + * @param name The user defined name for this secret. + * @param path Location of the file to set as a secret. + */ + setSecretFile(name: string, path: string): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "setSecretFile", + args: { name, path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a tunnel that forwards traffic from the host to a service. + * @param service Service to send traffic from the tunnel. + * @param opts.native Map each service port to the same port on the host, as if the service were + * running natively. + * + * Note: enabling may result in port conflicts. + * @param opts.ports Configure explicit port forwarding rules for the tunnel. + * + * If a port's frontend is unspecified or 0, a random port will be chosen by + * the host. + * + * If no ports are given, all of the service's ports are forwarded. If native + * is true, each port maps to the same port on the host. If native is false, + * each port maps to a random port chosen by the host. + * + * If ports are given and native is true, the ports are additive. + */ + tunnel(service: Service, opts?: HostTunnelOpts): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "tunnel", + args: { service, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Accesses a Unix socket on the host. + * @param path Location of the Unix socket (e.g., "/var/run/docker.sock"). + */ + unixSocket(path: string): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "unixSocket", + args: { path }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + + + + + + + + + + +/** + * A simple key value object that represents a label. + */ +export class Label extends BaseClient { + private readonly _name?: string = undefined + private readonly _value?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _value?: string, + ) { + super(parent) + + this._name = _name + this._value = _value + } + + /** + * The label name. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The label value. + */ + async value(): Promise { + if (this._value) { + return this._value + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "value", + }, + ], + this.client + ) + + + return response + } +} + +/** + * A definition of a list type in a Module. + */ +export class ListTypeDef extends BaseClient { + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + ) { + super(parent) + + } + + /** + * The type of the elements in the list + */ + elementTypeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "elementTypeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } +} + + +export class Module_ extends BaseClient { + private readonly _id?: ModuleID = undefined + private readonly _description?: string = undefined + private readonly _name?: string = undefined + private readonly _sdk?: string = undefined + private readonly _serve?: Void = undefined + private readonly _sourceDirectorySubPath?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ModuleID, + _description?: string, + _name?: string, + _sdk?: string, + _serve?: Void, + _sourceDirectorySubPath?: string, + ) { + super(parent) + + this._id = _id + this._description = _description + this._name = _name + this._sdk = _sdk + this._serve = _serve + this._sourceDirectorySubPath = _sourceDirectorySubPath + } + + /** + * The ID of the module + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Modules used by this module + */ + async dependencies(): Promise { + type dependencies = { + id: ModuleID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencies", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new Module_( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The dependencies as configured by the module + */ + async dependencyConfig(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencyConfig", + }, + ], + this.client + ) + + + return response + } + + /** + * The doc string of the module, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The code generated by the SDK's runtime + */ + generatedCode(): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "generatedCode", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The name of the module + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * Objects served by this module + */ + async objects(): Promise { + type objects = { + id: TypeDefID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "objects", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new TypeDef( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The SDK used by this module. Either a name of a builtin SDK or a module ref pointing to the SDK's implementation. + */ + async sdk(): Promise { + if (this._sdk) { + return this._sdk + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sdk", + }, + ], + this.client + ) + + + return response + } + + /** + * Serve a module's API in the current session. + * Note: this can only be called once per session. + * In the future, it could return a stream or service to remove the side effect. + */ + async serve(): Promise { + if (this._serve) { + return this._serve + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "serve", + }, + ], + this.client + ) + + + return response + } + + /** + * The directory containing the module's source code + */ + sourceDirectory(): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "sourceDirectory", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The module's subpath within the source directory + */ + async sourceDirectorySubPath(): Promise { + if (this._sourceDirectorySubPath) { + return this._sourceDirectorySubPath + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sourceDirectorySubPath", + }, + ], + this.client + ) + + + return response + } + + /** + * This module plus the given Object type and associated functions + */ + withObject(object: TypeDef): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "withObject", + args: { object }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Module. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Module_) => Module_) { + return arg(this) + } +} + +/** + * Static configuration for a module (e.g. parsed contents of dagger.json) + */ +export class ModuleConfig extends BaseClient { + private readonly _name?: string = undefined + private readonly _root?: string = undefined + private readonly _sdk?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _name?: string, + _root?: string, + _sdk?: string, + ) { + super(parent) + + this._name = _name + this._root = _root + this._sdk = _sdk + } + + /** + * Modules that this module depends on. + */ + async dependencies(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "dependencies", + }, + ], + this.client + ) + + + return response + } + + /** + * Exclude these file globs when loading the module root. + */ + async exclude(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "exclude", + }, + ], + this.client + ) + + + return response + } + + /** + * Include only these file globs when loading the module root. + */ + async include(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "include", + }, + ], + this.client + ) + + + return response + } + + /** + * The name of the module. + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } + + /** + * The root directory of the module's project, which may be above the module source code. + */ + async root(): Promise { + if (this._root) { + return this._root + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "root", + }, + ], + this.client + ) + + + return response + } + + /** + * Either the name of a built-in SDK ('go', 'python', etc.) OR a module reference pointing to the SDK's module implementation. + */ + async sdk(): Promise { + if (this._sdk) { + return this._sdk + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "sdk", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A definition of a custom object defined in a Module. + */ +export class ObjectTypeDef extends BaseClient { + private readonly _description?: string = undefined + private readonly _name?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _name?: string, + ) { + super(parent) + + this._description = _description + this._name = _name + } + + /** + * The doc string for the object, if any + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * Static fields defined on this object, if any + */ + async fields(): Promise { + type fields = { + description: string + name: string + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "fields", + }, + { + operation: "description name" + }, + ], + this.client + ) + + + return response.map( + (r) => new FieldTypeDef( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.name, + ) + ) + } + + /** + * Functions defined on this object, if any + */ + async functions(): Promise { + type functions = { + id: FunctionID + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "functions", + }, + { + operation: "id" + }, + ], + this.client + ) + + + return response.map( + (r) => new Function_( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.id, + ) + ) + } + + /** + * The name of the object + */ + async name(): Promise { + if (this._name) { + return this._name + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "name", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A port exposed by a container. + */ +export class Port extends BaseClient { + private readonly _description?: string = undefined + private readonly _port?: number = undefined + private readonly _protocol?: NetworkProtocol = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _description?: string, + _port?: number, + _protocol?: NetworkProtocol, + ) { + super(parent) + + this._description = _description + this._port = _port + this._protocol = _protocol + } + + /** + * The port description. + */ + async description(): Promise { + if (this._description) { + return this._description + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "description", + }, + ], + this.client + ) + + + return response + } + + /** + * The port number. + */ + async port(): Promise { + if (this._port) { + return this._port + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "port", + }, + ], + this.client + ) + + + return response + } + + /** + * The transport layer network protocol. + */ + async protocol(): Promise { + if (this._protocol) { + return this._protocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "protocol", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class Client extends BaseClient { + private readonly _checkVersionCompatibility?: boolean = undefined + private readonly _defaultPlatform?: Platform = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _checkVersionCompatibility?: boolean, + _defaultPlatform?: Platform, + ) { + super(parent) + + this._checkVersionCompatibility = _checkVersionCompatibility + this._defaultPlatform = _defaultPlatform + } + + /** + * Constructs a cache volume for a given cache key. + * @param key A string identifier to target this cache volume (e.g., "modules-cache"). + */ + cacheVolume(key: string): CacheVolume { + return new CacheVolume({ + queryTree: [ + ...this._queryTree, + { + operation: "cacheVolume", + args: { key }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Checks if the current Dagger Engine is compatible with an SDK's required version. + * @param version The SDK's required version. + */ + async checkVersionCompatibility(version: string): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "checkVersionCompatibility", + args: { version }, + }, + ], + this.client + ) + + + return response + } + + /** + * Creates a scratch container or loads one by ID. + * + * Optional platform argument initializes new containers to execute and publish + * as that platform. Platform defaults to that of the builder's host. + */ + container(opts?: ClientContainerOpts): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "container", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The FunctionCall context that the SDK caller is currently executing in. + * If the caller is not currently executing in a function, this will return + * an error. + */ + currentFunctionCall(): FunctionCall { + return new FunctionCall({ + queryTree: [ + ...this._queryTree, + { + operation: "currentFunctionCall", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The module currently being served in the session, if any. + */ + currentModule(): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "currentModule", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The default platform of the builder. + */ + async defaultPlatform(): Promise { + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "defaultPlatform", + }, + ], + this.client + ) + + + return response + } + + /** + * Creates an empty directory or loads one by ID. + */ + directory(opts?: ClientDirectoryOpts): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "directory", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a file by ID. + * @deprecated Use loadFileFromID instead. + */ + file(id: FileID): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "file", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a function. + */ + function_(name: string, returnType: TypeDef): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "function", + args: { name, returnType }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a code generation result, given a directory containing the generated + * code. + */ + generatedCode(code: Directory): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "generatedCode", + args: { code }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Queries a git repository. + * @param url Url of the git repository. + * Can be formatted as https://{host}/{owner}/{repo}, git@{host}:{owner}/{repo} + * Suffix ".git" is optional. + * @param opts.keepGitDir Set to true to keep .git directory. + * @param opts.sshKnownHosts Set SSH known hosts + * @param opts.sshAuthSocket Set SSH auth socket + * @param opts.experimentalServiceHost A service which must be started before the repo is fetched. + */ + git(url: string, opts?: ClientGitOpts): GitRepository { + return new GitRepository({ + queryTree: [ + ...this._queryTree, + { + operation: "git", + args: { url, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Queries the host environment. + */ + host(): Host { + return new Host({ + queryTree: [ + ...this._queryTree, + { + operation: "host", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a file containing an http remote url content. + * @param url HTTP url to get the content from (e.g., "https://docs.dagger.io"). + * @param opts.experimentalServiceHost A service which must be started before the URL is fetched. + */ + http(url: string, opts?: ClientHttpOpts): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "http", + args: { url, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a CacheVolume from its ID. + */ + loadCacheVolumeFromID(id: CacheVolumeID): CacheVolume { + return new CacheVolume({ + queryTree: [ + ...this._queryTree, + { + operation: "loadCacheVolumeFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a container from an ID. + */ + loadContainerFromID(id: ContainerID): Container { + return new Container({ + queryTree: [ + ...this._queryTree, + { + operation: "loadContainerFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Directory from its ID. + */ + loadDirectoryFromID(id: DirectoryID): Directory { + return new Directory({ + queryTree: [ + ...this._queryTree, + { + operation: "loadDirectoryFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a File from its ID. + */ + loadFileFromID(id: FileID): File { + return new File({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFileFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a function argument by ID. + */ + loadFunctionArgFromID(id: FunctionArgID): FunctionArg { + return new FunctionArg({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFunctionArgFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a function by ID. + */ + loadFunctionFromID(id: FunctionID): Function_ { + return new Function_({ + queryTree: [ + ...this._queryTree, + { + operation: "loadFunctionFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a GeneratedCode by ID. + */ + loadGeneratedCodeFromID(id: GeneratedCodeID): GeneratedCode { + return new GeneratedCode({ + queryTree: [ + ...this._queryTree, + { + operation: "loadGeneratedCodeFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a module by ID. + */ + loadModuleFromID(id: ModuleID): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "loadModuleFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Secret from its ID. + */ + loadSecretFromID(id: SecretID): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "loadSecretFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a service from ID. + */ + loadServiceFromID(id: ServiceID): Service { + return new Service({ + queryTree: [ + ...this._queryTree, + { + operation: "loadServiceFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a Socket from its ID. + */ + loadSocketFromID(id: SocketID): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "loadSocketFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load a TypeDef by ID. + */ + loadTypeDefFromID(id: TypeDefID): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "loadTypeDefFromID", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a new module. + */ + module_(): Module_ { + return new Module_({ + queryTree: [ + ...this._queryTree, + { + operation: "module", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Load the static configuration for a module from the given source directory and optional subpath. + */ + moduleConfig(sourceDirectory: Directory, opts?: ClientModuleConfigOpts): ModuleConfig { + return new ModuleConfig({ + queryTree: [ + ...this._queryTree, + { + operation: "moduleConfig", + args: { sourceDirectory, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Creates a named sub-pipeline. + * @param name Pipeline name. + * @param opts.description Pipeline description. + * @param opts.labels Pipeline labels. + */ + pipeline(name: string, opts?: ClientPipelineOpts): Client { + return new Client({ + queryTree: [ + ...this._queryTree, + { + operation: "pipeline", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a secret from its ID. + * @deprecated Use loadSecretFromID instead + */ + secret(id: SecretID): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "secret", + args: { id }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets a secret given a user defined name to its plaintext and returns the secret. + * The plaintext value is limited to a size of 128000 bytes. + * @param name The user defined name for this secret + * @param plaintext The plaintext of the secret + */ + setSecret(name: string, plaintext: string): Secret { + return new Secret({ + queryTree: [ + ...this._queryTree, + { + operation: "setSecret", + args: { name, plaintext }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Loads a socket by its ID. + * @deprecated Use loadSocketFromID instead. + */ + socket(opts?: ClientSocketOpts): Socket { + return new Socket({ + queryTree: [ + ...this._queryTree, + { + operation: "socket", + args: { ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Create a new TypeDef. + */ + typeDef(): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "typeDef", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current Client. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: Client) => Client) { + return arg(this) + } +} + +/** + * A reference to a secret value, which can be handled more safely than the value itself. + */ +export class Secret extends BaseClient { + private readonly _id?: SecretID = undefined + private readonly _plaintext?: string = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: SecretID, + _plaintext?: string, + ) { + super(parent) + + this._id = _id + this._plaintext = _plaintext + } + + /** + * The identifier for this secret. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * The value of this secret. + */ + async plaintext(): Promise { + if (this._plaintext) { + return this._plaintext + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "plaintext", + }, + ], + this.client + ) + + + return response + } +} + + + + +export class Service extends BaseClient { + private readonly _id?: ServiceID = undefined + private readonly _endpoint?: string = undefined + private readonly _hostname?: string = undefined + private readonly _start?: ServiceID = undefined + private readonly _stop?: ServiceID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: ServiceID, + _endpoint?: string, + _hostname?: string, + _start?: ServiceID, + _stop?: ServiceID, + ) { + super(parent) + + this._id = _id + this._endpoint = _endpoint + this._hostname = _hostname + this._start = _start + this._stop = _stop + } + + /** + * A unique identifier for this service. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves an endpoint that clients can use to reach this container. + * + * If no port is specified, the first exposed port is used. If none exist an error is returned. + * + * If a scheme is specified, a URL is returned. Otherwise, a host:port pair is returned. + * @param opts.port The exposed port number for the endpoint + * @param opts.scheme Return a URL with the given scheme, eg. http for http:// + */ + async endpoint(opts?: ServiceEndpointOpts): Promise { + if (this._endpoint) { + return this._endpoint + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "endpoint", + args: { ...opts }, + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves a hostname which can be used by clients to reach this container. + */ + async hostname(): Promise { + if (this._hostname) { + return this._hostname + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "hostname", + }, + ], + this.client + ) + + + return response + } + + /** + * Retrieves the list of ports provided by the service. + */ + async ports(): Promise { + type ports = { + description: string + port: number + protocol: NetworkProtocol + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "ports", + }, + { + operation: "description port protocol" + }, + ], + this.client + ) + + + return response.map( + (r) => new Port( + { + queryTree: this.queryTree, + host: this.clientHost, + sessionToken: this.sessionToken, + }, + r.description, + r.port, + r.protocol, + ) + ) + } + + /** + * Start the service and wait for its health checks to succeed. + * + * Services bound to a Container do not need to be manually started. + */ + async start(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "start", + }, + ], + this.client + ) + + return this + } + + /** + * Stop the service. + */ + async stop(): Promise { + await computeQuery( + [ + ...this._queryTree, + { + operation: "stop", + }, + ], + this.client + ) + + return this + } +} + + + + +export class Socket extends BaseClient { + private readonly _id?: SocketID = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: SocketID, + ) { + super(parent) + + this._id = _id + } + + /** + * The content-addressed identifier of the socket. + */ + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } +} + + + + + +/** + * A definition of a parameter or return type in a Module. + */ +export class TypeDef extends BaseClient { + private readonly _id?: TypeDefID = undefined + private readonly _kind?: TypeDefKind = undefined + private readonly _optional?: boolean = undefined + + /** + * Constructor is used for internal usage only, do not create object from it. + */ + constructor( + parent?: { queryTree?: QueryTree[], host?: string, sessionToken?: string }, + _id?: TypeDefID, + _kind?: TypeDefKind, + _optional?: boolean, + ) { + super(parent) + + this._id = _id + this._kind = _kind + this._optional = _optional + } + async id(): Promise { + if (this._id) { + return this._id + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "id", + }, + ], + this.client + ) + + + return response + } + + /** + * If kind is LIST, the list-specific type definition. + * If kind is not LIST, this will be null. + */ + asList(): ListTypeDef { + return new ListTypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "asList", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * If kind is OBJECT, the object-specific type definition. + * If kind is not OBJECT, this will be null. + */ + asObject(): ObjectTypeDef { + return new ObjectTypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "asObject", + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * The kind of type this is (e.g. primitive, list, object) + */ + async kind(): Promise { + if (this._kind) { + return this._kind + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "kind", + }, + ], + this.client + ) + + + return response + } + + /** + * Whether this type can be set to null. Defaults to false. + */ + async optional(): Promise { + if (this._optional) { + return this._optional + } + + const response: Awaited = await computeQuery( + [ + ...this._queryTree, + { + operation: "optional", + }, + ], + this.client + ) + + + return response + } + + /** + * Adds a static field for an Object TypeDef, failing if the type is not an object. + * @param name The name of the field in the object + * @param typeDef The type of the field + * @param opts.description A doc string for the field, if any + */ + withField(name: string, typeDef: TypeDef, opts?: TypeDefWithFieldOpts): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withField", + args: { name, typeDef, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Adds a function for an Object TypeDef, failing if the type is not an object. + */ + withFunction(function_: Function_): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withFunction", + args: { function_ }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets the kind of the type. + */ + withKind(kind: TypeDefKind): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withKind", + args: { kind }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a TypeDef of kind List with the provided type for its elements. + */ + withListOf(elementType: TypeDef): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withListOf", + args: { elementType }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Returns a TypeDef of kind Object with the provided name. + * + * Note that an object's fields and functions may be omitted if the intent is + * only to refer to an object. This is how functions are able to return their + * own object, or any other circular reference. + */ + withObject(name: string, opts?: TypeDefWithObjectOpts): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withObject", + args: { name, ...opts }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Sets whether this type can be set to null. + */ + withOptional(optional: boolean): TypeDef { + return new TypeDef({ + queryTree: [ + ...this._queryTree, + { + operation: "withOptional", + args: { optional }, + }, + ], + host: this.clientHost, + sessionToken: this.sessionToken, + }) + } + + /** + * Call the provided function with current TypeDef. + * + * This is useful for reusability and readability by not breaking the calling chain. + */ + with(arg: (param: TypeDef) => TypeDef) { + return arg(this) + } +} + + + + + + + diff --git a/sdk/connect.ts b/sdk/connect.ts new file mode 100644 index 0000000..bd26cf7 --- /dev/null +++ b/sdk/connect.ts @@ -0,0 +1,89 @@ +import { Writable } from "node:stream"; + +import { Client } from "./client.gen.ts"; + +/** + * ConnectOpts defines option used to connect to an engine. + */ +export interface ConnectOpts { + /** + * Use to overwrite Dagger workdir + * @defaultValue process.cwd() + */ + Workdir?: string; + /** + * Enable logs output + * @example + * LogOutput + * ```ts + * connect(async (client: Client) => { + const source = await client.host().workdir().id() + ... + }, {LogOutput: process.stdout}) + ``` + */ + LogOutput?: Writable; +} + +export type CallbackFct = (client: Client) => Promise; + +export interface ConnectParams { + port: number; + session_token: string; +} + +/** + * connect runs GraphQL server and initializes a + * GraphQL client to execute query on it through its callback. + * This implementation is based on the existing Go SDK. + */ +export async function connect( + cb: CallbackFct, + config: ConnectOpts = {} +): Promise { + let client: Client; + // let close: null | (() => void) = null; + + if (Deno.env.has("FLUENTCI_TOKEN") && Deno.env.has("FLUENTCI_SESSION_ID")) { + const client = new Client({ + host: Deno.env.get("FLUENTCI_HOST") || "vm.fluentci.io", + sessionToken: Deno.env.get("FLUENTCI_TOKEN"), + }); + await cb(client).finally(() => { + if (close) { + close(); + } + }); + return; + } + + // Prefer DAGGER_SESSION_PORT if set + const daggerSessionPort = Deno.env.get("DAGGER_SESSION_PORT"); + if (daggerSessionPort) { + const sessionToken = Deno.env.get("DAGGER_SESSION_TOKEN"); + if (!sessionToken) { + throw new Error( + "DAGGER_SESSION_TOKEN must be set when using DAGGER_SESSION_PORT" + ); + } + + if (config.Workdir && config.Workdir !== "") { + throw new Error( + "cannot configure workdir for existing session (please use --workdir or host.directory with absolute paths instead)" + ); + } + + client = new Client({ + host: `127.0.0.1:${daggerSessionPort}`, + sessionToken: sessionToken, + }); + } else { + throw new Error("DAGGER_SESSION_PORT must be set"); + } + + await cb(client).finally(() => { + if (close) { + close(); + } + }); +} diff --git a/sdk/utils.ts b/sdk/utils.ts new file mode 100644 index 0000000..075e278 --- /dev/null +++ b/sdk/utils.ts @@ -0,0 +1,251 @@ +// deno-lint-ignore-file no-explicit-any +import { + ClientError, + gql, + GraphQLClient, + GraphQLRequestError, + TooManyNestedObjectsError, + UnknownDaggerError, + NotAwaitedRequestError, + ExecError, +} from "../deps.ts"; + +import { Metadata, QueryTree } from "./client.gen.ts"; + +/** + * Format argument into GraphQL query format. + */ +function buildArgs(args: any): string { + const metadata: Metadata = args.__metadata || {}; + + // Remove unwanted quotes + const formatValue = (key: string, value: string) => { + // Special treatment for enumeration, they must be inserted without quotes + if (metadata[key]?.is_enum) { + return JSON.stringify(value).replace(/['"]+/g, ""); + } + + return JSON.stringify(value).replace( + /\{"[a-zA-Z]+":|,"[a-zA-Z]+":/gi, + (str) => { + return str.replace(/"/g, ""); + } + ); + }; + + if (args === undefined || args === null) { + return ""; + } + + const formattedArgs = Object.entries(args).reduce( + (acc: any, [key, value]) => { + // Ignore internal metadata key + if (key === "__metadata") { + return acc; + } + + if (value !== undefined && value !== null) { + acc.push(`${key}: ${formatValue(key, value as string)}`); + } + + return acc; + }, + [] + ); + + if (formattedArgs.length === 0) { + return ""; + } + + return `(${formattedArgs})`; +} + +/** + * Find QueryTree, convert them into GraphQl query + * then compute and return the result to the appropriate field + */ +async function computeNestedQuery( + query: QueryTree[], + client: GraphQLClient +): Promise { + // Check if there is a nested queryTree to be executed + const isQueryTree = (value: any) => value["_queryTree"] !== undefined; + + // Check if there is a nested array of queryTree to be executed + const isArrayQueryTree = (value: any[]) => + value.every((v) => v instanceof Object && isQueryTree(v)); + + // Prepare query tree for final query by computing nested queries + // and building it with their results. + const computeQueryTree = async (value: any): Promise => { + // Resolve sub queries if operation's args is a subquery + for (const op of value["_queryTree"]) { + await computeNestedQuery([op], client); + } + + // push an id that will be used by the container + return buildQuery([ + ...value["_queryTree"], + { + operation: "id", + }, + ]); + }; + + // Remove all undefined args and assert args type + const queryToExec = query.filter((q): q is Required => !!q.args); + + for (const q of queryToExec) { + await Promise.all( + // Compute nested query for single object + Object.entries(q.args).map(async ([key, value]: any) => { + if (value instanceof Object && isQueryTree(value)) { + // push an id that will be used by the container + const getQueryTree = await computeQueryTree(value); + + q.args[key] = await compute(getQueryTree, client); + } + + // Compute nested query for array of object + if (Array.isArray(value) && isArrayQueryTree(value)) { + const tmp: any = q.args[key]; + + for (let i = 0; i < value.length; i++) { + // push an id that will be used by the container + const getQueryTree = await computeQueryTree(value[i]); + + tmp[i] = await compute(getQueryTree, client); + } + + q.args[key] = tmp; + } + }) + ); + } +} + +/** + * Convert the queryTree into a GraphQL query + * @param q + * @returns + */ +export function buildQuery(q: QueryTree[]): string { + const query = q.reduce((acc, { operation, args }, i) => { + const qLen = q.length; + + acc += ` ${operation} ${args ? `${buildArgs(args)}` : ""} ${ + qLen - 1 !== i ? "{" : "}".repeat(qLen - 1) + }`; + + return acc; + }, ""); + + return `{${query + .replaceAll('"StringKind"', "StringKind") + .replaceAll('"VoidKind"', "VoidKind") + .replaceAll('"IntegerKind"', "IntegerKind") + .replaceAll('"BooleanKind"', "BooleanKind") + .replaceAll('"ObjectKind"', "ObjectKind") + .replaceAll('"ListKind"', "ListKind") + .replaceAll("function_", "function")} }`; +} + +/** + * Convert querytree into a Graphql query then compute it + * @param q | QueryTree[] + * @param client | GraphQLClient + * @returns + */ +export async function computeQuery( + q: QueryTree[], + client: GraphQLClient +): Promise { + await computeNestedQuery(q, client); + + const query = buildQuery(q); + + return await compute(query, client); +} + +/** + * Return a Graphql query result flattened + * @param response any + * @returns + */ +export function queryFlatten(response: any): T { + // Recursion break condition + // If our response is not an object or an array we assume we reached the value + if (!(response instanceof Object) || Array.isArray(response)) { + return response; + } + + const keys = Object.keys(response); + + if (keys.length != 1) { + // Dagger is currently expecting to only return one value + // If the response is nested in a way were more than one object is nested inside throw an error + throw new TooManyNestedObjectsError( + "Too many nested objects inside graphql response", + { response: response } + ); + } + + const nestedKey = keys[0]; + + return queryFlatten(response[nestedKey]); +} + +/** + * Send a GraphQL document to the server + * return a flatten result + * @hidden + */ +export async function compute( + query: string, + client: GraphQLClient +): Promise { + let computeQuery: Awaited; + try { + computeQuery = await client.request( + gql` + ${query} + ` + ); + } catch (e: any) { + if (e instanceof ClientError) { + const msg = e.response.errors?.[0]?.message ?? `API Error`; + const ext = e.response.errors?.[0]?.extensions; + + if (ext?._type === "EXEC_ERROR") { + throw new ExecError(msg, { + cmd: (ext.cmd as string[]) ?? [], + exitCode: (ext.exitCode as number) ?? -1, + stdout: (ext.stdout as string) ?? "", + stderr: (ext.stderr as string) ?? "", + }); + } + + throw new GraphQLRequestError(msg, { + request: e.request, + response: e.response, + cause: e, + }); + } + + // Looking for connection error in case the function has not been awaited. + if (e.errno === "ECONNREFUSED") { + throw new NotAwaitedRequestError( + "Encountered an error while requesting data via graphql through a synchronous call. Make sure the function called is awaited.", + { cause: e } + ); + } + + // Just throw the unknown error + throw new UnknownDaggerError( + "Encountered an unknown error while requesting data via graphql", + { cause: e } + ); + } + + return queryFlatten(computeQuery); +} diff --git a/src/dagger/jobs.ts b/src/dagger/jobs.ts index 249058b..cd39e3a 100644 --- a/src/dagger/jobs.ts +++ b/src/dagger/jobs.ts @@ -1,4 +1,6 @@ -import Client, { connect } from "../../deps.ts"; +import Client, { Directory } from "../../deps.ts"; +import { connect } from "../../sdk/connect.ts"; +import { getDirectory } from "./lib.ts"; export enum Job { config = "config", @@ -10,13 +12,34 @@ export enum Job { export const exclude = [".fluentci"]; -export const config = async (src = ".", exitCode?: number) => { +/** + * @function + * @description Scan a configuration file + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function config( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["config", src]; + const context = getDirectory(client, src); + const args = ["config", "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.config) .container() @@ -30,15 +53,36 @@ export const config = async (src = ".", exitCode?: number) => { console.log(result); }); return "Done"; -}; +} -export const fs = async (src = ".", exitCode?: number) => { +/** + * @function + * @description Scan a local filesystem + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function fs( + src: Directory | string, + exitCode?: number, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["fs", src]; + const context = getDirectory(client, src); + const args = ["fs", "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.fs) .container() @@ -52,15 +96,38 @@ export const fs = async (src = ".", exitCode?: number) => { console.log(result); }); return "Done"; -}; +} -export const repo = async (src = ".", exitCode?: number, repoUrl?: string) => { +/** + * @function + * @description Scan a repository + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} repoUrl + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function repo( + src: Directory | string, + exitCode?: number, + repoUrl?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); - const args = ["repo", Deno.env.get("TRIVY_REPO_URL") || repoUrl || src]; + const context = getDirectory(client, src); + const args = ["repo", Deno.env.get("TRIVY_REPO_URL") || repoUrl || "."]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.repo) .container() @@ -74,16 +141,41 @@ export const repo = async (src = ".", exitCode?: number, repoUrl?: string) => { console.log(result); }); return "Done"; -}; +} -export const image = async (src = ".", exitCode?: number, image?: string) => { +/** + * @function + * @description Scan a container image + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} image + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function image( + src: Directory | string, + exitCode?: number, + image?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); + const context = getDirectory(client, src); if (!Deno.env.has("TRIVY_IMAGE") && !image) { - throw new Error("TRIVY_IMAGE is not set"); + console.log("TRIVY_IMAGE is not set"); + Deno.exit(1); } const args = ["image", Deno.env.get("TRIVY_IMAGE") || image!]; + + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); @@ -100,19 +192,43 @@ export const image = async (src = ".", exitCode?: number, image?: string) => { console.log(result); }); return "Done"; -}; +} -export const sbom = async (src = ".", exitCode?: number, path?: string) => { +/** + * @function + * @description Scan a software bill of materials + * @param {Directory | string} src + * @param {number} exitCode + * @param {string} path + * @param {string} format + * @param {string} output + * @returns {Promise} + */ +export async function sbom( + src: Directory | string, + exitCode?: number, + path?: string, + format?: string, + output?: string +): Promise { await connect(async (client: Client) => { - const context = client.host().directory(src); + const context = getDirectory(client, src); if (!Deno.env.has("TRIVY_SBOM_PATH") && !path) { - throw new Error("TRIVY_SBOM_PATH is not set"); + console.error("TRIVY_SBOM_PATH is not set"); + Deno.exit(1); } const args = ["sbom", Deno.env.get("TRIVY_SBOM_PATH") || path!]; const TRIVY_EXIT_CODE = Deno.env.get("TRIVY_EXIT_CODE") || exitCode || "0"; args.push(`--exit-code=${TRIVY_EXIT_CODE}`); + if (format) { + args.push(`--format=${format}`); + } + + output = output || "output"; + args.push(`--output=${output}`); + const ctr = client .pipeline(Job.config) .container() @@ -126,16 +242,15 @@ export const sbom = async (src = ".", exitCode?: number, path?: string) => { console.log(result); }); return "Done"; -}; +} export type JobExec = ( - src?: string, - exitCode?: number -) => - | Promise - | ((src?: string, exitCode?: number, path?: string) => Promise) - | ((src?: string, exitCode?: number, repoUrl?: string) => Promise) - | ((src?: string, exitCode?: number, image?: string) => Promise); + src: Directory | string, + exitCode?: number, + path?: string, + format?: string, + output?: string +) => Promise; export const runnableJobs: Record = { [Job.config]: config, diff --git a/src/dagger/lib.ts b/src/dagger/lib.ts new file mode 100644 index 0000000..5106de1 --- /dev/null +++ b/src/dagger/lib.ts @@ -0,0 +1,13 @@ +import Client, { Directory, DirectoryID } from "../../deps.ts"; + +export const getDirectory = ( + client: Client, + src: string | Directory | undefined = "." +) => { + if (typeof src === "string" && src.startsWith("core.Directory")) { + return client.directory({ + id: src as DirectoryID, + }); + } + return src instanceof Directory ? src : client.host().directory(src); +}; diff --git a/src/dagger/pipeline.ts b/src/dagger/pipeline.ts index 9dc7a64..dbc9adc 100644 --- a/src/dagger/pipeline.ts +++ b/src/dagger/pipeline.ts @@ -21,6 +21,6 @@ async function runSpecificJobs(args: jobs.Job[]) { if (!job) { throw new Error(`Job ${name} not found`); } - await job(); + await job("."); } } diff --git a/src/dagger/queries.ts b/src/dagger/queries.ts deleted file mode 100644 index ab7ce92..0000000 --- a/src/dagger/queries.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { gql } from "../../deps.ts"; - -export const config = gql` - query config($src: String!, $exitCode: Int!) { - config(src: $src, exitCode: $exitCode) - } -`; - -export const fs = gql` - query fs($src: String!, $exitCode: Int!) { - fs(src: $src, exitCode: $exitCode) - } -`; - -export const repo = gql` - query repo($src: String!, $exitCode: Int!, $repoUrl: String!) { - repo(src: $src, exitCode: $exitCode, repoUrl: $repoUrl) - } -`; - -export const image = gql` - query image($src: String!, $exitCode: Int!, $image: String!) { - image(src: $src, exitCode: $exitCode, image: $image) - } -`; - -export const sbom = gql` - query sbom($src: String!, $exitCode: Int!, $path: String!) { - sbom(src: $src, exitCode: $exitCode, path: $path) - } -`; diff --git a/src/dagger/schema.ts b/src/dagger/schema.ts deleted file mode 100644 index c98a692..0000000 --- a/src/dagger/schema.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - queryType, - makeSchema, - dirname, - join, - resolve, - stringArg, - nonNull, - intArg, -} from "../../deps.ts"; - -import { config, fs, repo, image, sbom } from "./jobs.ts"; - -const Query = queryType({ - definition(t) { - t.string("config", { - args: { - src: nonNull(stringArg()), - exitCode: nonNull(intArg()), - }, - resolve: async (_root, args, _ctx) => - await config(args.src, args.exitCode), - }); - t.string("fs", { - args: { - src: nonNull(stringArg()), - exitCode: nonNull(intArg()), - }, - resolve: async (_root, args, _ctx) => await fs(args.src, args.exitCode), - }); - t.string("repo", { - args: { - src: nonNull(stringArg()), - exitCode: nonNull(intArg()), - repoUrl: nonNull(stringArg()), - }, - resolve: async (_root, args, _ctx) => - await repo(args.src, args.exitCode, args.repoUrl), - }); - t.string("image", { - args: { - src: nonNull(stringArg()), - exitCode: nonNull(intArg()), - image: nonNull(stringArg()), - }, - resolve: async (_root, args, _ctx) => - await image(args.src, args.exitCode, args.image), - }); - t.string("sbom", { - args: { - src: nonNull(stringArg()), - exitCode: nonNull(intArg()), - path: nonNull(stringArg()), - }, - resolve: async (_root, args, _ctx) => - await sbom(args.src, args.exitCode, args.path), - }); - }, -}); - -export const schema = makeSchema({ - types: [Query], - outputs: { - schema: resolve(join(dirname(".."), dirname(".."), "schema.graphql")), - typegen: resolve(join(dirname(".."), dirname(".."), "gen", "nexus.ts")), - }, -});