@saws/docker-service 2.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"fileNames":["../../../node_modules/typescript/lib/lib.es5.d.ts","../../../node_modules/typescript/lib/lib.es2015.d.ts","../../../node_modules/typescript/lib/lib.es2016.d.ts","../../../node_modules/typescript/lib/lib.es2017.d.ts","../../../node_modules/typescript/lib/lib.es2018.d.ts","../../../node_modules/typescript/lib/lib.es2019.d.ts","../../../node_modules/typescript/lib/lib.es2020.d.ts","../../../node_modules/typescript/lib/lib.es2021.d.ts","../../../node_modules/typescript/lib/lib.es2022.d.ts","../../../node_modules/typescript/lib/lib.es2023.d.ts","../../../node_modules/typescript/lib/lib.es2024.d.ts","../../../node_modules/typescript/lib/lib.es2025.d.ts","../../../node_modules/typescript/lib/lib.es2015.core.d.ts","../../../node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../../../node_modules/typescript/lib/lib.es2016.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2017.date.d.ts","../../../node_modules/typescript/lib/lib.es2017.object.d.ts","../../../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2017.string.d.ts","../../../node_modules/typescript/lib/lib.es2017.intl.d.ts","../../../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../../../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../../../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../../../node_modules/typescript/lib/lib.es2018.intl.d.ts","../../../node_modules/typescript/lib/lib.es2018.promise.d.ts","../../../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2019.array.d.ts","../../../node_modules/typescript/lib/lib.es2019.object.d.ts","../../../node_modules/typescript/lib/lib.es2019.string.d.ts","../../../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../../../node_modules/typescript/lib/lib.es2019.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../../../node_modules/typescript/lib/lib.es2020.date.d.ts","../../../node_modules/typescript/lib/lib.es2020.promise.d.ts","../../../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2020.string.d.ts","../../../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../../../node_modules/typescript/lib/lib.es2020.intl.d.ts","../../../node_modules/typescript/lib/lib.es2020.number.d.ts","../../../node_modules/typescript/lib/lib.es2021.promise.d.ts","../../../node_modules/typescript/lib/lib.es2021.string.d.ts","../../../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../../../node_modules/typescript/lib/lib.es2021.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.array.d.ts","../../../node_modules/typescript/lib/lib.es2022.error.d.ts","../../../node_modules/typescript/lib/lib.es2022.intl.d.ts","../../../node_modules/typescript/lib/lib.es2022.object.d.ts","../../../node_modules/typescript/lib/lib.es2022.string.d.ts","../../../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2023.array.d.ts","../../../node_modules/typescript/lib/lib.es2023.collection.d.ts","../../../node_modules/typescript/lib/lib.es2023.intl.d.ts","../../../node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts","../../../node_modules/typescript/lib/lib.es2024.collection.d.ts","../../../node_modules/typescript/lib/lib.es2024.object.d.ts","../../../node_modules/typescript/lib/lib.es2024.promise.d.ts","../../../node_modules/typescript/lib/lib.es2024.regexp.d.ts","../../../node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts","../../../node_modules/typescript/lib/lib.es2024.string.d.ts","../../../node_modules/typescript/lib/lib.es2025.collection.d.ts","../../../node_modules/typescript/lib/lib.es2025.float16.d.ts","../../../node_modules/typescript/lib/lib.es2025.intl.d.ts","../../../node_modules/typescript/lib/lib.es2025.iterator.d.ts","../../../node_modules/typescript/lib/lib.es2025.promise.d.ts","../../../node_modules/typescript/lib/lib.es2025.regexp.d.ts","../../../node_modules/typescript/lib/lib.esnext.collection.d.ts","../../../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../../../node_modules/typescript/lib/lib.esnext.temporal.d.ts","../../../node_modules/typescript/lib/lib.decorators.d.ts","../../../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../../core/dist/utils/stage-outputs.d.ts","../../core/dist/secrets-manager.d.ts","../../core/dist/servicedefinition.d.ts","../../core/dist/find-service-definition.d.ts","../../core/dist/get-saws-config.d.ts","../../core/dist/host-readiness.d.ts","../../core/dist/host.d.ts","../../core/dist/global-hosts.d.ts","../../core/dist/index.d.ts","../../core/dist/utils/run-local.d.ts","../../core/dist/utils/shell-quote.d.ts","../src/dockerservice.ts","../src/index.ts","../../../node_modules/@types/node/globals.typedarray.d.ts","../../../node_modules/@types/node/buffer.buffer.d.ts","../../../node_modules/@types/node/globals.d.ts","../../../node_modules/@types/node/web-globals/abortcontroller.d.ts","../../../node_modules/@types/node/web-globals/blob.d.ts","../../../node_modules/@types/node/web-globals/console.d.ts","../../../node_modules/@types/node/web-globals/crypto.d.ts","../../../node_modules/@types/node/web-globals/domexception.d.ts","../../../node_modules/@types/node/web-globals/encoding.d.ts","../../../node_modules/@types/node/web-globals/events.d.ts","../../../node_modules/undici-types/utility.d.ts","../../../node_modules/undici-types/header.d.ts","../../../node_modules/undici-types/readable.d.ts","../../../node_modules/undici-types/fetch.d.ts","../../../node_modules/undici-types/formdata.d.ts","../../../node_modules/undici-types/connector.d.ts","../../../node_modules/undici-types/client-stats.d.ts","../../../node_modules/undici-types/client.d.ts","../../../node_modules/undici-types/errors.d.ts","../../../node_modules/undici-types/dispatcher.d.ts","../../../node_modules/undici-types/global-dispatcher.d.ts","../../../node_modules/undici-types/global-origin.d.ts","../../../node_modules/undici-types/pool-stats.d.ts","../../../node_modules/undici-types/pool.d.ts","../../../node_modules/undici-types/handlers.d.ts","../../../node_modules/undici-types/balanced-pool.d.ts","../../../node_modules/undici-types/round-robin-pool.d.ts","../../../node_modules/undici-types/h2c-client.d.ts","../../../node_modules/undici-types/agent.d.ts","../../../node_modules/undici-types/dispatcher1-wrapper.d.ts","../../../node_modules/undici-types/mock-interceptor.d.ts","../../../node_modules/undici-types/mock-call-history.d.ts","../../../node_modules/undici-types/mock-agent.d.ts","../../../node_modules/undici-types/mock-client.d.ts","../../../node_modules/undici-types/mock-pool.d.ts","../../../node_modules/undici-types/snapshot-agent.d.ts","../../../node_modules/undici-types/mock-errors.d.ts","../../../node_modules/undici-types/proxy-agent.d.ts","../../../node_modules/undici-types/socks5-proxy-agent.d.ts","../../../node_modules/undici-types/env-http-proxy-agent.d.ts","../../../node_modules/undici-types/retry-handler.d.ts","../../../node_modules/undici-types/retry-agent.d.ts","../../../node_modules/undici-types/api.d.ts","../../../node_modules/undici-types/cache-interceptor.d.ts","../../../node_modules/undici-types/interceptors.d.ts","../../../node_modules/undici-types/util.d.ts","../../../node_modules/undici-types/cookies.d.ts","../../../node_modules/undici-types/patch.d.ts","../../../node_modules/undici-types/websocket.d.ts","../../../node_modules/undici-types/eventsource.d.ts","../../../node_modules/undici-types/diagnostics-channel.d.ts","../../../node_modules/undici-types/content-type.d.ts","../../../node_modules/undici-types/cache.d.ts","../../../node_modules/undici-types/index.d.ts","../../../node_modules/@types/node/web-globals/fetch.d.ts","../../../node_modules/@types/node/web-globals/importmeta.d.ts","../../../node_modules/@types/node/web-globals/messaging.d.ts","../../../node_modules/@types/node/web-globals/navigator.d.ts","../../../node_modules/@types/node/web-globals/performance.d.ts","../../../node_modules/@types/node/web-globals/storage.d.ts","../../../node_modules/@types/node/web-globals/streams.d.ts","../../../node_modules/@types/node/web-globals/timers.d.ts","../../../node_modules/@types/node/web-globals/url.d.ts","../../../node_modules/@types/node/assert.d.ts","../../../node_modules/@types/node/assert/strict.d.ts","../../../node_modules/@types/node/async_hooks.d.ts","../../../node_modules/@types/node/buffer.d.ts","../../../node_modules/@types/node/child_process.d.ts","../../../node_modules/@types/node/cluster.d.ts","../../../node_modules/@types/node/console.d.ts","../../../node_modules/@types/node/constants.d.ts","../../../node_modules/@types/node/crypto.d.ts","../../../node_modules/@types/node/dgram.d.ts","../../../node_modules/@types/node/diagnostics_channel.d.ts","../../../node_modules/@types/node/dns.d.ts","../../../node_modules/@types/node/dns/promises.d.ts","../../../node_modules/@types/node/domain.d.ts","../../../node_modules/@types/node/events.d.ts","../../../node_modules/@types/node/ffi.d.ts","../../../node_modules/@types/node/fs.d.ts","../../../node_modules/@types/node/fs/promises.d.ts","../../../node_modules/@types/node/http.d.ts","../../../node_modules/@types/node/http2.d.ts","../../../node_modules/@types/node/https.d.ts","../../../node_modules/@types/node/inspector.d.ts","../../../node_modules/@types/node/inspector.generated.d.ts","../../../node_modules/@types/node/inspector/promises.d.ts","../../../node_modules/@types/node/module.d.ts","../../../node_modules/@types/node/net.d.ts","../../../node_modules/@types/node/os.d.ts","../../../node_modules/@types/node/path.d.ts","../../../node_modules/@types/node/path/posix.d.ts","../../../node_modules/@types/node/path/win32.d.ts","../../../node_modules/@types/node/perf_hooks.d.ts","../../../node_modules/@types/node/process.d.ts","../../../node_modules/@types/node/punycode.d.ts","../../../node_modules/@types/node/querystring.d.ts","../../../node_modules/@types/node/quic.d.ts","../../../node_modules/@types/node/readline.d.ts","../../../node_modules/@types/node/readline/promises.d.ts","../../../node_modules/@types/node/repl.d.ts","../../../node_modules/@types/node/sea.d.ts","../../../node_modules/@types/node/sqlite.d.ts","../../../node_modules/@types/node/stream.d.ts","../../../node_modules/@types/node/stream/consumers.d.ts","../../../node_modules/@types/node/stream/iter.d.ts","../../../node_modules/@types/node/stream/promises.d.ts","../../../node_modules/@types/node/stream/web.d.ts","../../../node_modules/@types/node/string_decoder.d.ts","../../../node_modules/@types/node/test.d.ts","../../../node_modules/@types/node/test/reporters.d.ts","../../../node_modules/@types/node/timers.d.ts","../../../node_modules/@types/node/timers/promises.d.ts","../../../node_modules/@types/node/tls.d.ts","../../../node_modules/@types/node/trace_events.d.ts","../../../node_modules/@types/node/tty.d.ts","../../../node_modules/@types/node/url.d.ts","../../../node_modules/@types/node/util.d.ts","../../../node_modules/@types/node/util/types.d.ts","../../../node_modules/@types/node/v8.d.ts","../../../node_modules/@types/node/vm.d.ts","../../../node_modules/@types/node/wasi.d.ts","../../../node_modules/@types/node/worker_threads.d.ts","../../../node_modules/@types/node/zlib.d.ts","../../../node_modules/@types/node/zlib/iter.d.ts","../../../node_modules/@types/node/index.d.ts","../../../node_modules/@types/find-package-json/package-json.d.ts","../../../node_modules/@types/find-package-json/index.d.ts"],"fileIdsList":[[94,159,167,172,175,177,178,179,191,218,219],[94,159,167,172,175,177,178,179,191],[94,156,157,159,167,172,175,177,178,179,191],[94,158,159,167,172,175,177,178,179,191],[159,167,172,175,177,178,179,191],[94,159,167,172,175,177,178,179,191,200],[94,159,160,165,167,170,172,175,177,178,179,181,191,196,209],[94,159,160,161,167,170,172,175,177,178,179,191],[94,159,162,167,172,175,177,178,179,191,210],[94,159,163,164,167,172,175,177,178,179,182,191],[94,159,164,167,172,175,177,178,179,191,196,206],[94,159,165,167,170,172,175,177,178,179,181,191],[94,158,159,166,167,172,175,177,178,179,191],[94,159,167,168,172,175,177,178,179,191],[94,159,167,169,170,172,175,177,178,179,191],[94,158,159,167,170,172,175,177,178,179,191],[94,159,167,170,172,173,175,177,178,179,191,196,209],[94,159,167,170,172,173,175,177,178,179,191,196,198,200],[94,146,159,167,170,172,174,175,177,178,179,181,191,196,209],[94,159,167,170,172,174,175,177,178,179,181,191,196,206,209],[94,159,167,172,174,175,176,177,178,179,191,196,206,209],[93,94,95,96,97,98,99,100,101,102,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217],[94,159,167,170,172,175,177,178,179,191],[94,159,167,172,175,177,179,191],[94,159,167,172,175,177,178,179,180,191,209],[94,159,167,170,172,175,177,178,179,181,191,196],[94,159,167,172,175,177,178,179,182,191],[94,159,167,172,175,177,178,179,183,191],[94,159,167,170,172,175,177,178,179,186,191],[94,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216],[94,159,167,172,175,177,178,179,188,191],[94,159,167,172,175,177,178,179,189,191],[94,159,164,167,172,175,177,178,179,181,191,200],[94,159,167,170,172,175,177,178,179,191,192],[94,159,167,172,175,177,178,179,191,193,210,213],[94,159,167,170,172,175,177,178,179,191,196,198,199,200],[94,159,167,172,175,177,178,179,191,197,200],[94,159,167,170,172,175,177,178,179,191,196,198],[94,159,167,170,172,175,177,178,179,191,196,199,200],[94,159,167,172,175,177,178,179,191,200,210],[94,159,167,172,175,177,178,179,191,201],[94,156,159,167,172,175,177,178,179,191,196,203,209],[94,159,167,172,175,177,178,179,191,196,202],[94,159,167,170,172,175,177,178,179,191,204,205],[94,159,167,172,175,177,178,179,191,204,205],[94,159,164,167,172,175,177,178,179,181,191,196,206],[94,159,167,172,175,177,178,179,191,207],[94,159,167,172,175,177,178,179,181,191,208],[94,159,167,172,174,175,177,178,179,189,191,209],[94,159,167,172,175,177,178,179,191,210,211],[94,159,164,167,172,175,177,178,179,191,211],[94,159,167,172,175,177,178,179,191,196,212],[94,159,167,172,175,177,178,179,180,191,213],[94,159,167,172,175,177,178,179,191,214],[94,159,162,167,172,175,177,178,179,191],[94,159,164,167,172,175,177,178,179,191],[94,159,167,172,175,177,178,179,191,210],[94,146,159,167,172,175,177,178,179,191],[94,159,167,172,175,177,178,179,191,209],[94,159,167,172,175,177,178,179,191,215],[94,159,167,172,175,177,178,179,186,191],[94,159,167,172,175,177,178,179,191,205],[94,146,159,167,170,172,173,175,177,178,179,186,191,196,200,209,212,213,215],[94,159,167,172,175,177,178,179,191,196,216],[94,159,167,172,175,177,178,179,191,198,217],[94,109,112,115,116,159,167,172,175,177,178,179,191,209],[94,112,159,167,172,175,177,178,179,191,196,209],[94,112,116,159,167,172,175,177,178,179,191,209],[94,159,167,172,175,177,178,179,191,196],[94,106,159,167,172,175,177,178,179,191],[94,110,159,167,172,175,177,178,179,191],[94,108,109,112,159,167,172,175,177,178,179,191,209],[94,159,167,172,175,177,178,179,181,191,206],[94,159,167,172,175,177,178,179,191,218],[94,106,159,167,172,175,177,178,179,191,218],[94,108,112,159,167,172,175,177,178,179,181,191,209],[94,103,104,105,107,111,159,167,170,172,175,177,178,179,191,196,209],[94,112,159,167,172,175,177,178,179,191],[94,112,121,130,159,167,172,175,177,178,179,191],[94,104,110,159,167,172,175,177,178,179,191],[94,112,140,141,159,167,172,175,177,178,179,191],[94,104,107,112,159,167,172,175,177,178,179,191,200,209,218],[94,108,112,159,167,172,175,177,178,179,191,209],[94,103,159,167,172,175,177,178,179,191],[94,106,107,108,110,111,112,113,114,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,141,142,143,144,145,159,167,172,175,177,178,179,191],[94,112,133,136,159,167,172,175,177,178,179,191],[94,112,121,123,124,159,167,172,175,177,178,179,191],[94,110,112,123,125,159,167,172,175,177,178,179,191],[94,111,159,167,172,175,177,178,179,191],[94,104,106,112,159,167,172,175,177,178,179,191],[94,112,116,123,125,159,167,172,175,177,178,179,191],[94,116,159,167,172,175,177,178,179,191],[94,110,112,115,159,167,172,175,177,178,179,191,209],[94,104,108,112,121,159,167,172,175,177,178,179,191],[94,112,133,159,167,172,175,177,178,179,191],[94,125,159,167,172,175,177,178,179,191],[94,104,108,112,116,159,167,172,175,177,178,179,191],[94,106,112,140,159,167,172,175,177,178,179,191,200,215,218],[82,94,159,167,172,175,177,178,179,191],[81,86,94,159,167,172,175,177,178,179,191],[81,85,94,159,167,172,175,177,178,179,191],[81,82,83,84,85,86,87,94,159,167,172,175,177,178,179,191],[80,81,94,159,167,172,175,177,178,179,191,196],[88,89,90,94,159,160,164,167,172,173,175,177,178,179,183,191],[91,94,159,167,172,175,177,178,179,191]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"1e9332c23e9a907175e0ffc6a49e236f97b48838cc8aec9ce7e4cec21e544b65","impliedFormat":1},{"version":"3753fbc1113dc511214802a2342280a8b284ab9094f6420e7aa171e868679f91","impliedFormat":1},{"version":"999ca32883495a866aa5737fe1babc764a469e4cde6ee6b136a4b9ae68853e4b","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"0bd714129fca875f7d4c477a1a392200b0bcd13fb2e80928cd334b63830ea047","affectsGlobalScope":true,"impliedFormat":1},{"version":"e2c9037ae6cd2c52d80ceef0b3c5ffdb488627d71529cf4f63776daf11161c9a","affectsGlobalScope":true,"impliedFormat":1},{"version":"135d5cf4d345f59f1a9caadfafcd858d3d9cc68290db616cc85797224448cccc","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc238c3f81c2984751932b6aab223cd5b830e0ac6cad76389e5e9d2ffc03287d","affectsGlobalScope":true,"impliedFormat":1},{"version":"4a07f9b76d361f572620927e5735b77d6d2101c23cdd94383eb5b706e7b36357","affectsGlobalScope":true,"impliedFormat":1},{"version":"7c4e8dc6ab834cc6baa0227e030606d29e3e8449a9f67cdf5605ea5493c4db29","affectsGlobalScope":true,"impliedFormat":1},{"version":"de7ba0fd02e06cd9a5bd4ab441ed0e122735786e67dde1e849cced1cd8b46b78","affectsGlobalScope":true,"impliedFormat":1},{"version":"6148e4e88d720a06855071c3db02069434142a8332cf9c182cda551adedf3156","affectsGlobalScope":true,"impliedFormat":1},{"version":"d63dba625b108316a40c95a4425f8d4294e0deeccfd6c7e59d819efa19e23409","affectsGlobalScope":true,"impliedFormat":1},{"version":"0568d6befee03dd435bed4fc25c4e46865b24bdcb8c563fdc21f580a2c301904","affectsGlobalScope":true,"impliedFormat":1},{"version":"30d62269b05b584741f19a5369852d5d34895aa2ac4fd948956f886d15f9cc0d","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"ffbe6d7b295306b2ba88030f65b74c107d8d99bdcf596ea99c62a02f606108b0","affectsGlobalScope":true,"impliedFormat":1},{"version":"996fb27b15277369c68a4ba46ed138b4e9e839a02fb4ec756f7997629242fd9f","affectsGlobalScope":true,"impliedFormat":1},{"version":"79b712591b270d4778c89706ca2cfc56ddb8c3f895840e477388f1710dc5eda9","affectsGlobalScope":true,"impliedFormat":1},{"version":"20884846cef428b992b9bd032e70a4ef88e349263f63aeddf04dda837a7dba26","affectsGlobalScope":true,"impliedFormat":1},{"version":"db59a81f070c1880ad645b2c0275022baa6a0c4f0acdc58d29d349c6efcf0903","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ffedae1d1c2d53fdbca1c96d3c7dda544281f7d262f99b6880634f8fd8d9820","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"b507173a7718609bb52011f33e6fc61b0f3de62ec38c935b38dcfbb68223dea9","impliedFormat":99},{"version":"ed03f7587c6405bca4aa5cd0e13c159ba6a38d29438bf368174cbc12b7952990","impliedFormat":99},{"version":"c2c45e23c9ade84835e6589a92f4b1e0d959f4aad517ca2b9f306d505c8c186b","impliedFormat":99},{"version":"d5f72b73663996558032aae95128fd1c003dbc2a3c7c9616a4b9582885554547","impliedFormat":99},{"version":"db04ab7cf477c959b90d137c9150114e93ab293f7a82068813e62596e514c8b9","impliedFormat":99},{"version":"d096b43d56e50a815348abdc7f505bff20b7326edd25d5ceab70be8ae550b216","impliedFormat":99},{"version":"f4b14039ec5893b0c7691e5695493a13207b5a6e7ea07e9d58fe3f112e9e87fd","impliedFormat":99},{"version":"7e7edbefeefa7d89d7d0e3b51e4361ff4cbafd2f0b8691af8f00d4ec7a2d0dbb","impliedFormat":99},{"version":"b5a012b8d2b5aedaa0284247fe44638a60a00afb8a4727aa86567f401ae06b1d","impliedFormat":99},{"version":"d5af5a55477c977d5c969e0b57015847db4ef7444431770cabb0dc067c35b629","impliedFormat":99},{"version":"3fdb492c7902b3162a9fa765e5ce843a831b87bf6a47c1aa4b73056e39a2eb17","impliedFormat":99},{"version":"76a357cb60e5a7b836d50630a11192ce43c873e13aeda7401798a0585e21381a","signature":"1ef4d20b196cea0b21d8f6a8a62108355283f839b9e4796b5ac9a6c09d559e83","impliedFormat":99},{"version":"41c2effc93c4a7c1143353cdd450d9f8b91c091630764c5654727bcb5af3cfce","impliedFormat":99},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc2110f7decca6bfb9392e30421cfa1436479e4a6756e8fec6cbc22625d4f881","affectsGlobalScope":true,"impliedFormat":1},{"version":"f53a7652392cf26ebbe4e29fd0672aa87c93bd6d0241289c13fab87b9ac35c8a","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"b00a630557d1622ad312633bdbfbdb9c6b7220d948dca9f899db30679f160074","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"88809d6c1b9c78d04a133646a6feb926def05a8774c308c7c93bc32ee163d271","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"3ac40516c33b87f751f7507346933081a26cdb8a3e11a6b3aa07d23f803c85db","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"14e9acf826baba0ef4b5665704084896e7bcc06f65a9ab13af7e93d27d6b7069","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"829bc57ee8f287b490ab5bbc5a962fca57e432c1e38ec680ecd3ecaf12800613","impliedFormat":1},{"version":"eec76bf6b9346f3f95fa402621b889489e96930e72295b0369022f332e9b4a6a","impliedFormat":1},{"version":"3a3ff14da53d5013f3e6d8c4ad55225e3649c08786c4421ce639c00d8d589b7d","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"38004e6801340cb890afb8cb5a9fc8972297e7f88ab94026e4b0b3c61fb32f8a","impliedFormat":1},{"version":"d243db6b25788f439e7e2f03c05688e92f46764351673bb0e7b2f3631232e186","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"149f9a9e7f04e67afa0e2a49fc0ff421035c01d6b793cfcae7d2e9f6819431e2","impliedFormat":1},{"version":"e8a9dfa4c75ef6d25df8b40eaa9c31e0a69452aaf2ced4a3f4215dbdbaa876f4","impliedFormat":1},{"version":"a70af845a2eb9dd6e2723e319e14ea7fb28b129ec1361c21509b49305448c323","impliedFormat":1},{"version":"b53dc572d4f187904207ae1166652de47aab8eeb00c254d009cb226863076b56","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"f501234c5aeeeb5d7659412335227466aaacf30b952372d60afeb21c02c96348","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"9ac977503f15bf13ca7c82ad9a32a782f42d43e474824e8b3bffe228fd5f2639","impliedFormat":1},{"version":"8b91ff5bb912be3ea213cbcf0075aace1f5d4ff249a0d227ed673868cb7bfabc","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"7cb4f431a4591b0e23002bed805dc871a874dfed6b9a3994dce68a6df73e6739","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"436d7b4543b340b0f3eef4310d524242e41369b9652aa9c70428767c4dcac455","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"e99963ae1e3a48ca7a7958c02f3e88bb963eb7978c28b68ae6b8c9f03309d83c","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"594ae90cacd813fa392ff80d2e0a8eff4e41f4a136329a940e321399dd8895b4","impliedFormat":1},{"version":"d1f333ade8ff35a409b4984e1f11956fe11c61855b0c7e9b59f0313e48b40c4a","impliedFormat":1},{"version":"0224aa4b3464895d69c413a640a19ac2166778a74eb5eb3b36b021c72d42b274","impliedFormat":1},{"version":"2e6fca0024dd8a076a886d9ec031a936ea59ad878a25b944820495d92f8381dd","affectsGlobalScope":true,"impliedFormat":1},{"version":"177459cba484e2f1e08872a3d2fdbca3162d9d43ca5ec9dc0c946835b55f74be","impliedFormat":1},{"version":"2fbf504c4791f9d32cd766cfe6b605bcda63289b925401953a7900db9af85348","impliedFormat":1},{"version":"ed0fb633cae35948d9e144004299a4bdf1ab912667c787b7fbffcd6d8c7b92a2","impliedFormat":1},{"version":"1678b04557dca52feab73cc67610918a7f5e25bfdba3e7fa081acd625d93106d","impliedFormat":1},{"version":"0e312260895afc9de021ce9de3c8a857392f0ccc7f19d3a030e4d6136a4ac91e","impliedFormat":1},{"version":"2ea729503db9793f2691162fec3dd1118cab62e96d025f8eeb376d43ec293395","impliedFormat":1},{"version":"98fc7231d6c846a8ed19bdef026ddffe5e2182cc818be74899287421ad370a87","impliedFormat":1},{"version":"3a40b5d34e014017539acb92f04cf2bc0aa71e49efb33c66039df93be97842a1","impliedFormat":1},{"version":"2bc7aa4fba46df0bd495425a7c8201437a7d465f83854fac859df2d67f664df3","impliedFormat":1},{"version":"41d17e1ad9a002feb11c8cdd2777e5bbc0cdb1e3f595d237e4dded0b6949983b","impliedFormat":1},{"version":"8c7e618c2a91ea7f6b5cca272a295864e92c16413be8fc56a943e8c7d5320011","affectsGlobalScope":true,"impliedFormat":1},{"version":"79a85c64bf083c5f4dd7074e804d1000c0c47301b84d48417a224decd681be30","impliedFormat":1},{"version":"9f1e3a76d5f509b5579e567de522b402cb79e201c4f47dcd014451c0580b290d","impliedFormat":1},{"version":"2ddab5b6932f9a6327f71baeb82a1d6b0824e0d23a4c7a5de5d355857113c22f","impliedFormat":1},{"version":"70f3f8b2dcaf7388f26731a59c79437813e3620b594903525a303cb2a7901016","impliedFormat":1},{"version":"62e8f884c3bc6dff6189b6e662ebe8b238a645938f2df7a97b8a82fca56773a4","impliedFormat":1},{"version":"2c2bdaa1d8ead9f68628d6d9d250e46ee8e81aa4898b4769a36956ae15e060fe","impliedFormat":1},{"version":"57a0d1b3d59063d4af2d3f8aac27cfe3c20a0f5d1faf0f8598ccf0b779637939","impliedFormat":1},{"version":"5ff4433a2deae4f85ab1377e90a7554ce6b47ae51c69a84ca30a6e22fae85834","impliedFormat":1},{"version":"82b91e4e42e6c41bc7fc1b6c2dc5eba6a2ba98375eb1f210e6ff6bba2d54177e","impliedFormat":1},{"version":"97234c5303866576f913d0ccae7d58d6322d9e803c7bf1228a3fda46ab8087b2","affectsGlobalScope":true,"impliedFormat":1},{"version":"93ecf87143cac7b9d05cffc1d6bdc075b7e4fdd48ff05f1fad85043f6ae678d3","impliedFormat":1},{"version":"6f200afcb82b3e9a54bed6db23f2edf2508cd266801257312c0f124b47f2bdb9","impliedFormat":1},{"version":"ec501101c2a96133a6c695f934c8f6642149cc728571b29cbb7b770984c1088e","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"39338f84e8c4d0e3de7b3c4a7024fb3925f42100eed5cbe73be58902799dff4d","impliedFormat":1},{"version":"fbf83eb33bf5e329527add92acc65da59323876c702ddccf5f4bf1e848c92369","affectsGlobalScope":true,"impliedFormat":1},{"version":"230763250f20449fa7b3c9273e1967adb0023dc890d4be1553faca658ee65971","impliedFormat":1},{"version":"c3e9078b60cb329d1221f5878e88cecfa3e74460550e605a58fcfb41a66029ff","impliedFormat":1},{"version":"515318bc6e656f75e9e34db625316bfafbafd800dfb1642574af93735a24ad38","impliedFormat":1},{"version":"441b9bb09013654aa3d050e68b06464d8959b473e85868249d9d18f692acd35b","impliedFormat":1},{"version":"bc18a1991ba681f03e13285fa1d7b99b03b67ee671b7bc936254467177543890","impliedFormat":1},{"version":"55246f15e33ff1e2e9e679b25fa9790a48db55dc63d567fe25fac8b6a0efe911","impliedFormat":1},{"version":"fa94bbf532b7af8f394b95fa310980d6e20bd2d4c871c6a6cb9f70f03750a44b","impliedFormat":1},{"version":"03b7804d69cecd66850abada858ed6d4a59001f8c228a9fe212306ee860a4ff6","impliedFormat":1},{"version":"5b26c4dd672d88336bb929787c9bfb55119e80ba89ec6dc923da1c063892843e","affectsGlobalScope":true,"impliedFormat":1},{"version":"7fa2214bb0d64701bc6f9ce8cde2fd2ff8c571e0b23065fa04a8a5a6beb91511","impliedFormat":1},{"version":"987fd1f85dc36f4b2c927aa3db814ac6b452e970f4f55d24ed4ecbb7df09be00","impliedFormat":1},{"version":"f12624a4a8d042b68914eac1b0a16571fc1c523173fcdf2517c65d191bd5a86c","impliedFormat":1},{"version":"b4769767f13a1692a66186e01c3aa186ff808d5ff72ed36eda8c37738fb2ac92","impliedFormat":1},{"version":"841983e39bd4cbb463be385e92fda11057cab368bf27100a801c492f1d86cbaa","impliedFormat":1},{"version":"683edfc4f2b411ebe04729cb6dc09ddd26fbac2c57771a6d7c55964af776e176","impliedFormat":1},{"version":"1ec3f3a5f04cc42df33274fbe5c0937d9a9e06f249a7a26288d7d54f0763ffd4","impliedFormat":1},{"version":"e4156ddb25aa0e3b5303d372f26957b36778f0f6bbd4326359269873295e3058","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc1b433a84cae05ddc5672d4823170af78606ad21ecef60dbc4570190cbf1357","impliedFormat":1},{"version":"e47f532d6e1617833f13a5b0710c0089d402c89c2f2b54f324e5a20e418d287a","impliedFormat":1},{"version":"7f78cfb2b343838612c192cb251746e3a7c62ac7675726a47e130d9b213f6580","impliedFormat":1},{"version":"201db9cf1687fab1adf5282fcba861f382b32303dc4f67c89d59655e78a25461","impliedFormat":1},{"version":"8e2577e7262051fd3c5bd6ca2b2056d358ff8853565720f92455860824c25188","impliedFormat":1},{"version":"7ec8d7d483f7394f9da611b10d3a0e402f76ff5c991261e6ce43a15f81ca4258","impliedFormat":1},{"version":"bb9dbb4b2ad81e3e71ec5ba4314973718555b9d04ba2a17dfbf875efecb8e2c0","impliedFormat":1},{"version":"82c3cc48c692438e41b94d936b8acd75ca97b18c50fa1af8a0715eb9d07d18cd","impliedFormat":1},{"version":"045a210189ec63c5488410b33f9fca53d77d051599d0d6506d8048551399c5f3","impliedFormat":1},{"version":"99ab6d0d660ce4d21efb52288a39fd35bb3f556980ec5463b1ae8f304a3bbc85","impliedFormat":1},{"version":"632c45ccb4cdc2c3a80c7a36a63dd7763016e59cac5e07bfb3e37e3548957028","impliedFormat":1},{"version":"c9a2daf6cd1eb854cd5b9e424247c5e306692055738c2effd35f7871d942b76e","impliedFormat":1},{"version":"afa1c49f8e559e413d57343339db857d2a8159435cf9cf7d4deb41718fff1b88","impliedFormat":1},{"version":"e50a7130339a951e6da9e968ed5521b0997a5b0479e148914087213839b5474c","impliedFormat":1},{"version":"990db7c9743d636fd3b2820ec8c40b512879da4c82e00488e7a352e2d005fc39","impliedFormat":1},{"version":"f091ed534c92e6408336f94323ecfe1890c0b5e0166154120712ed97ac9754a1","impliedFormat":1}],"root":[91,92],"options":{"composite":true,"esModuleInterop":true,"module":199,"outDir":"./","rootDir":"../src","skipLibCheck":true,"target":12,"tsBuildInfoFile":"./.tsbuildinfo"},"referencedMap":[[220,1],[219,2],[156,3],[157,3],[158,4],[94,5],[159,6],[160,7],[161,8],[162,9],[163,10],[164,11],[165,12],[166,13],[167,14],[168,14],[169,15],[170,16],[171,2],[172,17],[173,18],[95,2],[93,2],[174,19],[175,20],[176,21],[218,22],[177,23],[178,24],[179,23],[180,25],[181,26],[182,27],[183,28],[184,28],[185,28],[186,29],[187,30],[188,31],[189,32],[190,33],[191,34],[192,34],[193,35],[194,2],[195,2],[196,36],[197,37],[198,38],[199,39],[200,40],[201,41],[202,42],[203,43],[204,44],[205,45],[206,46],[207,47],[208,48],[209,49],[210,50],[211,51],[212,52],[213,53],[214,54],[96,23],[97,2],[98,55],[99,56],[100,2],[101,57],[102,2],[147,58],[148,59],[149,60],[150,60],[151,61],[152,2],[153,6],[154,62],[155,59],[215,63],[216,64],[217,65],[78,2],[79,2],[14,2],[13,2],[2,2],[15,2],[16,2],[17,2],[18,2],[19,2],[20,2],[21,2],[22,2],[3,2],[23,2],[24,2],[4,2],[25,2],[29,2],[26,2],[27,2],[28,2],[30,2],[31,2],[32,2],[5,2],[33,2],[34,2],[35,2],[36,2],[6,2],[40,2],[37,2],[38,2],[39,2],[41,2],[7,2],[42,2],[47,2],[48,2],[43,2],[44,2],[45,2],[46,2],[8,2],[52,2],[49,2],[50,2],[51,2],[53,2],[9,2],[54,2],[55,2],[56,2],[58,2],[57,2],[59,2],[60,2],[10,2],[61,2],[62,2],[63,2],[11,2],[64,2],[65,2],[66,2],[67,2],[68,2],[69,2],[12,2],[70,2],[71,2],[72,2],[73,2],[74,2],[1,2],[75,2],[76,2],[77,2],[121,66],[135,67],[118,68],[136,69],[145,70],[109,71],[110,72],[108,73],[144,74],[139,75],[143,76],[112,77],[122,78],[132,79],[111,80],[142,81],[106,82],[107,75],[113,78],[114,2],[120,83],[117,78],[104,84],[146,85],[137,86],[125,87],[124,78],[126,88],[129,89],[123,90],[127,91],[140,74],[115,92],[116,93],[130,94],[105,69],[134,95],[133,78],[119,93],[128,96],[131,97],[138,2],[103,2],[141,98],[83,99],[84,99],[87,100],[85,2],[86,101],[88,102],[81,2],[82,103],[89,99],[90,2],[80,2],[91,104],[92,105]],"latestChangedDtsFile":"./DockerService.d.ts","version":"6.0.3"}
@@ -0,0 +1,160 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ import { ServiceDefinition, type Host, type SecretReference, type ServiceDefinitionConfig } from "@saws/core";
3
+ export type DockerHealthCheckConfig = {
4
+ /** Command executed by Docker inside the container using CMD-SHELL. */
5
+ command: string;
6
+ /** Time between checks, expressed as a Docker duration such as "10s". */
7
+ interval?: string;
8
+ /** Maximum time one check may run, expressed as a Docker duration. */
9
+ timeout?: string;
10
+ /** Consecutive failures required before the container is unhealthy. */
11
+ retries?: number;
12
+ /** Startup grace period during which failures do not count. */
13
+ startPeriod?: string;
14
+ };
15
+ export type RestartConfig = "always" | "unless-stopped" | "no";
16
+ type ImageConfig = {
17
+ image: string;
18
+ };
19
+ type DockerFileConfig = {
20
+ dockerfile: string;
21
+ buildContext?: string;
22
+ };
23
+ type DefaultDockerFileConfig = {
24
+ image?: never;
25
+ dockerfile?: never;
26
+ buildContext?: never;
27
+ };
28
+ export type DockerRegistryAuthConfig = {
29
+ username: string;
30
+ password: string | SecretReference;
31
+ };
32
+ export type DockerRunConfig = {
33
+ name: string;
34
+ image: string;
35
+ network: string;
36
+ env?: Record<string, string>;
37
+ envFiles?: string[];
38
+ volumes?: string[];
39
+ ports?: string[];
40
+ entrypoint?: string;
41
+ command?: string[];
42
+ labels?: Record<string, string>;
43
+ restart?: RestartConfig;
44
+ healthCheck?: DockerHealthCheckConfig | false;
45
+ pull?: boolean;
46
+ /** Content digests for runtime files. Values are safe to persist in the config hash. */
47
+ runtimeFileDigests?: Record<string, string>;
48
+ configHash?: string;
49
+ };
50
+ export type RuntimeFile = {
51
+ localPath: string;
52
+ remotePath: string;
53
+ };
54
+ /** A file whose contents affect the behavior of a container. */
55
+ export type ContainerRuntimeFile = {
56
+ /** Stable identifier for the file, preferably its path inside the container. */
57
+ path: string;
58
+ /** Exact bytes that will be made available to the container. */
59
+ contents: string | Uint8Array;
60
+ };
61
+ export type DockerServiceConfig = (ImageConfig | DockerFileConfig | DefaultDockerFileConfig) & {
62
+ host: Host;
63
+ appDirectory?: string;
64
+ network?: string;
65
+ registry?: string;
66
+ auth?: DockerRegistryAuthConfig;
67
+ volumes?: string[];
68
+ ports?: string[];
69
+ entrypoint?: string;
70
+ command?: string[];
71
+ labels?: Record<string, string>;
72
+ restart?: RestartConfig;
73
+ healthCheck?: DockerHealthCheckConfig | false;
74
+ } & ServiceDefinitionConfig;
75
+ export declare class DockerService extends ServiceDefinition {
76
+ readonly host: Host;
77
+ readonly appDirectory: string;
78
+ readonly network: string;
79
+ readonly registry?: string;
80
+ readonly auth?: DockerRegistryAuthConfig;
81
+ readonly image?: string;
82
+ readonly dockerfile?: string;
83
+ readonly buildContext?: string;
84
+ readonly volumes: string[];
85
+ readonly ports: string[];
86
+ readonly entrypoint?: string;
87
+ readonly command: string[];
88
+ readonly labels: Record<string, string>;
89
+ readonly restart?: RestartConfig;
90
+ readonly healthCheck?: DockerHealthCheckConfig | false;
91
+ protected readonly serviceType: string;
92
+ protected devProcess?: ChildProcess;
93
+ private devEnvironmentFile?;
94
+ private readonly localRunAbortController;
95
+ private readonly activeEphemeralContainers;
96
+ private localRegistryAuthenticated;
97
+ private remoteRegistryAuthenticated;
98
+ constructor(config: DockerServiceConfig);
99
+ dev(): Promise<void>;
100
+ deploy(stage: string): Promise<void>;
101
+ logs(stage: string): Promise<void>;
102
+ exit(): void;
103
+ protected getContainerName(stage: string): string;
104
+ protected getContainerEnvironment(stage: string): Promise<Record<string, string>>;
105
+ protected getDockerRunConfig(stage: string, deploy: boolean): Promise<DockerRunConfig>;
106
+ protected onContainerStarted(_stage: string): Promise<void>;
107
+ /**
108
+ * Registers generated or copied files whose contents affect the running container.
109
+ * Only SHA-256 digests of these contents participate in deployment change detection.
110
+ * Subclasses must generate or copy the files before calling `super.deploy(stage)`.
111
+ */
112
+ protected getContainerRuntimeFiles(_stage: string, _deploy: boolean): Promise<readonly ContainerRuntimeFile[]>;
113
+ protected getImage(stage: string, deploy: boolean): string;
114
+ protected buildDockerfileImage(stage: string, deploy: boolean): Promise<void>;
115
+ protected pushDockerfileImage(stage: string): Promise<void>;
116
+ protected getNetwork(stage: string): string;
117
+ protected getAppDirectory(stage: string): string;
118
+ protected getBuiltImageName(stage: string, deploy: boolean): string;
119
+ private buildImage;
120
+ protected pushImage(stage: string, image: string): Promise<void>;
121
+ private authenticateLocalRegistry;
122
+ private authenticateRemoteRegistry;
123
+ private resolveRegistryPassword;
124
+ private getRegistryServer;
125
+ private prepareLocalNetwork;
126
+ protected prepareRemote(stage: string, network: string, dryRun?: boolean): Promise<void>;
127
+ protected assertRemoteHostReady(dryRun?: boolean): Promise<void>;
128
+ protected runLocalDetachedContainer(stage: string, config: DockerRunConfig): Promise<void>;
129
+ protected runEphemeralContainer(stage: string, config: DockerRunConfig, options?: {
130
+ dryRun?: boolean;
131
+ logServiceName?: string;
132
+ }): Promise<void>;
133
+ private startLocalContainer;
134
+ private getLocalRunOptions;
135
+ protected runRemoteContainer(stage: string, config: DockerRunConfig): Promise<void>;
136
+ protected getDockerRunCommand(config: DockerRunConfig, detached: boolean, options?: {
137
+ remove?: boolean;
138
+ includeRestart?: boolean;
139
+ }): string;
140
+ private getDockerHealthCheckArgs;
141
+ protected getContainerConfigHash(config: DockerRunConfig): string;
142
+ private getContainerRuntimeFileDigests;
143
+ protected writeRemoteEnvironmentFile(stage: string, config: DockerRunConfig, dryRun?: boolean): Promise<RuntimeFile | undefined>;
144
+ protected writeLocalEnvironmentFile(stage: string, config: DockerRunConfig): Promise<string | undefined>;
145
+ private withLocalEnvironmentFile;
146
+ protected writeRemoteRuntimeFile(stage: string, relativePath: string, contents: string, options?: boolean | {
147
+ dryRun?: boolean;
148
+ mode?: number;
149
+ }): Promise<RuntimeFile>;
150
+ protected removeRemoteRuntimeFile(runtimeFile: RuntimeFile, dryRun?: boolean): Promise<void>;
151
+ private writeLocalRuntimeFile;
152
+ private observeDevProcess;
153
+ getStdOut(): null;
154
+ getStdErr(): null;
155
+ private removeDevEnvironmentFile;
156
+ private getDockerLogsCommand;
157
+ private runLocalLogsCommand;
158
+ private removeActiveEphemeralContainers;
159
+ }
160
+ export {};
@@ -0,0 +1,656 @@
1
+ import { createHash } from "node:crypto";
2
+ import { spawn, spawnSync } from "node:child_process";
3
+ import { mkdir, rm, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { ServiceDefinition, } from "@saws/core";
6
+ import { runLocal } from "@saws/core/utils/run-local";
7
+ import { shellQuote } from "@saws/core/utils/shell-quote";
8
+ export class DockerService extends ServiceDefinition {
9
+ host;
10
+ appDirectory;
11
+ network;
12
+ registry;
13
+ auth;
14
+ image;
15
+ dockerfile;
16
+ buildContext;
17
+ volumes;
18
+ ports;
19
+ entrypoint;
20
+ command;
21
+ labels;
22
+ restart;
23
+ healthCheck;
24
+ serviceType = "docker";
25
+ devProcess;
26
+ devEnvironmentFile;
27
+ localRunAbortController = new AbortController();
28
+ activeEphemeralContainers = new Set();
29
+ localRegistryAuthenticated = false;
30
+ remoteRegistryAuthenticated = false;
31
+ constructor(config) {
32
+ super(config);
33
+ const hasImage = "image" in config && config.image != null;
34
+ const hasDockerfile = "dockerfile" in config && config.dockerfile != null;
35
+ if (hasImage && hasDockerfile) {
36
+ throw new Error(`Docker service "${config.name}" cannot configure both image and dockerfile`);
37
+ }
38
+ const buildsDockerfile = !hasImage;
39
+ if (buildsDockerfile &&
40
+ config.registry != null &&
41
+ config.registry.replace(/\/+$/, "").length === 0) {
42
+ throw new Error(`Docker service "${config.name}" registry cannot be empty`);
43
+ }
44
+ if (buildsDockerfile && config.auth != null && config.auth.username.trim().length === 0) {
45
+ throw new Error(`Docker service "${config.name}" registry auth username cannot be empty`);
46
+ }
47
+ this.host = config.host;
48
+ this.appDirectory = config.appDirectory ?? "/opt/saws";
49
+ this.network = config.network ?? "saws";
50
+ this.registry = config.registry?.replace(/\/+$/, "");
51
+ this.auth = config.auth;
52
+ if (hasImage) {
53
+ this.image = config.image;
54
+ }
55
+ else {
56
+ this.dockerfile = hasDockerfile ? config.dockerfile : path.join(config.name, "Dockerfile");
57
+ this.buildContext = hasDockerfile ? config.buildContext : config.name;
58
+ }
59
+ this.volumes = config.volumes ?? [];
60
+ this.ports = config.ports ?? [];
61
+ this.entrypoint = config.entrypoint;
62
+ this.command = config.command ?? [];
63
+ this.labels = config.labels ?? {};
64
+ this.restart = config.restart;
65
+ this.healthCheck = config.healthCheck;
66
+ }
67
+ async dev() {
68
+ await super.dev();
69
+ const stage = "local";
70
+ await this.buildDockerfileImage(stage, false);
71
+ const config = await this.getDockerRunConfig(stage, false);
72
+ try {
73
+ this.devEnvironmentFile = await this.writeLocalEnvironmentFile(stage, config);
74
+ this.devProcess = await this.startLocalContainer(config);
75
+ this.observeDevProcess(this.devProcess);
76
+ }
77
+ catch (error) {
78
+ await this.removeDevEnvironmentFile();
79
+ throw error;
80
+ }
81
+ await this.onContainerStarted(stage);
82
+ }
83
+ async deploy(stage) {
84
+ await super.deploy(stage);
85
+ await this.buildDockerfileImage(stage, true);
86
+ await this.pushDockerfileImage(stage);
87
+ const config = await this.getDockerRunConfig(stage, true);
88
+ config.configHash = this.getContainerConfigHash(config);
89
+ if (this.host == null) {
90
+ await this.runLocalDetachedContainer(stage, config);
91
+ await this.onContainerStarted(stage);
92
+ return;
93
+ }
94
+ await this.assertRemoteHostReady();
95
+ let environmentFile;
96
+ try {
97
+ environmentFile = await this.writeRemoteEnvironmentFile(stage, config);
98
+ await this.runRemoteContainer(stage, config);
99
+ }
100
+ finally {
101
+ if (environmentFile != null) {
102
+ await this.removeRemoteRuntimeFile(environmentFile);
103
+ }
104
+ }
105
+ await this.onContainerStarted(stage);
106
+ }
107
+ async logs(stage) {
108
+ if (stage === "local")
109
+ return;
110
+ const command = this.getDockerLogsCommand(stage);
111
+ if (this.host == null) {
112
+ await this.runLocalLogsCommand(command);
113
+ return;
114
+ }
115
+ await this.host.exec(command);
116
+ }
117
+ exit() {
118
+ super.exit();
119
+ this.localRunAbortController.abort();
120
+ this.devProcess?.kill();
121
+ this.devProcess = undefined;
122
+ this.removeActiveEphemeralContainers();
123
+ void this.removeDevEnvironmentFile();
124
+ }
125
+ getContainerName(stage) {
126
+ return `${stage}-${this.name}`.replaceAll("_", "-").toLowerCase();
127
+ }
128
+ async getContainerEnvironment(stage) {
129
+ return {
130
+ ...(await this.getDependenciesEnvironmentVariables(stage)),
131
+ ...(await this.getStageEnvironmentVariables(stage)),
132
+ };
133
+ }
134
+ async getDockerRunConfig(stage, deploy) {
135
+ const runtimeFileDigests = this.getContainerRuntimeFileDigests(await this.getContainerRuntimeFiles(stage, deploy));
136
+ return {
137
+ name: this.getContainerName(stage),
138
+ image: this.getImage(stage, deploy),
139
+ pull: this.dockerfile == null || deploy,
140
+ network: this.getNetwork(stage),
141
+ env: await this.getContainerEnvironment(stage),
142
+ volumes: this.volumes,
143
+ ports: this.ports,
144
+ entrypoint: this.entrypoint,
145
+ command: this.command,
146
+ restart: this.restart,
147
+ healthCheck: this.healthCheck,
148
+ runtimeFileDigests,
149
+ labels: {
150
+ ...this.labels,
151
+ "saws.service": this.name,
152
+ "saws.serviceType": this.serviceType,
153
+ "saws.stage": stage,
154
+ },
155
+ };
156
+ }
157
+ async onContainerStarted(_stage) { }
158
+ /**
159
+ * Registers generated or copied files whose contents affect the running container.
160
+ * Only SHA-256 digests of these contents participate in deployment change detection.
161
+ * Subclasses must generate or copy the files before calling `super.deploy(stage)`.
162
+ */
163
+ async getContainerRuntimeFiles(_stage, _deploy) {
164
+ return [];
165
+ }
166
+ getImage(stage, deploy) {
167
+ if (this.image != null)
168
+ return this.image;
169
+ return this.getBuiltImageName(stage, deploy);
170
+ }
171
+ async buildDockerfileImage(stage, deploy) {
172
+ if (this.dockerfile == null)
173
+ return;
174
+ await this.buildImage(this.getImage(stage, deploy), deploy && this.host != null ? this.host.platform : undefined);
175
+ }
176
+ async pushDockerfileImage(stage) {
177
+ if (this.dockerfile == null || this.host == null)
178
+ return;
179
+ await this.pushImage(stage, this.getImage(stage, true));
180
+ }
181
+ getNetwork(stage) {
182
+ return `${this.network}-${stage}`;
183
+ }
184
+ getAppDirectory(stage) {
185
+ return path.posix.join(this.appDirectory, stage);
186
+ }
187
+ getBuiltImageName(stage, deploy) {
188
+ const repository = `${stage}-${this.name}`
189
+ .toLowerCase()
190
+ .replace(/[^a-z0-9._-]+/g, "-")
191
+ .replace(/^[._-]+|[._-]+$/g, "");
192
+ if (repository.length === 0) {
193
+ throw new Error(`Cannot derive a Docker image name for service "${this.name}"`);
194
+ }
195
+ if (deploy && this.host != null) {
196
+ if (this.registry == null) {
197
+ throw new Error(`Docker service "${this.name}" uses a Dockerfile and remote deploy, but no registry is configured`);
198
+ }
199
+ return `${this.registry}/${repository}:latest`;
200
+ }
201
+ return `saws-${repository}:latest`;
202
+ }
203
+ async buildImage(image, platform) {
204
+ const dockerfile = path.resolve(this.dockerfile);
205
+ const buildContext = path.resolve(this.buildContext ?? path.dirname(this.dockerfile));
206
+ await runLocal([
207
+ "docker build",
208
+ ...(platform == null ? [] : [`--platform ${shellQuote(platform)}`]),
209
+ `-f ${shellQuote(dockerfile)}`,
210
+ `-t ${shellQuote(image)}`,
211
+ shellQuote(buildContext),
212
+ ].join(" "), this.getLocalRunOptions());
213
+ }
214
+ async pushImage(stage, image) {
215
+ await this.authenticateLocalRegistry(stage);
216
+ await runLocal(`docker push ${shellQuote(image)}`, this.getLocalRunOptions());
217
+ }
218
+ async authenticateLocalRegistry(stage) {
219
+ if (this.registry == null || this.auth == null || this.localRegistryAuthenticated)
220
+ return;
221
+ await runLocal([
222
+ "docker login",
223
+ shellQuote(this.getRegistryServer()),
224
+ `--username ${shellQuote(this.auth.username)}`,
225
+ "--password-stdin",
226
+ ].join(" "), this.getLocalRunOptions({ input: `${await this.resolveRegistryPassword(stage)}\n` }));
227
+ this.localRegistryAuthenticated = true;
228
+ }
229
+ async authenticateRemoteRegistry(stage) {
230
+ if (this.registry == null || this.auth == null || this.remoteRegistryAuthenticated)
231
+ return;
232
+ await this.host.exec([
233
+ "docker login",
234
+ shellQuote(this.getRegistryServer()),
235
+ `--username ${shellQuote(this.auth.username)}`,
236
+ "--password-stdin",
237
+ ].join(" "), { input: `${await this.resolveRegistryPassword(stage)}\n` });
238
+ this.remoteRegistryAuthenticated = true;
239
+ }
240
+ async resolveRegistryPassword(stage) {
241
+ return typeof this.auth.password === "string"
242
+ ? this.auth.password
243
+ : this.auth.password.resolve({ stage });
244
+ }
245
+ getRegistryServer() {
246
+ return this.registry.split("/", 1)[0];
247
+ }
248
+ async prepareLocalNetwork(network, options = {}) {
249
+ await runLocal(`docker network inspect ${shellQuote(network)} >/dev/null 2>&1 || docker network create ${shellQuote(network)}`, this.getLocalRunOptions(options));
250
+ }
251
+ async prepareRemote(stage, network, dryRun) {
252
+ if (!dryRun) {
253
+ await this.authenticateRemoteRegistry(stage);
254
+ }
255
+ await this.host.exec(`mkdir -p ${shellQuote(this.getAppDirectory(stage))}`, { dryRun });
256
+ await this.host.exec(`docker network inspect ${shellQuote(network)} >/dev/null 2>&1 || docker network create ${shellQuote(network)}`, { dryRun });
257
+ }
258
+ async assertRemoteHostReady(dryRun) {
259
+ await this.host.assertReady({ dryRun });
260
+ }
261
+ async runLocalDetachedContainer(stage, config) {
262
+ await this.prepareLocalNetwork(config.network);
263
+ if (config.pull !== false) {
264
+ await runLocal(`docker pull ${shellQuote(config.image)}`, this.getLocalRunOptions());
265
+ }
266
+ await this.withLocalEnvironmentFile(stage, config, async () => {
267
+ await runLocal(`docker rm -f ${shellQuote(config.name)} >/dev/null 2>&1 || true`, this.getLocalRunOptions());
268
+ await runLocal(this.getDockerRunCommand({
269
+ ...config,
270
+ labels: {
271
+ ...config.labels,
272
+ "saws.configHash": config.configHash ?? this.getContainerConfigHash(config),
273
+ },
274
+ }, true), this.getLocalRunOptions());
275
+ });
276
+ }
277
+ async runEphemeralContainer(stage, config, options = {}) {
278
+ if (stage === "local" || this.host == null) {
279
+ await this.prepareLocalNetwork(config.network, {
280
+ dryRun: options.dryRun,
281
+ serviceName: options.logServiceName,
282
+ });
283
+ if (config.pull !== false) {
284
+ await runLocal(`docker pull ${shellQuote(config.image)}`, this.getLocalRunOptions({
285
+ dryRun: options.dryRun,
286
+ serviceName: options.logServiceName,
287
+ }));
288
+ }
289
+ await this.withLocalEnvironmentFile(stage, config, async () => {
290
+ await runLocal(`docker rm -f ${shellQuote(config.name)} >/dev/null 2>&1 || true`, this.getLocalRunOptions({
291
+ dryRun: options.dryRun,
292
+ serviceName: options.logServiceName,
293
+ }));
294
+ if (!options.dryRun)
295
+ this.activeEphemeralContainers.add(config.name);
296
+ try {
297
+ await runLocal(this.getDockerRunCommand(config, false, { remove: true, includeRestart: false }), this.getLocalRunOptions({
298
+ dryRun: options.dryRun,
299
+ serviceName: options.logServiceName,
300
+ }));
301
+ }
302
+ finally {
303
+ this.activeEphemeralContainers.delete(config.name);
304
+ }
305
+ });
306
+ return;
307
+ }
308
+ await this.assertRemoteHostReady(options.dryRun);
309
+ await this.prepareRemote(stage, config.network, options.dryRun);
310
+ if (config.pull !== false) {
311
+ await this.host.exec(`docker pull ${shellQuote(config.image)}`, { dryRun: options.dryRun });
312
+ }
313
+ let environmentFile;
314
+ try {
315
+ environmentFile = await this.writeRemoteEnvironmentFile(stage, config, options.dryRun);
316
+ await this.host.exec(`docker rm -f ${shellQuote(config.name)} >/dev/null 2>&1 || true`, {
317
+ dryRun: options.dryRun,
318
+ });
319
+ await this.host.exec(this.getDockerRunCommand(config, false, { remove: true, includeRestart: false }), { dryRun: options.dryRun });
320
+ }
321
+ finally {
322
+ if (environmentFile != null) {
323
+ await this.removeRemoteRuntimeFile(environmentFile, options.dryRun);
324
+ }
325
+ }
326
+ }
327
+ async startLocalContainer(config) {
328
+ await this.prepareLocalNetwork(config.network);
329
+ if (config.pull !== false) {
330
+ await runLocal(`docker pull ${shellQuote(config.image)}`, this.getLocalRunOptions());
331
+ }
332
+ await runLocal(`docker rm -f ${shellQuote(config.name)} >/dev/null 2>&1 || true`, this.getLocalRunOptions());
333
+ const args = [
334
+ "run",
335
+ "--name",
336
+ config.name,
337
+ "--network",
338
+ config.network,
339
+ ...(config.env == null
340
+ ? []
341
+ : Object.entries(config.env).flatMap(([key, value]) => ["-e", `${key}=${value}`])),
342
+ ...(config.envFiles ?? []).flatMap((envFile) => ["--env-file", envFile]),
343
+ ...(config.volumes ?? []).flatMap((volume) => ["-v", volume]),
344
+ ...(config.ports ?? []).flatMap((port) => ["-p", port]),
345
+ ...(config.entrypoint == null ? [] : ["--entrypoint", config.entrypoint]),
346
+ ...Object.entries(config.labels ?? {}).flatMap(([key, value]) => [
347
+ "--label",
348
+ `${key}=${value}`,
349
+ ]),
350
+ ...this.getDockerHealthCheckArgs(config.healthCheck).flatMap((argument) => argument.flagOnly ? [argument.flag] : [argument.flag, argument.value]),
351
+ config.image,
352
+ ...(config.command ?? []),
353
+ ];
354
+ return spawn("docker", args, { stdio: ["ignore", "pipe", "pipe"] });
355
+ }
356
+ getLocalRunOptions(options = {}) {
357
+ const { serviceName, ...runOptions } = options;
358
+ return {
359
+ ...runOptions,
360
+ logSink: this.getRuntimeLogSink(),
361
+ serviceName: serviceName ?? this.name,
362
+ signal: this.localRunAbortController.signal,
363
+ };
364
+ }
365
+ async runRemoteContainer(stage, config) {
366
+ await this.prepareRemote(stage, config.network);
367
+ if (config.pull !== false) {
368
+ await this.host.exec(`docker pull ${shellQuote(config.image)}`);
369
+ }
370
+ const configHash = config.configHash ?? this.getContainerConfigHash(config);
371
+ const containerName = shellQuote(config.name);
372
+ const image = shellQuote(config.image);
373
+ const currentHash = `$(docker inspect --format ${shellQuote('{{index .Config.Labels "saws.configHash"}}')} ${containerName} 2>/dev/null || true)`;
374
+ const currentImage = `$(docker inspect --format ${shellQuote("{{.Image}}")} ${containerName} 2>/dev/null || true)`;
375
+ const desiredImage = `$(docker image inspect --format ${shellQuote("{{.Id}}")} ${image})`;
376
+ const isRunning = `$(docker inspect --format ${shellQuote("{{.State.Running}}")} ${containerName} 2>/dev/null || true)`;
377
+ await this.host.exec([
378
+ `if [ "${currentHash}" = ${shellQuote(configHash)} ] && [ "${currentImage}" = "${desiredImage}" ]; then`,
379
+ `if [ "${isRunning}" = "true" ]; then`,
380
+ `echo ${shellQuote(`Container ${config.name} is unchanged`)}`,
381
+ "else",
382
+ `docker start ${containerName}`,
383
+ "fi",
384
+ "else",
385
+ `docker rm -f ${containerName} >/dev/null 2>&1 || true`,
386
+ this.getDockerRunCommand({
387
+ ...config,
388
+ labels: {
389
+ ...config.labels,
390
+ "saws.configHash": configHash,
391
+ },
392
+ }, true),
393
+ "fi",
394
+ ].join("\n"));
395
+ }
396
+ getDockerRunCommand(config, detached, options = {}) {
397
+ const envArgs = Object.entries(config.env ?? {})
398
+ .map(([key, value]) => `-e ${shellQuote(`${key}=${value}`)}`)
399
+ .join(" ");
400
+ const envFileArgs = (config.envFiles ?? [])
401
+ .map((envFile) => `--env-file ${shellQuote(envFile)}`)
402
+ .join(" ");
403
+ const volumeArgs = (config.volumes ?? []).map((volume) => `-v ${shellQuote(volume)}`).join(" ");
404
+ const portArgs = (config.ports ?? []).map((port) => `-p ${shellQuote(port)}`).join(" ");
405
+ const entrypointArg = config.entrypoint == null ? "" : `--entrypoint ${shellQuote(config.entrypoint)}`;
406
+ const labelArgs = Object.entries(config.labels ?? {})
407
+ .map(([key, value]) => `--label ${shellQuote(`${key}=${value}`)}`)
408
+ .join(" ");
409
+ const healthCheckArgs = this.getDockerHealthCheckArgs(config.healthCheck)
410
+ .map((argument) => argument.flagOnly ? argument.flag : `${argument.flag} ${shellQuote(argument.value)}`)
411
+ .join(" ");
412
+ const command = (config.command ?? []).map((part) => shellQuote(part)).join(" ");
413
+ return [
414
+ "docker run",
415
+ options.remove ? "--rm" : "",
416
+ detached ? "-d" : "",
417
+ `--name ${shellQuote(config.name)}`,
418
+ `--network ${shellQuote(config.network)}`,
419
+ options.includeRestart === false
420
+ ? ""
421
+ : `--restart ${shellQuote(config.restart ?? "unless-stopped")}`,
422
+ envArgs,
423
+ envFileArgs,
424
+ volumeArgs,
425
+ portArgs,
426
+ entrypointArg,
427
+ labelArgs,
428
+ healthCheckArgs,
429
+ shellQuote(config.image),
430
+ command,
431
+ ]
432
+ .filter(Boolean)
433
+ .join(" ");
434
+ }
435
+ getDockerHealthCheckArgs(healthCheck) {
436
+ if (healthCheck == null)
437
+ return [];
438
+ if (healthCheck === false)
439
+ return [{ flag: "--no-healthcheck", flagOnly: true }];
440
+ if (healthCheck.command.length === 0) {
441
+ throw new Error("Docker health check command cannot be empty");
442
+ }
443
+ if (healthCheck.retries != null &&
444
+ (!Number.isInteger(healthCheck.retries) || healthCheck.retries < 1)) {
445
+ throw new Error("Docker health check retries must be a positive integer");
446
+ }
447
+ const args = [{ flag: "--health-cmd", flagOnly: false, value: healthCheck.command }];
448
+ for (const [flag, value] of [
449
+ ["--health-interval", healthCheck.interval],
450
+ ["--health-timeout", healthCheck.timeout],
451
+ ["--health-start-period", healthCheck.startPeriod],
452
+ ]) {
453
+ if (value == null)
454
+ continue;
455
+ if (!isDockerDuration(value)) {
456
+ throw new Error(`${flag.slice(2)} must be a positive Docker duration`);
457
+ }
458
+ args.push({ flag, flagOnly: false, value });
459
+ }
460
+ if (healthCheck.retries != null) {
461
+ args.push({ flag: "--health-retries", flagOnly: false, value: String(healthCheck.retries) });
462
+ }
463
+ return args;
464
+ }
465
+ getContainerConfigHash(config) {
466
+ const labels = { ...config.labels };
467
+ delete labels["saws.configHash"];
468
+ return createHash("sha256")
469
+ .update(JSON.stringify({
470
+ name: config.name,
471
+ image: config.image,
472
+ network: config.network,
473
+ environment: sortRecord(config.env),
474
+ envFiles: [...(config.envFiles ?? [])].sort(),
475
+ volumes: [...(config.volumes ?? [])].sort(),
476
+ ports: [...(config.ports ?? [])].sort(),
477
+ entrypoint: config.entrypoint,
478
+ command: config.command ?? [],
479
+ labels: sortRecord(labels),
480
+ runtimeFileDigests: config.runtimeFileDigests == null ? undefined : sortRecord(config.runtimeFileDigests),
481
+ restart: config.restart ?? "unless-stopped",
482
+ healthCheck: config.healthCheck === false
483
+ ? false
484
+ : config.healthCheck == null
485
+ ? null
486
+ : {
487
+ command: config.healthCheck.command,
488
+ interval: config.healthCheck.interval,
489
+ timeout: config.healthCheck.timeout,
490
+ retries: config.healthCheck.retries,
491
+ startPeriod: config.healthCheck.startPeriod,
492
+ },
493
+ }))
494
+ .digest("hex");
495
+ }
496
+ getContainerRuntimeFileDigests(files) {
497
+ if (files.length === 0)
498
+ return undefined;
499
+ const digests = {};
500
+ for (const file of files) {
501
+ if (file.path.length === 0) {
502
+ throw new Error("Container runtime file path cannot be empty");
503
+ }
504
+ if (digests[file.path] != null) {
505
+ throw new Error(`Container runtime file path "${file.path}" is registered more than once`);
506
+ }
507
+ digests[file.path] = createHash("sha256").update(file.contents).digest("hex");
508
+ }
509
+ return sortRecord(digests);
510
+ }
511
+ async writeRemoteEnvironmentFile(stage, config, dryRun) {
512
+ const contents = serializeEnvironment(config.env);
513
+ if (contents == null)
514
+ return undefined;
515
+ const runtimeFile = await this.writeRemoteRuntimeFile(stage, `${this.name}/container.env`, contents, dryRun);
516
+ config.env = undefined;
517
+ config.envFiles = [...(config.envFiles ?? []), runtimeFile.remotePath];
518
+ return runtimeFile;
519
+ }
520
+ async writeLocalEnvironmentFile(stage, config) {
521
+ const contents = serializeEnvironment(config.env);
522
+ if (contents == null)
523
+ return undefined;
524
+ const localPath = await this.writeLocalRuntimeFile(stage, `${this.name}/container.env`, contents);
525
+ config.env = undefined;
526
+ config.envFiles = [...(config.envFiles ?? []), localPath];
527
+ return localPath;
528
+ }
529
+ async withLocalEnvironmentFile(stage, config, callback) {
530
+ const environmentFile = await this.writeLocalEnvironmentFile(stage, config);
531
+ try {
532
+ return await callback();
533
+ }
534
+ finally {
535
+ if (environmentFile != null) {
536
+ await rm(environmentFile, { force: true });
537
+ }
538
+ }
539
+ }
540
+ async writeRemoteRuntimeFile(stage, relativePath, contents, options = {}) {
541
+ const dryRun = typeof options === "boolean" ? options : options.dryRun;
542
+ const mode = typeof options === "boolean" ? 0o600 : (options.mode ?? 0o600);
543
+ const localDir = path.resolve(".saws", "hosts", this.host.name, stage);
544
+ await mkdir(localDir, { recursive: true });
545
+ const localPath = path.join(localDir, relativePath);
546
+ await mkdir(path.dirname(localPath), { recursive: true });
547
+ await writeFile(localPath, contents, { mode });
548
+ const remotePath = path.posix.join(this.getAppDirectory(stage), relativePath);
549
+ await this.host.exec(`mkdir -p ${shellQuote(path.posix.dirname(remotePath))}`, { dryRun });
550
+ await this.host.copyFile(localPath, remotePath, { dryRun });
551
+ await this.host.exec(`chmod ${mode.toString(8)} ${shellQuote(remotePath)}`, { dryRun });
552
+ return { localPath, remotePath };
553
+ }
554
+ async removeRemoteRuntimeFile(runtimeFile, dryRun) {
555
+ await rm(runtimeFile.localPath, { force: true });
556
+ await this.host.exec(`rm -f ${shellQuote(runtimeFile.remotePath)}`, { dryRun });
557
+ }
558
+ async writeLocalRuntimeFile(stage, relativePath, contents) {
559
+ const localPath = path.resolve(".saws", "local", stage, relativePath);
560
+ await mkdir(path.dirname(localPath), { recursive: true });
561
+ await writeFile(localPath, contents, { mode: 0o600 });
562
+ return localPath;
563
+ }
564
+ observeDevProcess(process) {
565
+ process.stdout?.on("data", (chunk) => {
566
+ this.writeRuntimeLog(chunk.toString("utf8"), "stdout");
567
+ });
568
+ process.stderr?.on("data", (chunk) => {
569
+ this.writeRuntimeLog(chunk.toString("utf8"), "stderr");
570
+ });
571
+ process.once("error", (error) => {
572
+ this.writeRuntimeLog(`${error.stack ?? error.message}\n`, "stderr");
573
+ });
574
+ process.once("exit", (code, signal) => {
575
+ if (this.devProcess === process)
576
+ this.devProcess = undefined;
577
+ if (code !== 0 && signal !== "SIGTERM" && signal !== "SIGINT") {
578
+ this.writeRuntimeLog(`Docker container exited with code ${code ?? "unknown"}${signal == null ? "" : ` (${signal})`}\n`, "stderr");
579
+ }
580
+ });
581
+ }
582
+ getStdOut() {
583
+ return null;
584
+ }
585
+ getStdErr() {
586
+ return null;
587
+ }
588
+ async removeDevEnvironmentFile() {
589
+ if (this.devEnvironmentFile == null)
590
+ return;
591
+ const localPath = this.devEnvironmentFile;
592
+ this.devEnvironmentFile = undefined;
593
+ await rm(localPath, { force: true });
594
+ }
595
+ getDockerLogsCommand(stage) {
596
+ return [
597
+ `CONTAINERS=$(docker ps --filter label=saws.service=${shellQuote(this.name)} --filter label=saws.stage=${shellQuote(stage)} --format '{{.Names}}')`,
598
+ 'if [ -z "$CONTAINERS" ]; then',
599
+ `echo ${shellQuote(`No running containers found for ${this.name} (${stage})`)} >&2`,
600
+ "exit 1",
601
+ "fi",
602
+ "PIDS=",
603
+ 'cleanup() { for pid in $PIDS; do kill "$pid" >/dev/null 2>&1 || true; done; }',
604
+ "trap cleanup INT TERM EXIT",
605
+ "for container in $CONTAINERS; do",
606
+ 'docker logs --tail 100 -f "$container" &',
607
+ 'PIDS="$PIDS $!"',
608
+ "done",
609
+ "wait",
610
+ ].join("\n");
611
+ }
612
+ async runLocalLogsCommand(command) {
613
+ await new Promise((resolve, reject) => {
614
+ const child = spawn(command, {
615
+ shell: true,
616
+ stdio: "inherit",
617
+ });
618
+ child.on("error", reject);
619
+ child.on("exit", (code) => {
620
+ if (code === 0) {
621
+ resolve();
622
+ return;
623
+ }
624
+ reject(new Error(`docker logs exited with code ${code}`));
625
+ });
626
+ });
627
+ }
628
+ removeActiveEphemeralContainers() {
629
+ for (const container of this.activeEphemeralContainers) {
630
+ spawnSync("docker", ["rm", "-f", container], { stdio: "ignore" });
631
+ }
632
+ this.activeEphemeralContainers.clear();
633
+ }
634
+ }
635
+ function serializeEnvironment(environment) {
636
+ const entries = Object.entries(environment ?? {});
637
+ if (entries.length === 0)
638
+ return undefined;
639
+ for (const [key, value] of entries) {
640
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) {
641
+ throw new Error(`Invalid Docker environment variable name: ${key}`);
642
+ }
643
+ if (value.includes("\n") || value.includes("\r")) {
644
+ throw new Error(`Docker environment variable ${key} contains a newline`);
645
+ }
646
+ }
647
+ return `${entries.map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
648
+ }
649
+ function sortRecord(record) {
650
+ return Object.fromEntries(Object.entries(record ?? {}).sort(([left], [right]) => left.localeCompare(right)));
651
+ }
652
+ function isDockerDuration(value) {
653
+ if (!/^(?:\d+(?:\.\d+)?(?:ns|us|µs|ms|s|m|h))+$/.test(value))
654
+ return false;
655
+ return [...value.matchAll(/(\d+(?:\.\d+)?)(?:ns|us|µs|ms|s|m|h)/g)].some((match) => Number(match[1]) > 0);
656
+ }
@@ -0,0 +1 @@
1
+ export * from "./DockerService.js";
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ export * from "./DockerService.js";
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@saws/docker-service",
3
+ "version": "2.0.0-beta.11",
4
+ "description": "",
5
+ "license": "ISC",
6
+ "author": "",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/shichongrui/saws.git"
10
+ },
11
+ "files": [
12
+ "./dist"
13
+ ],
14
+ "type": "module",
15
+ "types": "./dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ }
21
+ },
22
+ "scripts": {
23
+ "test": "tsc -b && node --test tests/*.test.mjs"
24
+ },
25
+ "dependencies": {
26
+ "@saws/core": "2.0.0-beta.11"
27
+ }
28
+ }