turborepo-remote-cache 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +120 -0
- package/build/app.js +45 -0
- package/build/app.js.map +1 -0
- package/build/cli.js +5 -0
- package/build/cli.js.map +1 -0
- package/build/env.js +42 -0
- package/build/env.js.map +1 -0
- package/build/index.js +24 -0
- package/build/index.js.map +1 -0
- package/build/logger.js +29 -0
- package/build/logger.js.map +1 -0
- package/build/plugins/config.js +9 -0
- package/build/plugins/config.js.map +1 -0
- package/build/plugins/remote-cache/index.js +40 -0
- package/build/plugins/remote-cache/index.js.map +1 -0
- package/build/plugins/remote-cache/routes/get-artifact.js +22 -0
- package/build/plugins/remote-cache/routes/get-artifact.js.map +1 -0
- package/build/plugins/remote-cache/routes/index.js +8 -0
- package/build/plugins/remote-cache/routes/index.js.map +1 -0
- package/build/plugins/remote-cache/routes/put-artifact.js +23 -0
- package/build/plugins/remote-cache/routes/put-artifact.js.map +1 -0
- package/build/plugins/remote-cache/routes/schema.js +15 -0
- package/build/plugins/remote-cache/routes/schema.js.map +1 -0
- package/build/plugins/remote-cache/storage/index.js +40 -0
- package/build/plugins/remote-cache/storage/index.js.map +1 -0
- package/build/plugins/remote-cache/storage/local.js +12 -0
- package/build/plugins/remote-cache/storage/local.js.map +1 -0
- package/build/plugins/remote-cache/storage/s3.js +27 -0
- package/build/plugins/remote-cache/storage/s3.js.map +1 -0
- package/build/vercel.js +10 -0
- package/build/vercel.js.map +1 -0
- package/package.json +93 -0
- package/vercel.json +15 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Maksim Sinik, Matteo Vivona
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
 [](https://github.com/fox1t/turborepo-remote-cache/actions/workflows/build.yml) [](https://hub.docker.com/r/fox1t/turborepo-remote-cache)
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
This project is an open-source implementation of the [Turborepo custom remote cache server](https://turborepo.org/docs/features/remote-caching#custom-remote-caches). If Vercel's official cache server isn't a viable option, this server is an alternative for self-hosted deployments.
|
|
8
|
+
It supports several storage providers and deploys environments. Moreover, the project provides __"deploy to "__ buttons for one-click deployments whenever possible.
|
|
9
|
+
|
|
10
|
+
## Index
|
|
11
|
+
- [Supported Storage Providers](#supported-storage-providers)
|
|
12
|
+
- [ENV VARS](#env-vars)
|
|
13
|
+
- [Deployment Instructions](#deployment-environments)
|
|
14
|
+
- [Enable custom remote caching in a Turborepo monorepo](#enable-custom-remote-caching-in-your-turborepo-monorepo)
|
|
15
|
+
|
|
16
|
+
## Supported Storage Providers
|
|
17
|
+
- [x] Local filesystem
|
|
18
|
+
- [x] AWS S3
|
|
19
|
+
- [ ] Azure Blob Storage (WIP)
|
|
20
|
+
- [ ] Google Cloud Storage (WIP)
|
|
21
|
+
- [ ] Google Drive Blobs (WIP)
|
|
22
|
+
|
|
23
|
+
## ENV VARS
|
|
24
|
+
|
|
25
|
+
- `NODE_ENV`: String. Optional. Possible values: `development | production`. Default value: `production`.
|
|
26
|
+
- `PORT`: Number. Optional. Default value: `3000`.
|
|
27
|
+
- `TURBO_TOKEN`: String. Secret token used for the authentication. The value must be the same one provided for the `token` parameter of the `build` script. See [Enable custom remote caching in a Turborepo monorepo](#enable-custom-remote-caching-in-your-turborepo-monorepo) for more info. This value should be private.
|
|
28
|
+
- `LOG_LEVEL`: String. Optional. Default value: `'info'`
|
|
29
|
+
- `STORAGE_PROVIDER`: Optional. Possible values: `local | s3`. Default value: "local". Use this var to choose the storage provider.
|
|
30
|
+
- `STORAGE_PATH`: String. Caching folder. If `STORAGE_PROVIDER` is set to `s3`, this will be the name of the bucket.
|
|
31
|
+
- `S3_ACCESS_KEY`: String. Used only if `STORAGE_PROVIDER=s3`
|
|
32
|
+
- `S3_SECRET_KEY`: String. Used only if `STORAGE_PROVIDER=s3`
|
|
33
|
+
- `S3_REGION`: String. Used only if `STORAGE_PROVIDER=s3`
|
|
34
|
+
- `S3_ENDPOINT`: String. Optional. Used only if `STORAGE_PROVIDER=s3`. __NOTE: This var can be omitted if the other s3 vars are provided.__
|
|
35
|
+
|
|
36
|
+
## Deployment Environments
|
|
37
|
+
- [Deploy on Vercel](#deploy-on-vercel)
|
|
38
|
+
- [Deploy on Docker](#deploy-on-docker)
|
|
39
|
+
- [Deploy on DigitalOcean](#deploy-on-digitalocean)
|
|
40
|
+
|
|
41
|
+
## Enable custom remote caching in your Turborepo monorepo
|
|
42
|
+
To enable a custom remote caching server in your Turborepo monorepo, you must add a config file by hand. The `turbo login` command works only with the official Vercel server.
|
|
43
|
+
|
|
44
|
+
1. create `.turbo` folder at the root of your monorepo
|
|
45
|
+
2. create `config.json` file inside it, and add these properties:
|
|
46
|
+
- `teamId`: it could be any string that starts with `"team_"`. This property will be used as a cache storage folder for the current repository. Ex. `team_myteam`
|
|
47
|
+
- `apiUrl`: address of a running `turborepo-remote-cache` server.
|
|
48
|
+
|
|
49
|
+
For example:
|
|
50
|
+
|
|
51
|
+
`.turbo/config.json`
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"teamId": "team_FcALQN9XEVbeJ1NjTQoS9Wup",
|
|
55
|
+
"apiUrl": "http://localhost:3000"
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
3. Modify your Turborepo top-level `build` script, adding the `--token=` parameter.
|
|
59
|
+
__Note: The token value must be the same used for your `TURBO_TOKEN` env var. See [ENV_VARS](#env-vars) section for more info.__
|
|
60
|
+
|
|
61
|
+
For example:
|
|
62
|
+
|
|
63
|
+
`package.json`
|
|
64
|
+
```json
|
|
65
|
+
//...
|
|
66
|
+
"build": "turbo run build --token=\"yourToken\"",
|
|
67
|
+
"dev": "turbo run dev --parallel",
|
|
68
|
+
"lint": "turbo run lint",
|
|
69
|
+
"format": "prettier --write \"**/*.{ts,tsx,md}\""
|
|
70
|
+
//...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Deploy on Vercel
|
|
74
|
+
The server can be easily deployed as Vercel Function using the deploy button.
|
|
75
|
+
|
|
76
|
+
__Note: Local storage isn't supported for this deployment method.__
|
|
77
|
+
|
|
78
|
+
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Ffox1t%2Fturborepo-remote-cache&env=NODE_ENV,TURBO_TOKEN,STORAGE_PROVIDER,STORAGE_PATH,S3_ACCESS_KEY,S3_SECRET_KEY,S3_REGION,S3_ENDPOINT&envDescription=The%20server%20needs%20several%20credentials.%20The%20required%20environmental%20variables%20can%20be%20found%20here%3A&envLink=https%3A%2F%2Fgithub.com%2Ffox1t%2Fturborepo-remote-cache%23readme)
|
|
79
|
+
|
|
80
|
+
## Deploy on Docker
|
|
81
|
+
You can find the image on the [dockerhub](https://hub.docker.com/r/fox1t/turborepo-remote-cache).
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
1. create an `.env` file, containing all of the env vars you need. Check [ENV_VARS](#env-vars) for more info.
|
|
85
|
+
```sh
|
|
86
|
+
NODE_ENV=
|
|
87
|
+
PORT=
|
|
88
|
+
TURBO_TOKEN=
|
|
89
|
+
LOG_LEVEL=
|
|
90
|
+
STORAGE_PROVIDER=
|
|
91
|
+
STORAGE_PATH=
|
|
92
|
+
S3_ACCESS_KEY=
|
|
93
|
+
S3_SECRET_KEY=
|
|
94
|
+
S3_REGION=
|
|
95
|
+
S3_ENDPOINT=
|
|
96
|
+
```
|
|
97
|
+
2. run the image using the `.env` file created on the step one.
|
|
98
|
+
```sh
|
|
99
|
+
docker run --env-file=.env -p 3000:3000 fox1t/turborepo-remote-cache
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Deploy on DigitalOcean
|
|
103
|
+
The server can be easily deployed on DigitalOcean App Service.
|
|
104
|
+
|
|
105
|
+
__Note: Local storage isn't supported for this deployment method.__
|
|
106
|
+
|
|
107
|
+
[](https://cloud.digitalocean.com/apps/new?repo=https://github.com/fox1t/turborepo-remote-cache/tree/main)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## Contribute to this project
|
|
111
|
+
1. clone this repository
|
|
112
|
+
|
|
113
|
+
`git clone git@github.com:fox1t/turborepo-remote-cache.git`
|
|
114
|
+
|
|
115
|
+
2. `cd turborepo-remote-cache`
|
|
116
|
+
3. `npm i`
|
|
117
|
+
4. `cp .env.example .env`
|
|
118
|
+
5. put your env vars to the `env` file. See [ENV_VARS](#env-vars) section for more details.
|
|
119
|
+
6. `npm run dev`
|
|
120
|
+
|
package/build/app.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createApp = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fastify_1 = (0, tslib_1.__importDefault)(require("fastify"));
|
|
6
|
+
const hyperid_1 = (0, tslib_1.__importDefault)(require("hyperid"));
|
|
7
|
+
const boom_1 = require("@hapi/boom");
|
|
8
|
+
const remote_cache_1 = (0, tslib_1.__importDefault)(require("./plugins/remote-cache"));
|
|
9
|
+
const config_1 = (0, tslib_1.__importDefault)(require("./plugins/config"));
|
|
10
|
+
const logger_1 = require("./logger");
|
|
11
|
+
const uuid = (0, hyperid_1.default)({ urlSafe: true });
|
|
12
|
+
function createApp(options = {}) {
|
|
13
|
+
const app = (0, fastify_1.default)({
|
|
14
|
+
logger: logger_1.logger,
|
|
15
|
+
genReqId: () => uuid(),
|
|
16
|
+
...options,
|
|
17
|
+
});
|
|
18
|
+
app.register(config_1.default).after(() => {
|
|
19
|
+
app.register(remote_cache_1.default, {
|
|
20
|
+
allowedTokens: [app.config.TURBO_TOKEN],
|
|
21
|
+
provider: app.config.STORAGE_PROVIDER,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
app.setErrorHandler((err, request, reply) => {
|
|
25
|
+
if (err.validation) {
|
|
26
|
+
reply.log.warn(err);
|
|
27
|
+
reply.code(400).send({ message: err.message });
|
|
28
|
+
}
|
|
29
|
+
else if ((0, boom_1.isBoom)(err)) {
|
|
30
|
+
reply.log.warn(err);
|
|
31
|
+
reply
|
|
32
|
+
.code(err.output.statusCode)
|
|
33
|
+
.send(err.data != null
|
|
34
|
+
? { message: err.message, ...err.data }
|
|
35
|
+
: { message: err.output.payload.message });
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
request.log.error(err);
|
|
39
|
+
reply.code(500).send({ message: err.message });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
return app;
|
|
43
|
+
}
|
|
44
|
+
exports.createApp = createApp;
|
|
45
|
+
//# sourceMappingURL=app.js.map
|
package/build/app.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":";;;;AAAA,mEAAwE;AACxE,mEAA6B;AAC7B,qCAAmC;AACnC,uFAAgD;AAChD,2EAAqC;AACrC,qCAAiC;AAEjC,MAAM,IAAI,GAAG,IAAA,iBAAO,EAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAA;AAEvC,SAAgB,SAAS,CAAC,UAAgC,EAAE;IAC1D,MAAM,GAAG,GAAG,IAAA,iBAAO,EAAC;QAClB,MAAM,EAAN,eAAM;QACN,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE;QACtB,GAAG,OAAO;KACX,CAAC,CAAA;IAEF,GAAG,CAAC,QAAQ,CAAC,gBAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QAC9B,GAAG,CAAC,QAAQ,CAAC,sBAAW,EAAE;YACxB,aAAa,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;YACvC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,gBAAgB;SACtC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,GAAG,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;QAC1C,IAAI,GAAG,CAAC,UAAU,EAAE;YAClB,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;SAC/C;aAAM,IAAI,IAAA,aAAM,EAAC,GAAG,CAAC,EAAE;YACtB,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACnB,KAAK;iBACF,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;iBAC3B,IAAI,CACH,GAAG,CAAC,IAAI,IAAI,IAAI;gBACd,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE;gBACvC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAC5C,CAAA;SACJ;aAAM;YACL,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACtB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAA;SAC/C;IACH,CAAC,CAAC,CAAA;IAEF,OAAO,GAAG,CAAA;AACZ,CAAC;AAlCD,8BAkCC","sourcesContent":["import Fastify, { FastifyInstance, FastifyServerOptions } from 'fastify'\nimport hyperid from 'hyperid'\nimport { isBoom } from '@hapi/boom'\nimport remoteCache from './plugins/remote-cache'\nimport config from './plugins/config'\nimport { logger } from './logger'\n\nconst uuid = hyperid({ urlSafe: true })\n\nexport function createApp(options: FastifyServerOptions = {}): FastifyInstance {\n const app = Fastify({\n logger,\n genReqId: () => uuid(),\n ...options,\n })\n\n app.register(config).after(() => {\n app.register(remoteCache, {\n allowedTokens: [app.config.TURBO_TOKEN],\n provider: app.config.STORAGE_PROVIDER,\n })\n })\n\n app.setErrorHandler((err, request, reply) => {\n if (err.validation) {\n reply.log.warn(err)\n reply.code(400).send({ message: err.message })\n } else if (isBoom(err)) {\n reply.log.warn(err)\n reply\n .code(err.output.statusCode)\n .send(\n err.data != null\n ? { message: err.message, ...err.data }\n : { message: err.output.payload.message },\n )\n } else {\n request.log.error(err)\n reply.code(500).send({ message: err.message })\n }\n })\n\n return app\n}\n"]}
|
package/build/cli.js
ADDED
package/build/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA,mBAAgB","sourcesContent":["#!/usr/bin/env node\nimport './index'\n"]}
|
package/build/env.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.env = exports.STORAGE_PROVIDERS = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const ajv_1 = (0, tslib_1.__importDefault)(require("ajv"));
|
|
6
|
+
const env_schema_1 = (0, tslib_1.__importDefault)(require("env-schema"));
|
|
7
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
8
|
+
var NODE_ENVS;
|
|
9
|
+
(function (NODE_ENVS) {
|
|
10
|
+
NODE_ENVS["PRODUCTION"] = "production";
|
|
11
|
+
NODE_ENVS["DEVELOPMENT"] = "development";
|
|
12
|
+
NODE_ENVS["TEST"] = "test";
|
|
13
|
+
})(NODE_ENVS || (NODE_ENVS = {}));
|
|
14
|
+
var STORAGE_PROVIDERS;
|
|
15
|
+
(function (STORAGE_PROVIDERS) {
|
|
16
|
+
STORAGE_PROVIDERS["LOCAL"] = "local";
|
|
17
|
+
STORAGE_PROVIDERS["S3"] = "S3";
|
|
18
|
+
STORAGE_PROVIDERS["s3"] = "s3";
|
|
19
|
+
})(STORAGE_PROVIDERS = exports.STORAGE_PROVIDERS || (exports.STORAGE_PROVIDERS = {}));
|
|
20
|
+
const schema = typebox_1.Type.Object({
|
|
21
|
+
NODE_ENV: typebox_1.Type.Optional(typebox_1.Type.Enum(NODE_ENVS, { default: NODE_ENVS.PRODUCTION })),
|
|
22
|
+
TURBO_TOKEN: typebox_1.Type.String(),
|
|
23
|
+
PORT: typebox_1.Type.Number({ default: 3000 }),
|
|
24
|
+
LOG_LEVEL: typebox_1.Type.Optional(typebox_1.Type.String({ default: 'info' })),
|
|
25
|
+
STORAGE_PROVIDER: typebox_1.Type.Optional(typebox_1.Type.Enum(STORAGE_PROVIDERS, { default: STORAGE_PROVIDERS.LOCAL })),
|
|
26
|
+
STORAGE_PATH: typebox_1.Type.Optional(typebox_1.Type.String()),
|
|
27
|
+
S3_ACCESS_KEY: typebox_1.Type.Optional(typebox_1.Type.String()),
|
|
28
|
+
S3_SECRET_KEY: typebox_1.Type.Optional(typebox_1.Type.String()),
|
|
29
|
+
S3_REGION: typebox_1.Type.Optional(typebox_1.Type.String()),
|
|
30
|
+
S3_ENDPOINT: typebox_1.Type.Optional(typebox_1.Type.String()),
|
|
31
|
+
}, { additionalProperties: false });
|
|
32
|
+
exports.env = (0, env_schema_1.default)({
|
|
33
|
+
ajv: new ajv_1.default({
|
|
34
|
+
removeAdditional: true,
|
|
35
|
+
useDefaults: true,
|
|
36
|
+
coerceTypes: true,
|
|
37
|
+
keywords: ['kind', 'RegExp', 'modifier'],
|
|
38
|
+
}),
|
|
39
|
+
dotenv: process.env.NODE_ENV === NODE_ENVS.DEVELOPMENT ? true : false,
|
|
40
|
+
schema,
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=env.js.map
|
package/build/env.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":";;;;AAAA,2DAAqB;AACrB,yEAAkC;AAClC,+CAAgD;AAEhD,IAAK,SAIJ;AAJD,WAAK,SAAS;IACZ,sCAAyB,CAAA;IACzB,wCAA2B,CAAA;IAC3B,0BAAa,CAAA;AACf,CAAC,EAJI,SAAS,KAAT,SAAS,QAIb;AAED,IAAY,iBAIX;AAJD,WAAY,iBAAiB;IAC3B,oCAAe,CAAA;IACf,8BAAS,CAAA;IACT,8BAAS,CAAA;AACX,CAAC,EAJW,iBAAiB,GAAjB,yBAAiB,KAAjB,yBAAiB,QAI5B;AAED,MAAM,MAAM,GAAG,cAAI,CAAC,MAAM,CACxB;IACE,QAAQ,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC;IAChF,WAAW,EAAE,cAAI,CAAC,MAAM,EAAE;IAC1B,IAAI,EAAE,cAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACpC,SAAS,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAC1D,gBAAgB,EAAE,cAAI,CAAC,QAAQ,CAC7B,cAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAAE,OAAO,EAAE,iBAAiB,CAAC,KAAK,EAAE,CAAC,CACnE;IACD,YAAY,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,EAAE,CAAC;IAC1C,aAAa,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,EAAE,CAAC;IAC3C,aAAa,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,EAAE,CAAC;IAC3C,SAAS,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,EAAE,CAAC;IACvC,WAAW,EAAE,cAAI,CAAC,QAAQ,CAAC,cAAI,CAAC,MAAM,EAAE,CAAC;CAC1C,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAA;AAEY,QAAA,GAAG,GAAG,IAAA,oBAAS,EAAwB;IAClD,GAAG,EAAE,IAAI,aAAG,CAAC;QACX,gBAAgB,EAAE,IAAI;QACtB,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,IAAI;QACjB,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC;KACzC,CAAC;IACF,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK;IACrE,MAAM;CACP,CAAC,CAAA","sourcesContent":["import Ajv from 'ajv'\nimport envSchema from 'env-schema'\nimport { Type, Static } from '@sinclair/typebox'\n\nenum NODE_ENVS {\n PRODUCTION = 'production',\n DEVELOPMENT = 'development',\n TEST = 'test',\n}\n\nexport enum STORAGE_PROVIDERS {\n LOCAL = 'local',\n S3 = 'S3',\n s3 = 's3',\n}\n\nconst schema = Type.Object(\n {\n NODE_ENV: Type.Optional(Type.Enum(NODE_ENVS, { default: NODE_ENVS.PRODUCTION })),\n TURBO_TOKEN: Type.String(),\n PORT: Type.Number({ default: 3000 }),\n LOG_LEVEL: Type.Optional(Type.String({ default: 'info' })),\n STORAGE_PROVIDER: Type.Optional(\n Type.Enum(STORAGE_PROVIDERS, { default: STORAGE_PROVIDERS.LOCAL }),\n ),\n STORAGE_PATH: Type.Optional(Type.String()),\n S3_ACCESS_KEY: Type.Optional(Type.String()),\n S3_SECRET_KEY: Type.Optional(Type.String()),\n S3_REGION: Type.Optional(Type.String()),\n S3_ENDPOINT: Type.Optional(Type.String()),\n },\n { additionalProperties: false },\n)\n\nexport const env = envSchema<Static<typeof schema>>({\n ajv: new Ajv({\n removeAdditional: true,\n useDefaults: true,\n coerceTypes: true,\n keywords: ['kind', 'RegExp', 'modifier'],\n }),\n dotenv: process.env.NODE_ENV === NODE_ENVS.DEVELOPMENT ? true : false,\n schema,\n})\n"]}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
require("make-promises-safe");
|
|
5
|
+
const close_with_grace_1 = (0, tslib_1.__importDefault)(require("close-with-grace"));
|
|
6
|
+
const app_1 = require("./app");
|
|
7
|
+
const env_1 = require("./env");
|
|
8
|
+
const app = (0, app_1.createApp)({
|
|
9
|
+
trustProxy: true,
|
|
10
|
+
});
|
|
11
|
+
(0, close_with_grace_1.default)({ delay: 10000 }, async function ({ err, signal }) {
|
|
12
|
+
if (err) {
|
|
13
|
+
app.log.error(err);
|
|
14
|
+
}
|
|
15
|
+
app.log.info(`[${signal}] Gracefully closing the server instance.`);
|
|
16
|
+
await app.close();
|
|
17
|
+
});
|
|
18
|
+
app.listen(env_1.env.PORT, '0.0.0.0', err => {
|
|
19
|
+
if (err) {
|
|
20
|
+
app.log.error(err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,8BAA2B;AAC3B,qFAA6C;AAE7C,+BAAiC;AACjC,+BAA2B;AAE3B,MAAM,GAAG,GAAG,IAAA,eAAS,EAAC;IACpB,UAAU,EAAE,IAAI;CACjB,CAAC,CAAA;AAEF,IAAA,0BAAc,EACZ,EAAE,KAAK,EAAE,KAAK,EAAE,EAChB,KAAK,WAAW,EAAE,GAAG,EAAE,MAAM,EAAoC;IAC/D,IAAI,GAAG,EAAE;QACP,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;KACnB;IAED,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,MAAM,2CAA2C,CAAC,CAAA;IAEnE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAA;AACnB,CAAC,CACF,CAAA;AAED,GAAG,CAAC,MAAM,CAAC,SAAG,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,CAAC,EAAE;IACpC,IAAI,GAAG,EAAE;QACP,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;KAChB;AACH,CAAC,CAAC,CAAA","sourcesContent":["import 'make-promises-safe'\nimport closeWithGrace from 'close-with-grace'\n\nimport { createApp } from './app'\nimport { env } from './env'\n\nconst app = createApp({\n trustProxy: true,\n})\n\ncloseWithGrace(\n { delay: 10000 },\n async function ({ err, signal }: { err?: Error; signal?: string }) {\n if (err) {\n app.log.error(err)\n }\n\n app.log.info(`[${signal}] Gracefully closing the server instance.`)\n\n await app.close()\n },\n)\n\napp.listen(env.PORT, '0.0.0.0', err => {\n if (err) {\n app.log.error(err)\n process.exit(1)\n }\n})\n"]}
|
package/build/logger.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const pino_1 = (0, tslib_1.__importDefault)(require("pino"));
|
|
6
|
+
const env_1 = require("./env");
|
|
7
|
+
const PinoLevelToSeverityLookup = {
|
|
8
|
+
trace: 'DEBUG',
|
|
9
|
+
debug: 'DEBUG',
|
|
10
|
+
info: 'INFO',
|
|
11
|
+
warn: 'WARNING',
|
|
12
|
+
error: 'ERROR',
|
|
13
|
+
fatal: 'CRITICAL',
|
|
14
|
+
};
|
|
15
|
+
exports.logger = (0, pino_1.default)({
|
|
16
|
+
level: env_1.env.LOG_LEVEL,
|
|
17
|
+
messageKey: 'message',
|
|
18
|
+
redact: ['req.headers.authorization'],
|
|
19
|
+
formatters: {
|
|
20
|
+
level(label, number) {
|
|
21
|
+
return {
|
|
22
|
+
severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup['info'],
|
|
23
|
+
level: number,
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
exports.default = exports.logger;
|
|
29
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":";;;;AAAA,6DAAuB;AACvB,+BAA2B;AAC3B,MAAM,yBAAyB,GAAG;IAChC,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,UAAU;CACT,CAAA;AAEG,QAAA,MAAM,GAAG,IAAA,cAAI,EAAC;IACzB,KAAK,EAAE,SAAG,CAAC,SAAS;IACpB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,CAAC,2BAA2B,CAAC;IACrC,UAAU,EAAE;QACV,KAAK,CAAC,KAAK,EAAE,MAAM;YACjB,OAAO;gBACL,QAAQ,EAAE,yBAAyB,CAAC,KAAK,CAAC,IAAI,yBAAyB,CAAC,MAAM,CAAC;gBAC/E,KAAK,EAAE,MAAM;aACd,CAAA;QACH,CAAC;KACF;CACF,CAAC,CAAA;AAEF,kBAAe,cAAM,CAAA","sourcesContent":["import Pino from 'pino'\nimport { env } from './env'\nconst PinoLevelToSeverityLookup = {\n trace: 'DEBUG',\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARNING',\n error: 'ERROR',\n fatal: 'CRITICAL',\n} as const\n\nexport const logger = Pino({\n level: env.LOG_LEVEL,\n messageKey: 'message',\n redact: ['req.headers.authorization'],\n formatters: {\n level(label, number) {\n return {\n severity: PinoLevelToSeverityLookup[label] || PinoLevelToSeverityLookup['info'],\n level: number,\n }\n },\n },\n})\n\nexport default logger\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const fastify_plugin_1 = (0, tslib_1.__importDefault)(require("fastify-plugin"));
|
|
5
|
+
const env_1 = require("../env");
|
|
6
|
+
exports.default = (0, fastify_plugin_1.default)(async function (fastify) {
|
|
7
|
+
fastify.decorate('config', env_1.env);
|
|
8
|
+
}, { name: 'config' });
|
|
9
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/plugins/config.ts"],"names":[],"mappings":";;;AAAA,iFAA+B;AAC/B,gCAA4B;AAE5B,kBAAe,IAAA,wBAAE,EACf,KAAK,WAAW,OAAO;IACrB,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,SAAG,CAAC,CAAA;AACjC,CAAC,EACD,EAAE,IAAI,EAAE,QAAQ,EAAE,CACnB,CAAA","sourcesContent":["import fp from 'fastify-plugin'\nimport { env } from '../env'\n\nexport default fp(\n async function (fastify) {\n fastify.decorate('config', env)\n },\n { name: 'config' },\n)\n\ndeclare module 'fastify' {\n interface FastifyInstance {\n config: typeof env\n }\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const boom_1 = require("@hapi/boom");
|
|
4
|
+
const routes_1 = require("./routes");
|
|
5
|
+
const storage_1 = require("./storage");
|
|
6
|
+
const env_1 = require("../../env");
|
|
7
|
+
async function turboRemoteCache(instance, options) {
|
|
8
|
+
const { allowedTokens, bodyLimit = 104857600, apiVersion = 'v8', provider = env_1.STORAGE_PROVIDERS.LOCAL, } = options;
|
|
9
|
+
if (!(Array.isArray(allowedTokens) && allowedTokens.length)) {
|
|
10
|
+
throw new Error(`'allowedTokens' options must be a string[], ${typeof allowedTokens} provided instead`);
|
|
11
|
+
}
|
|
12
|
+
instance.addContentTypeParser('application/octet-stream', { parseAs: 'buffer', bodyLimit }, async function parser(request, payload) {
|
|
13
|
+
return payload;
|
|
14
|
+
});
|
|
15
|
+
const tokens = new Set(allowedTokens);
|
|
16
|
+
instance.addHook('onRequest', async function (request) {
|
|
17
|
+
let authHeader = request.headers['authorization'];
|
|
18
|
+
authHeader = Array.isArray(authHeader) ? authHeader.join() : authHeader;
|
|
19
|
+
if (!authHeader) {
|
|
20
|
+
throw (0, boom_1.badRequest)(`Missing Authorization header`);
|
|
21
|
+
}
|
|
22
|
+
const [, token] = authHeader.split('Bearer ');
|
|
23
|
+
if (!tokens.has(token)) {
|
|
24
|
+
throw (0, boom_1.unauthorized)(`Invalid authorization token`);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
instance.decorate('location', (0, storage_1.createLocation)(provider, {
|
|
28
|
+
accessKey: instance.config.S3_ACCESS_KEY,
|
|
29
|
+
secretKey: instance.config.S3_SECRET_KEY,
|
|
30
|
+
path: instance.config.STORAGE_PATH,
|
|
31
|
+
region: instance.config.S3_REGION,
|
|
32
|
+
endpoint: instance.config.S3_ENDPOINT,
|
|
33
|
+
}));
|
|
34
|
+
await instance.register(async function (i) {
|
|
35
|
+
i.route(routes_1.getArtifact);
|
|
36
|
+
i.route(routes_1.putArtifact);
|
|
37
|
+
}, { prefix: `/${apiVersion}` });
|
|
38
|
+
}
|
|
39
|
+
exports.default = turboRemoteCache;
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/plugins/remote-cache/index.ts"],"names":[],"mappings":";;AACA,qCAAqD;AACrD,qCAAmD;AACnD,uCAA0C;AAC1C,mCAA6C;AAE7C,KAAK,UAAU,gBAAgB,CAC7B,QAAyB,EACzB,OAKC;IAED,MAAM,EACJ,aAAa,EACb,SAAS,GAAG,SAAS,EACrB,UAAU,GAAG,IAAI,EACjB,QAAQ,GAAG,uBAAiB,CAAC,KAAK,GACnC,GAAG,OAAO,CAAA;IACX,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE;QAC3D,MAAM,IAAI,KAAK,CACb,+CAA+C,OAAO,aAAa,mBAAmB,CACvF,CAAA;KACF;IAED,QAAQ,CAAC,oBAAoB,CAC3B,0BAA0B,EAC1B,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,EAChC,KAAK,UAAU,MAAM,CAAC,OAAO,EAAE,OAAO;QACpC,OAAO,OAAO,CAAA;IAChB,CAAC,CACF,CAAA;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,CAAS,aAAa,CAAC,CAAA;IAC7C,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,WAAW,OAAO;QACnD,IAAI,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAA;QACjD,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,UAAU,CAAA;QAEvE,IAAI,CAAC,UAAU,EAAE;YACf,MAAM,IAAA,iBAAU,EAAC,8BAA8B,CAAC,CAAA;SACjD;QACD,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;QAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;YACtB,MAAM,IAAA,mBAAY,EAAC,6BAA6B,CAAC,CAAA;SAClD;IACH,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,QAAQ,CACf,UAAU,EACV,IAAA,wBAAc,EAAC,QAAQ,EAAE;QACvB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa;QACxC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,aAAa;QACxC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY;QAClC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS;QACjC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,WAAW;KACtC,CAAC,CACH,CAAA;IAED,MAAM,QAAQ,CAAC,QAAQ,CACrB,KAAK,WAAW,CAAC;QACf,CAAC,CAAC,KAAK,CAAC,oBAAW,CAAC,CAAA;QACpB,CAAC,CAAC,KAAK,CAAC,oBAAW,CAAC,CAAA;IACtB,CAAC,EACD,EAAE,MAAM,EAAE,IAAI,UAAU,EAAE,EAAE,CAC7B,CAAA;AACH,CAAC;AAED,kBAAe,gBAAgB,CAAA","sourcesContent":["import { FastifyInstance } from 'fastify'\nimport { badRequest, unauthorized } from '@hapi/boom'\nimport { getArtifact, putArtifact } from './routes'\nimport { createLocation } from './storage'\nimport { STORAGE_PROVIDERS } from '../../env'\n\nasync function turboRemoteCache(\n instance: FastifyInstance,\n options: {\n allowedTokens: string[]\n bodyLimit?: number\n apiVersion?: `v${number}`\n provider?: STORAGE_PROVIDERS\n },\n) {\n const {\n allowedTokens,\n bodyLimit = 104857600,\n apiVersion = 'v8',\n provider = STORAGE_PROVIDERS.LOCAL,\n } = options\n if (!(Array.isArray(allowedTokens) && allowedTokens.length)) {\n throw new Error(\n `'allowedTokens' options must be a string[], ${typeof allowedTokens} provided instead`,\n )\n }\n\n instance.addContentTypeParser<Buffer>(\n 'application/octet-stream',\n { parseAs: 'buffer', bodyLimit },\n async function parser(request, payload) {\n return payload\n },\n )\n\n const tokens = new Set<string>(allowedTokens)\n instance.addHook('onRequest', async function (request) {\n let authHeader = request.headers['authorization']\n authHeader = Array.isArray(authHeader) ? authHeader.join() : authHeader\n\n if (!authHeader) {\n throw badRequest(`Missing Authorization header`)\n }\n const [, token] = authHeader.split('Bearer ')\n if (!tokens.has(token)) {\n throw unauthorized(`Invalid authorization token`)\n }\n })\n\n instance.decorate(\n 'location',\n createLocation(provider, {\n accessKey: instance.config.S3_ACCESS_KEY,\n secretKey: instance.config.S3_SECRET_KEY,\n path: instance.config.STORAGE_PATH,\n region: instance.config.S3_REGION,\n endpoint: instance.config.S3_ENDPOINT,\n }),\n )\n\n await instance.register(\n async function (i) {\n i.route(getArtifact)\n i.route(putArtifact)\n },\n { prefix: `/${apiVersion}` },\n )\n}\n\nexport default turboRemoteCache\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getArtifact = void 0;
|
|
4
|
+
const boom_1 = require("@hapi/boom");
|
|
5
|
+
const schema_1 = require("./schema");
|
|
6
|
+
exports.getArtifact = {
|
|
7
|
+
method: 'GET',
|
|
8
|
+
url: '/artifacts/:id',
|
|
9
|
+
schema: schema_1.artifactsRouteSchema,
|
|
10
|
+
async handler(req, reply) {
|
|
11
|
+
const artifactId = req.params.id;
|
|
12
|
+
const teamId = req.query.teamId;
|
|
13
|
+
try {
|
|
14
|
+
const artifact = await this.location.getCachedArtifact(artifactId, teamId);
|
|
15
|
+
reply.send(artifact);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
throw (0, boom_1.notFound)(`Artifact not found`, err);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=get-artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-artifact.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/routes/get-artifact.ts"],"names":[],"mappings":";;;AAEA,qCAAqC;AACrC,qCAA8E;AAEjE,QAAA,WAAW,GAQpB;IACF,MAAM,EAAE,KAAK;IACb,GAAG,EAAE,gBAAgB;IACrB,MAAM,EAAE,6BAAoB;IAC5B,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK;QACtB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAA;QAChC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA;QAC/B,IAAI;YACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;YAC1E,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;SACrB;QAAC,OAAO,GAAG,EAAE;YACZ,MAAM,IAAA,eAAQ,EAAC,oBAAoB,EAAE,GAAG,CAAC,CAAA;SAC1C;IACH,CAAC;CACF,CAAA","sourcesContent":["import type { Server } from 'http'\nimport type { RouteOptions, RawRequestDefaultExpression, RawReplyDefaultExpression } from 'fastify'\nimport { notFound } from '@hapi/boom'\nimport { type Querystring, type Params, artifactsRouteSchema } from './schema'\n\nexport const getArtifact: RouteOptions<\n Server,\n RawRequestDefaultExpression,\n RawReplyDefaultExpression,\n {\n Querystring: Querystring\n Params: Params\n }\n> = {\n method: 'GET',\n url: '/artifacts/:id',\n schema: artifactsRouteSchema,\n async handler(req, reply) {\n const artifactId = req.params.id\n const teamId = req.query.teamId\n try {\n const artifact = await this.location.getCachedArtifact(artifactId, teamId)\n reply.send(artifact)\n } catch (err) {\n throw notFound(`Artifact not found`, err)\n }\n },\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.putArtifact = exports.getArtifact = void 0;
|
|
4
|
+
var get_artifact_1 = require("./get-artifact");
|
|
5
|
+
Object.defineProperty(exports, "getArtifact", { enumerable: true, get: function () { return get_artifact_1.getArtifact; } });
|
|
6
|
+
var put_artifact_1 = require("./put-artifact");
|
|
7
|
+
Object.defineProperty(exports, "putArtifact", { enumerable: true, get: function () { return put_artifact_1.putArtifact; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/routes/index.ts"],"names":[],"mappings":";;;AAAA,+CAA4C;AAAnC,2GAAA,WAAW,OAAA;AACpB,+CAA4C;AAAnC,2GAAA,WAAW,OAAA","sourcesContent":["export { getArtifact } from './get-artifact'\nexport { putArtifact } from './put-artifact'\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.putArtifact = void 0;
|
|
4
|
+
const boom_1 = require("@hapi/boom");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
const schema_1 = require("./schema");
|
|
7
|
+
exports.putArtifact = {
|
|
8
|
+
url: '/artifacts/:id',
|
|
9
|
+
method: 'PUT',
|
|
10
|
+
schema: schema_1.artifactsRouteSchema,
|
|
11
|
+
async handler(req, reply) {
|
|
12
|
+
const artifactId = req.params.id;
|
|
13
|
+
const teamId = req.query.teamId;
|
|
14
|
+
try {
|
|
15
|
+
await this.location.createCachedArtifact(artifactId, teamId, stream_1.Readable.from(req.body));
|
|
16
|
+
reply.send({ urls: [`${teamId}/${artifactId}`] });
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
throw (0, boom_1.preconditionFailed)(`Error during the artifact creation`, err);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=put-artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"put-artifact.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/routes/put-artifact.ts"],"names":[],"mappings":";;;AAEA,qCAA+C;AAC/C,mCAAiC;AACjC,qCAA8E;AAEjE,QAAA,WAAW,GASpB;IACF,GAAG,EAAE,gBAAgB;IACrB,MAAM,EAAE,KAAK;IACb,MAAM,EAAE,6BAAoB;IAC5B,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK;QACtB,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,CAAC,EAAE,CAAA;QAChC,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM,CAAA;QAC/B,IAAI;YACF,MAAM,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,iBAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YAErF,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC,EAAE,CAAC,CAAA;SAClD;QAAC,OAAO,GAAG,EAAE;YAEZ,MAAM,IAAA,yBAAkB,EAAC,oCAAoC,EAAE,GAAG,CAAC,CAAA;SACpE;IACH,CAAC;CACF,CAAA","sourcesContent":["import type { Server } from 'http'\nimport type { RouteOptions, RawRequestDefaultExpression, RawReplyDefaultExpression } from 'fastify'\nimport { preconditionFailed } from '@hapi/boom'\nimport { Readable } from 'stream'\nimport { type Querystring, type Params, artifactsRouteSchema } from './schema'\n\nexport const putArtifact: RouteOptions<\n Server,\n RawRequestDefaultExpression,\n RawReplyDefaultExpression,\n {\n Querystring: Querystring\n Params: Params\n Body: Buffer\n }\n> = {\n url: '/artifacts/:id',\n method: 'PUT',\n schema: artifactsRouteSchema,\n async handler(req, reply) {\n const artifactId = req.params.id\n const teamId = req.query.teamId\n try {\n await this.location.createCachedArtifact(artifactId, teamId, Readable.from(req.body))\n\n reply.send({ urls: [`${teamId}/${artifactId}`] })\n } catch (err) {\n // we need this error throw since turbo retries if the error is in 5xx range\n throw preconditionFailed(`Error during the artifact creation`, err)\n }\n },\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.artifactsRouteSchema = void 0;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
5
|
+
const querystring = typebox_1.Type.Object({
|
|
6
|
+
teamId: typebox_1.Type.String(),
|
|
7
|
+
}, { additionalParameters: false });
|
|
8
|
+
const params = typebox_1.Type.Object({
|
|
9
|
+
id: typebox_1.Type.String(),
|
|
10
|
+
}, { additionalParameters: false });
|
|
11
|
+
exports.artifactsRouteSchema = {
|
|
12
|
+
querystring,
|
|
13
|
+
params,
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/routes/schema.ts"],"names":[],"mappings":";;;AAAA,+CAAgD;AAEhD,MAAM,WAAW,GAAG,cAAI,CAAC,MAAM,CAC7B;IACE,MAAM,EAAE,cAAI,CAAC,MAAM,EAAE;CACtB,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAA;AAGD,MAAM,MAAM,GAAG,cAAI,CAAC,MAAM,CACxB;IACE,EAAE,EAAE,cAAI,CAAC,MAAM,EAAE;CAClB,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAChC,CAAA;AAGY,QAAA,oBAAoB,GAAG;IAClC,WAAW;IACX,MAAM;CACP,CAAA","sourcesContent":["import { Type, Static } from '@sinclair/typebox'\n\nconst querystring = Type.Object(\n {\n teamId: Type.String(),\n },\n { additionalParameters: false },\n)\nexport type Querystring = Static<typeof querystring>\n\nconst params = Type.Object(\n {\n id: Type.String(),\n },\n { additionalParameters: false },\n)\nexport type Params = Static<typeof params>\n\nexport const artifactsRouteSchema = {\n querystring,\n params,\n}\n"]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLocation = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const stream_1 = require("stream");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const env_1 = require("../../../env");
|
|
8
|
+
const s3_1 = require("./s3");
|
|
9
|
+
const local_1 = require("./local");
|
|
10
|
+
const pipeline = (0, util_1.promisify)(stream_1.pipeline);
|
|
11
|
+
const TURBO_CACHE_FOLDER_NAME = 'turborepocache';
|
|
12
|
+
function createLocation(provider, providerOptions) {
|
|
13
|
+
const { path = TURBO_CACHE_FOLDER_NAME, accessKey, secretKey, region, endpoint } = providerOptions;
|
|
14
|
+
const location = provider === env_1.STORAGE_PROVIDERS.LOCAL
|
|
15
|
+
? (0, local_1.createLocal)({ path })
|
|
16
|
+
: (0, s3_1.createS3)({ accessKey, secretKey, bucket: path, region, endpoint });
|
|
17
|
+
async function getCachedArtifact(artifactId, teamId) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const artifactPath = (0, path_1.join)(teamId, artifactId);
|
|
20
|
+
location.exists(artifactPath, (err, exists) => {
|
|
21
|
+
if (err) {
|
|
22
|
+
return reject(err);
|
|
23
|
+
}
|
|
24
|
+
if (!exists) {
|
|
25
|
+
return reject(new Error(`Artifact ${artifactPath} doesn't exist.`));
|
|
26
|
+
}
|
|
27
|
+
resolve(location.createReadStream(artifactPath));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async function createCachedArtifact(artifactId, teamId, artifact) {
|
|
32
|
+
return pipeline(artifact, location.createWriteStream((0, path_1.join)(teamId, artifactId)));
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
getCachedArtifact,
|
|
36
|
+
createCachedArtifact,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
exports.createLocation = createLocation;
|
|
40
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/storage/index.ts"],"names":[],"mappings":";;;AAAA,+BAA2B;AAC3B,mCAA+D;AAC/D,+BAAgC;AAChC,sCAAgD;AAChD,6BAA+C;AAC/C,mCAAmD;AAEnD,MAAM,QAAQ,GAAG,IAAA,gBAAS,EAAC,iBAAgB,CAAC,CAAA;AAC5C,MAAM,uBAAuB,GAAG,gBAAyB,CAAA;AAIzD,SAAgB,cAAc,CAAC,QAA2B,EAAE,eAAgC;IAC1F,MAAM,EAAE,IAAI,GAAG,uBAAuB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,eAAe,CAAA;IAClG,MAAM,QAAQ,GACZ,QAAQ,KAAK,uBAAiB,CAAC,KAAK;QAClC,CAAC,CAAC,IAAA,mBAAW,EAAC,EAAE,IAAI,EAAE,CAAC;QACvB,CAAC,CAAC,IAAA,aAAQ,EAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAA;IAExE,KAAK,UAAU,iBAAiB,CAAC,UAAkB,EAAE,MAAc;QACjE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,YAAY,GAAG,IAAA,WAAI,EAAC,MAAM,EAAE,UAAU,CAAC,CAAA;YAC7C,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;gBAC5C,IAAI,GAAG,EAAE;oBACP,OAAO,MAAM,CAAC,GAAG,CAAC,CAAA;iBACnB;gBACD,IAAI,CAAC,MAAM,EAAE;oBACX,OAAO,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,YAAY,iBAAiB,CAAC,CAAC,CAAA;iBACpE;gBACD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAA;YAClD,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,UAAU,oBAAoB,CAAC,UAAkB,EAAE,MAAc,EAAE,QAAkB;QACxF,OAAO,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,iBAAiB,CAAC,IAAA,WAAI,EAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,CAAA;IACjF,CAAC;IACD,OAAO;QACL,iBAAiB;QACjB,oBAAoB;KACrB,CAAA;AACH,CAAC;AA7BD,wCA6BC","sourcesContent":["import { join } from 'path'\nimport { Readable, pipeline as pipelineCallback } from 'stream'\nimport { promisify } from 'util'\nimport { STORAGE_PROVIDERS } from '../../../env'\nimport { createS3, type S3Options } from './s3'\nimport { createLocal, LocalOptions } from './local'\n\nconst pipeline = promisify(pipelineCallback)\nconst TURBO_CACHE_FOLDER_NAME = 'turborepocache' as const\n\ntype ProviderOptions = Partial<LocalOptions> & Omit<S3Options, 'bucket'>\n\nexport function createLocation(provider: STORAGE_PROVIDERS, providerOptions: ProviderOptions) {\n const { path = TURBO_CACHE_FOLDER_NAME, accessKey, secretKey, region, endpoint } = providerOptions\n const location =\n provider === STORAGE_PROVIDERS.LOCAL\n ? createLocal({ path })\n : createS3({ accessKey, secretKey, bucket: path, region, endpoint })\n\n async function getCachedArtifact(artifactId: string, teamId: string) {\n return new Promise((resolve, reject) => {\n const artifactPath = join(teamId, artifactId)\n location.exists(artifactPath, (err, exists) => {\n if (err) {\n return reject(err)\n }\n if (!exists) {\n return reject(new Error(`Artifact ${artifactPath} doesn't exist.`))\n }\n resolve(location.createReadStream(artifactPath))\n })\n })\n }\n\n async function createCachedArtifact(artifactId: string, teamId: string, artifact: Readable) {\n return pipeline(artifact, location.createWriteStream(join(teamId, artifactId)))\n }\n return {\n getCachedArtifact,\n createCachedArtifact,\n }\n}\n\ndeclare module 'fastify' {\n interface FastifyInstance {\n location: {\n getCachedArtifact: ReturnType<typeof createLocation>['getCachedArtifact']\n createCachedArtifact: ReturnType<typeof createLocation>['createCachedArtifact']\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createLocal = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const os_1 = require("os");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const fs_blob_store_1 = (0, tslib_1.__importDefault)(require("fs-blob-store"));
|
|
8
|
+
function createLocal({ path }) {
|
|
9
|
+
return (0, fs_blob_store_1.default)((0, path_1.join)((0, os_1.tmpdir)(), path));
|
|
10
|
+
}
|
|
11
|
+
exports.createLocal = createLocal;
|
|
12
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/storage/local.ts"],"names":[],"mappings":";;;;AAAA,2BAA2B;AAC3B,+BAA2B;AAC3B,+EAA8B;AAM9B,SAAgB,WAAW,CAAC,EAAE,IAAI,EAAgB;IAChD,OAAO,IAAA,uBAAE,EAAC,IAAA,WAAI,EAAC,IAAA,WAAM,GAAE,EAAE,IAAI,CAAC,CAAC,CAAA;AACjC,CAAC;AAFD,kCAEC","sourcesContent":["import { tmpdir } from 'os'\nimport { join } from 'path'\nimport fs from 'fs-blob-store'\n\nexport type LocalOptions = {\n path: string\n}\n\nexport function createLocal({ path }: LocalOptions) {\n return fs(join(tmpdir(), path))\n}\n"]}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createS3 = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const s3_blob_store_1 = (0, tslib_1.__importDefault)(require("s3-blob-store"));
|
|
6
|
+
const aws_sdk_1 = (0, tslib_1.__importDefault)(require("aws-sdk"));
|
|
7
|
+
function createS3({ accessKey, secretKey, bucket, region, endpoint }) {
|
|
8
|
+
if (!accessKey || !secretKey || !(region || endpoint)) {
|
|
9
|
+
throw new Error(`To use S3 storage "accessKey (S3_ACCESS_KEY)", "secretKey (S3_SECRET_KEY)", and one of "region (S3_REGION)" and "endpoint (S3_ENDPOINT)" parameters are mandatory.`);
|
|
10
|
+
}
|
|
11
|
+
const client = new aws_sdk_1.default.S3({
|
|
12
|
+
credentials: {
|
|
13
|
+
accessKeyId: accessKey,
|
|
14
|
+
secretAccessKey: secretKey,
|
|
15
|
+
},
|
|
16
|
+
...(region ? { region } : {}),
|
|
17
|
+
...(endpoint ? { endpoint: new aws_sdk_1.default.Endpoint(endpoint) } : {}),
|
|
18
|
+
...(process.env.NODE_ENV === 'test' ? { sslEnabled: false, s3ForcePathStyle: true } : {}),
|
|
19
|
+
});
|
|
20
|
+
const location = (0, s3_blob_store_1.default)({
|
|
21
|
+
client,
|
|
22
|
+
bucket,
|
|
23
|
+
});
|
|
24
|
+
return location;
|
|
25
|
+
}
|
|
26
|
+
exports.createS3 = createS3;
|
|
27
|
+
//# sourceMappingURL=s3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"s3.js","sourceRoot":"","sources":["../../../../src/plugins/remote-cache/storage/s3.ts"],"names":[],"mappings":";;;;AAAA,+EAA8B;AAC9B,mEAAyB;AASzB,SAAgB,QAAQ,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAa;IACpF,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,MAAM,IAAI,QAAQ,CAAC,EAAE;QACrD,MAAM,IAAI,KAAK,CACb,oKAAoK,CACrK,CAAA;KACF;IAED,MAAM,MAAM,GAAG,IAAI,iBAAG,CAAC,EAAE,CAAC;QACxB,WAAW,EAAE;YACX,WAAW,EAAE,SAAS;YACtB,eAAe,EAAE,SAAS;SAC3B;QACD,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,iBAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC1F,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,IAAA,uBAAE,EAAC;QAClB,MAAM;QACN,MAAM;KACP,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAA;AACjB,CAAC;AAvBD,4BAuBC","sourcesContent":["import s3 from 's3-blob-store'\nimport aws from 'aws-sdk'\n\nexport interface S3Options {\n accessKey?: string\n secretKey?: string\n region?: string\n endpoint?: string\n bucket: string\n}\nexport function createS3({ accessKey, secretKey, bucket, region, endpoint }: S3Options) {\n if (!accessKey || !secretKey || !(region || endpoint)) {\n throw new Error(\n `To use S3 storage \"accessKey (S3_ACCESS_KEY)\", \"secretKey (S3_SECRET_KEY)\", and one of \"region (S3_REGION)\" and \"endpoint (S3_ENDPOINT)\" parameters are mandatory.`,\n )\n }\n\n const client = new aws.S3({\n credentials: {\n accessKeyId: accessKey,\n secretAccessKey: secretKey,\n },\n ...(region ? { region } : {}),\n ...(endpoint ? { endpoint: new aws.Endpoint(endpoint) } : {}),\n ...(process.env.NODE_ENV === 'test' ? { sslEnabled: false, s3ForcePathStyle: true } : {}),\n })\n\n const location = s3({\n client,\n bucket,\n })\n\n return location\n}\n"]}
|
package/build/vercel.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const app_1 = require("./app");
|
|
4
|
+
const app = (0, app_1.createApp)();
|
|
5
|
+
async function default_1(req, res) {
|
|
6
|
+
await app.ready();
|
|
7
|
+
app.server.emit('request', req, res);
|
|
8
|
+
}
|
|
9
|
+
exports.default = default_1;
|
|
10
|
+
//# sourceMappingURL=vercel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vercel.js","sourceRoot":"","sources":["../src/vercel.ts"],"names":[],"mappings":";;AACA,+BAAiC;AACjC,MAAM,GAAG,GAAG,IAAA,eAAS,GAAE,CAAA;AAER,KAAK,oBAAW,GAAkB,EAAE,GAAmB;IACpE,MAAM,GAAG,CAAC,KAAK,EAAE,CAAA;IACjB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AACtC,CAAC;AAHD,4BAGC","sourcesContent":["import type { VercelRequest, VercelResponse } from '@vercel/node'\nimport { createApp } from './app'\nconst app = createApp()\n\nexport default async function (req: VercelRequest, res: VercelResponse) {\n await app.ready()\n app.server.emit('request', req, res)\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "turborepo-remote-cache",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Turborepo remote cache server",
|
|
5
|
+
"main": "build",
|
|
6
|
+
"author": "Maksim Sinik <maksim@sinik.it>",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"bin": {
|
|
9
|
+
"turborepo-remote-cache": "./build/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"prebuild": "npm run lint && rimraf ./build",
|
|
13
|
+
"build": "tsc -p ./tsconfig.json",
|
|
14
|
+
"start": "node --enable-source-maps build/index.js",
|
|
15
|
+
"update": "npx npm-check -u",
|
|
16
|
+
"lint": "eslint --ext .ts --no-error-on-unmatched-pattern \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
17
|
+
"dev": "tsup --watch --onSuccess \"run-p dev:start check:types\"",
|
|
18
|
+
"dev:start": "node --inspect -r @cspotcode/source-map-support/register -r dotenv/config build/index.js",
|
|
19
|
+
"check:types": "tsc -p ./tsconfig.json --noEmit",
|
|
20
|
+
"test": "cross-env TS_NODE_PROJECT=./test/tsconfig.json tap --ts",
|
|
21
|
+
"test:watch": "npm run test -- --watch",
|
|
22
|
+
"test:report": "npm run test -- --output-file=out.tap && tap-mocha-reporter xunit < out.tap > junit-testresults.xml"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/fox1t/turborepo-remote-cache.git"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@hapi/boom": "^9.1.4",
|
|
30
|
+
"@sinclair/typebox": "^0.23.1",
|
|
31
|
+
"@vercel/node": "^1.12.1",
|
|
32
|
+
"ajv": "^8.8.2",
|
|
33
|
+
"aws-sdk": "^2.1053.0",
|
|
34
|
+
"boom": "^7.3.0",
|
|
35
|
+
"close-with-grace": "^1.1.0",
|
|
36
|
+
"env-schema": "^3.5.0",
|
|
37
|
+
"fastify": "^3.25.0",
|
|
38
|
+
"fastify-autoload": "^3.9.0",
|
|
39
|
+
"fastify-plugin": "^3.0.0",
|
|
40
|
+
"fs-blob-store": "^6.0.0",
|
|
41
|
+
"hyperid": "^2.3.1",
|
|
42
|
+
"make-promises-safe": "^5.1.0",
|
|
43
|
+
"pino": "^6.13.3",
|
|
44
|
+
"pino-pretty": "^7.3.0",
|
|
45
|
+
"s3-blob-store": "^4.1.1",
|
|
46
|
+
"tslib": "^2.3.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@cspotcode/source-map-support": "^0.7.0",
|
|
50
|
+
"@types/node": "^17.0.0",
|
|
51
|
+
"@types/pino": "^6.3.12",
|
|
52
|
+
"@types/tap": "^15.0.5",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
|
54
|
+
"@typescript-eslint/parser": "^5.7.0",
|
|
55
|
+
"cross-env": "^7.0.3",
|
|
56
|
+
"dotenv": "^10.0.0",
|
|
57
|
+
"esbuild": "^0.14.5",
|
|
58
|
+
"eslint": "^8.4.1",
|
|
59
|
+
"eslint-config-prettier": "^8.3.0",
|
|
60
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
61
|
+
"husky": "^7.0.4",
|
|
62
|
+
"npm-run-all": "^4.1.5",
|
|
63
|
+
"prettier": "^2.5.1",
|
|
64
|
+
"rimraf": "^3.0.2",
|
|
65
|
+
"s3rver": "^3.7.1",
|
|
66
|
+
"tap": "^15.1.5",
|
|
67
|
+
"ts-node": "^10.4.0",
|
|
68
|
+
"tsup": "^5.11.6",
|
|
69
|
+
"typescript": "^4.5.4"
|
|
70
|
+
},
|
|
71
|
+
"husky": {
|
|
72
|
+
"hooks": {
|
|
73
|
+
"pre-commit": "npm run test && npm run build"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/nucleode/typescript-microservice-starter/issues"
|
|
78
|
+
},
|
|
79
|
+
"homepage": "https://github.com/nucleode/typescript-microservice-starter#readme",
|
|
80
|
+
"directories": {
|
|
81
|
+
"test": "test"
|
|
82
|
+
},
|
|
83
|
+
"keywords": [
|
|
84
|
+
"turborepo",
|
|
85
|
+
"monorepo",
|
|
86
|
+
"remote",
|
|
87
|
+
"cache"
|
|
88
|
+
],
|
|
89
|
+
"files": [
|
|
90
|
+
"build",
|
|
91
|
+
"vercel.json"
|
|
92
|
+
]
|
|
93
|
+
}
|