@wabicloud/turborepo-remote-cache-serverless 0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wabicloud
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,97 @@
1
+ # @wabicloud/turborepo-remote-cache-serverless
2
+
3
+ An AWS CDK construct that deploys a fully serverless Turborepo remote cache using S3, Lambda, and Secrets Manager. No servers to manage, scales to zero, costs almost nothing for small teams.
4
+
5
+ ## Quick Start
6
+
7
+ ### Install
8
+
9
+ ```bash
10
+ npm install @wabicloud/turborepo-remote-cache-serverless
11
+ ```
12
+
13
+ ### Add to your CDK stack
14
+
15
+ ```typescript
16
+ import { TurborepoRemoteCache } from "@wabicloud/turborepo-remote-cache-serverless";
17
+
18
+ const cache = new TurborepoRemoteCache(this, "TurboCache");
19
+
20
+ new cdk.CfnOutput(this, "TurboCacheUrl", {
21
+ value: cache.functionUrl.url,
22
+ });
23
+ ```
24
+
25
+ ### Deploy
26
+
27
+ ```bash
28
+ cdk deploy
29
+ ```
30
+
31
+ ### Generate a token
32
+
33
+ ```bash
34
+ npx wabicloud-turbo-cache generate-token \
35
+ --team team_myproject \
36
+ --secret-name turborepo/cache-token \
37
+ --region us-east-1
38
+ ```
39
+
40
+ ### Configure Turborepo
41
+
42
+ ```bash
43
+ export TURBO_API="https://<your-function-url>"
44
+ export TURBO_TOKEN="<generated-token>"
45
+ export TURBO_TEAM="team_myproject"
46
+
47
+ pnpm turbo build --preflight
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ | Prop | Type | Default | Description |
53
+ |------|------|---------|-------------|
54
+ | `expiration` | `Duration` | 30 days | How long cached artifacts are kept |
55
+ | `secretName` | `string` | `turborepo/cache-token` | Secrets Manager secret name |
56
+
57
+ ```typescript
58
+ new TurborepoRemoteCache(this, "TurboCache", {
59
+ expiration: cdk.Duration.days(7),
60
+ secretName: "my-project/turbo-token",
61
+ });
62
+ ```
63
+
64
+ ## How It Works
65
+
66
+ The construct creates:
67
+
68
+ - **S3 bucket** - stores cached build artifacts with automatic expiration
69
+ - **Lambda function** with a public Function URL - handles Turborepo's remote cache API
70
+ - **Secrets Manager secret** - holds the JWT signing key for token authentication
71
+
72
+ Turborepo uses `--preflight` mode: it sends an OPTIONS request to get a presigned S3 URL, then uploads/downloads directly to S3. This means the Lambda only handles lightweight auth + URL generation, while S3 handles the heavy lifting.
73
+
74
+ ## CLI Reference
75
+
76
+ ```
77
+ wabicloud-turbo-cache generate-token
78
+
79
+ Flags:
80
+ --team Team ID (must start with "team_") [required]
81
+ --secret-name Secrets Manager secret name [default: turborepo/cache-token]
82
+ --region AWS region [default: us-east-1]
83
+ ```
84
+
85
+ Uses the standard AWS credential chain. Set `AWS_PROFILE` for named profiles.
86
+
87
+ ## Exposed Properties
88
+
89
+ The construct exposes these for further customization:
90
+
91
+ - `cache.functionUrl` - Lambda Function URL (use `.url` for the endpoint)
92
+ - `cache.secret` - Secrets Manager secret
93
+ - `cache.bucket` - S3 bucket
94
+
95
+ ## License
96
+
97
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/cli.ts
4
+ import { SignJWT } from "jose";
5
+ import {
6
+ SecretsManagerClient,
7
+ GetSecretValueCommand
8
+ } from "@aws-sdk/client-secrets-manager";
9
+ function usage() {
10
+ console.error(`Usage: turborepo-remote-cache-serverless generate-token \\
11
+ --team <team_id> \\
12
+ --secret-name <secret_name> \\
13
+ --region <aws_region>
14
+
15
+ Flags:
16
+ --team Team ID (must start with "team_"), e.g. team_myproject
17
+ --secret-name Secrets Manager secret name (default: turborepo/cache-token)
18
+ --region AWS region (default: us-east-1)
19
+
20
+ Uses the standard AWS credential chain (env vars, profiles, instance roles).
21
+ Set AWS_PROFILE to use a named profile.`);
22
+ process.exit(1);
23
+ }
24
+ function parseArgs(argv) {
25
+ const args = argv.slice(2);
26
+ if (args[0] !== "generate-token") {
27
+ console.error(`Unknown command: ${args[0] ?? "(none)"}`);
28
+ usage();
29
+ }
30
+ let team;
31
+ let secretName = "turborepo/cache-token";
32
+ let region = "us-east-1";
33
+ for (let i = 1; i < args.length; i++) {
34
+ switch (args[i]) {
35
+ case "--team":
36
+ team = args[++i];
37
+ break;
38
+ case "--secret-name":
39
+ secretName = args[++i];
40
+ break;
41
+ case "--region":
42
+ region = args[++i];
43
+ break;
44
+ default:
45
+ console.error(`Unknown flag: ${args[i]}`);
46
+ usage();
47
+ }
48
+ }
49
+ if (!team) {
50
+ console.error("Error: --team is required");
51
+ usage();
52
+ }
53
+ if (!/^team_\w+$/.test(team)) {
54
+ console.error(
55
+ 'Error: Team ID must start with "team_" followed by alphanumeric characters'
56
+ );
57
+ console.error("Example: team_wabicloud, team_myproject");
58
+ process.exit(1);
59
+ }
60
+ return { team, secretName, region };
61
+ }
62
+ async function main() {
63
+ const { team, secretName, region } = parseArgs(process.argv);
64
+ const client = new SecretsManagerClient({ region });
65
+ const response = await client.send(
66
+ new GetSecretValueCommand({ SecretId: secretName })
67
+ );
68
+ const jwtSecret = response.SecretString;
69
+ if (!jwtSecret) {
70
+ console.error(
71
+ "Error: Could not retrieve JWT secret from Secrets Manager"
72
+ );
73
+ process.exit(1);
74
+ }
75
+ const secretKey = new TextEncoder().encode(jwtSecret);
76
+ const token = await new SignJWT({ teamId: team }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().sign(secretKey);
77
+ console.log("\n=== Turborepo Remote Cache Token ===\n");
78
+ console.log(`Team: ${team}
79
+ `);
80
+ console.log("Add these to your environment:\n");
81
+ console.log(`export TURBO_TOKEN="${token}"`);
82
+ console.log(`export TURBO_TEAM="${team}"`);
83
+ console.log(
84
+ "\nSet TURBO_API to your Function URL, then run: pnpm turbo build --preflight\n"
85
+ );
86
+ }
87
+ main().catch((err) => {
88
+ console.error("Error:", err.message);
89
+ process.exit(1);
90
+ });
@@ -0,0 +1 @@
1
+ import{S3Client as h,HeadObjectCommand as p}from"@aws-sdk/client-s3";import{S3RequestPresigner as y}from"@aws-sdk/s3-request-presigner";import{Hash as C}from"@smithy/hash-node";import{HttpRequest as w}from"@smithy/protocol-http";import{parseUrl as E}from"@smithy/url-parser";import{formatUrl as S}from"@aws-sdk/util-format-url";import{SecretsManagerClient as T,GetSecretValueCommand as b}from"@aws-sdk/client-secrets-manager";import{fromNodeProviderChain as P}from"@aws-sdk/credential-providers";import*as f from"jose";var R=new h({}),N=new T({}),g=process.env.CACHE_BUCKET,l=process.env.AWS_REGION||"eu-central-1",I=process.env.TURBO_TOKEN_SECRET_ARN,U=3600,d=null;async function A(){return d||(d=(await N.send(new b({SecretId:I}))).SecretString,d)}async function O(e,n){let r=e.replace("Bearer ",""),s=new TextEncoder().encode(n),{payload:o}=await f.jwtVerify(r,s),t=o.teamId;if(!t||!/^team_\w+$/.test(t))throw new Error("Invalid token: missing or invalid teamId");return{teamId:t}}async function q(e,n,r){let s=new y({credentials:P(),region:l,sha256:C.bind(null,"sha256")}),o=E(`https://${g}.s3.${l}.amazonaws.com/${n}`),t=new w({...o,method:e});t.query={...t.query,slug:r};let a=await s.presign(t,{expiresIn:U});return S(a).replace("&slug="+encodeURIComponent(r),"")}var k=async e=>{let{method:n,path:r}=e.requestContext.http;if(n==="GET"&&r==="/v8/artifacts/status")return{statusCode:200,body:JSON.stringify({enabled:!0})};if(n==="POST"&&r==="/v8/artifacts/events")return{statusCode:200,body:"{}"};let s=r.match(/^\/v8\/artifacts\/([a-f0-9]+)$/);if(!s)return{statusCode:404,body:"Not found"};let o=await A(),t=e.headers.authorization||"",a;try{a=(await O(t,o)).teamId}catch{return{statusCode:401,body:"Unauthorized"}}let u=s[1],m=`${a}/${u}`;if(n==="OPTIONS"){let i=e.headers["access-control-request-method"]||e.headers["Access-Control-Request-Method"];if(i==="GET")try{await R.send(new p({Bucket:g,Key:m}))}catch(c){if(c instanceof Error&&(c.name==="NotFound"||c.name==="NoSuchKey"))return{statusCode:404,body:"Not found"};throw c}return i==="GET"||i==="PUT"?{statusCode:200,headers:{location:await q(i,m,a),"Access-Control-Allow-Origin":"*","Access-Control-Allow-Methods":"GET, PUT, OPTIONS","Access-Control-Allow-Headers":"Content-Type, User-Agent, x-artifact-duration, x-artifact-tag"},body:""}:{statusCode:404,body:"Not found"}}return{statusCode:404,body:"Not found"}};export{k as handler};
package/dist/index.cjs ADDED
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ TurborepoRemoteCache: () => TurborepoRemoteCache
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/construct.ts
38
+ var cdk = __toESM(require("aws-cdk-lib"), 1);
39
+ var s3 = __toESM(require("aws-cdk-lib/aws-s3"), 1);
40
+ var lambda = __toESM(require("aws-cdk-lib/aws-lambda"), 1);
41
+ var logs = __toESM(require("aws-cdk-lib/aws-logs"), 1);
42
+ var secretsmanager = __toESM(require("aws-cdk-lib/aws-secretsmanager"), 1);
43
+ var import_constructs = require("constructs");
44
+ var import_node_path = require("path");
45
+ var TurborepoRemoteCache = class extends import_constructs.Construct {
46
+ /** The Lambda Function URL endpoint (use as TURBO_API). */
47
+ functionUrl;
48
+ /** The Secrets Manager secret holding the JWT signing key. */
49
+ secret;
50
+ /** The S3 bucket storing cached artifacts. */
51
+ bucket;
52
+ constructor(scope, id, props = {}) {
53
+ super(scope, id);
54
+ const {
55
+ expiration = cdk.Duration.days(30),
56
+ secretName = "turborepo/cache-token"
57
+ } = props;
58
+ this.bucket = new s3.Bucket(this, "CacheBucket", {
59
+ encryption: s3.BucketEncryption.S3_MANAGED,
60
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
61
+ lifecycleRules: [{ expiration }],
62
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
63
+ autoDeleteObjects: true,
64
+ cors: [
65
+ {
66
+ allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.PUT],
67
+ allowedOrigins: ["*"],
68
+ allowedHeaders: ["*"],
69
+ maxAge: 3e3
70
+ }
71
+ ]
72
+ });
73
+ this.secret = new secretsmanager.Secret(this, "TurboToken", {
74
+ secretName,
75
+ generateSecretString: {
76
+ excludePunctuation: true,
77
+ passwordLength: 32
78
+ }
79
+ });
80
+ const cacheHandler = new lambda.Function(this, "CacheHandler", {
81
+ runtime: lambda.Runtime.NODEJS_22_X,
82
+ handler: "index.handler",
83
+ code: lambda.Code.fromAsset((0, import_node_path.join)(__dirname, "handler")),
84
+ memorySize: 1024,
85
+ timeout: cdk.Duration.seconds(30),
86
+ environment: {
87
+ CACHE_BUCKET: this.bucket.bucketName,
88
+ TURBO_TOKEN_SECRET_ARN: this.secret.secretArn
89
+ }
90
+ });
91
+ new logs.LogGroup(this, "CacheHandlerLogGroup", {
92
+ logGroupName: `/aws/lambda/${cacheHandler.functionName}`,
93
+ retention: logs.RetentionDays.ONE_MONTH,
94
+ removalPolicy: cdk.RemovalPolicy.DESTROY
95
+ });
96
+ this.bucket.grantReadWrite(cacheHandler);
97
+ this.secret.grantRead(cacheHandler);
98
+ this.functionUrl = cacheHandler.addFunctionUrl({
99
+ authType: lambda.FunctionUrlAuthType.NONE
100
+ });
101
+ }
102
+ };
103
+ // Annotate the CommonJS export names for ESM import in node:
104
+ 0 && (module.exports = {
105
+ TurborepoRemoteCache
106
+ });
@@ -0,0 +1,29 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import * as s3 from 'aws-cdk-lib/aws-s3';
3
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
4
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
5
+ import { Construct } from 'constructs';
6
+
7
+ interface TurborepoRemoteCacheProps {
8
+ /**
9
+ * How long cached artifacts are kept before automatic deletion.
10
+ * @default Duration.days(30)
11
+ */
12
+ readonly expiration?: cdk.Duration;
13
+ /**
14
+ * Name of the Secrets Manager secret that stores the JWT signing key.
15
+ * @default 'turborepo/cache-token'
16
+ */
17
+ readonly secretName?: string;
18
+ }
19
+ declare class TurborepoRemoteCache extends Construct {
20
+ /** The Lambda Function URL endpoint (use as TURBO_API). */
21
+ readonly functionUrl: lambda.FunctionUrl;
22
+ /** The Secrets Manager secret holding the JWT signing key. */
23
+ readonly secret: secretsmanager.Secret;
24
+ /** The S3 bucket storing cached artifacts. */
25
+ readonly bucket: s3.Bucket;
26
+ constructor(scope: Construct, id: string, props?: TurborepoRemoteCacheProps);
27
+ }
28
+
29
+ export { TurborepoRemoteCache, type TurborepoRemoteCacheProps };
@@ -0,0 +1,29 @@
1
+ import * as cdk from 'aws-cdk-lib';
2
+ import * as s3 from 'aws-cdk-lib/aws-s3';
3
+ import * as lambda from 'aws-cdk-lib/aws-lambda';
4
+ import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
5
+ import { Construct } from 'constructs';
6
+
7
+ interface TurborepoRemoteCacheProps {
8
+ /**
9
+ * How long cached artifacts are kept before automatic deletion.
10
+ * @default Duration.days(30)
11
+ */
12
+ readonly expiration?: cdk.Duration;
13
+ /**
14
+ * Name of the Secrets Manager secret that stores the JWT signing key.
15
+ * @default 'turborepo/cache-token'
16
+ */
17
+ readonly secretName?: string;
18
+ }
19
+ declare class TurborepoRemoteCache extends Construct {
20
+ /** The Lambda Function URL endpoint (use as TURBO_API). */
21
+ readonly functionUrl: lambda.FunctionUrl;
22
+ /** The Secrets Manager secret holding the JWT signing key. */
23
+ readonly secret: secretsmanager.Secret;
24
+ /** The S3 bucket storing cached artifacts. */
25
+ readonly bucket: s3.Bucket;
26
+ constructor(scope: Construct, id: string, props?: TurborepoRemoteCacheProps);
27
+ }
28
+
29
+ export { TurborepoRemoteCache, type TurborepoRemoteCacheProps };
package/dist/index.js ADDED
@@ -0,0 +1,76 @@
1
+ // node_modules/.pnpm/tsup@8.5.1_postcss@8.5.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ var getFilename = () => fileURLToPath(import.meta.url);
5
+ var getDirname = () => path.dirname(getFilename());
6
+ var __dirname = /* @__PURE__ */ getDirname();
7
+
8
+ // src/construct.ts
9
+ import * as cdk from "aws-cdk-lib";
10
+ import * as s3 from "aws-cdk-lib/aws-s3";
11
+ import * as lambda from "aws-cdk-lib/aws-lambda";
12
+ import * as logs from "aws-cdk-lib/aws-logs";
13
+ import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
14
+ import { Construct } from "constructs";
15
+ import { join } from "path";
16
+ var TurborepoRemoteCache = class extends Construct {
17
+ /** The Lambda Function URL endpoint (use as TURBO_API). */
18
+ functionUrl;
19
+ /** The Secrets Manager secret holding the JWT signing key. */
20
+ secret;
21
+ /** The S3 bucket storing cached artifacts. */
22
+ bucket;
23
+ constructor(scope, id, props = {}) {
24
+ super(scope, id);
25
+ const {
26
+ expiration = cdk.Duration.days(30),
27
+ secretName = "turborepo/cache-token"
28
+ } = props;
29
+ this.bucket = new s3.Bucket(this, "CacheBucket", {
30
+ encryption: s3.BucketEncryption.S3_MANAGED,
31
+ blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
32
+ lifecycleRules: [{ expiration }],
33
+ removalPolicy: cdk.RemovalPolicy.DESTROY,
34
+ autoDeleteObjects: true,
35
+ cors: [
36
+ {
37
+ allowedMethods: [s3.HttpMethods.GET, s3.HttpMethods.PUT],
38
+ allowedOrigins: ["*"],
39
+ allowedHeaders: ["*"],
40
+ maxAge: 3e3
41
+ }
42
+ ]
43
+ });
44
+ this.secret = new secretsmanager.Secret(this, "TurboToken", {
45
+ secretName,
46
+ generateSecretString: {
47
+ excludePunctuation: true,
48
+ passwordLength: 32
49
+ }
50
+ });
51
+ const cacheHandler = new lambda.Function(this, "CacheHandler", {
52
+ runtime: lambda.Runtime.NODEJS_22_X,
53
+ handler: "index.handler",
54
+ code: lambda.Code.fromAsset(join(__dirname, "handler")),
55
+ memorySize: 1024,
56
+ timeout: cdk.Duration.seconds(30),
57
+ environment: {
58
+ CACHE_BUCKET: this.bucket.bucketName,
59
+ TURBO_TOKEN_SECRET_ARN: this.secret.secretArn
60
+ }
61
+ });
62
+ new logs.LogGroup(this, "CacheHandlerLogGroup", {
63
+ logGroupName: `/aws/lambda/${cacheHandler.functionName}`,
64
+ retention: logs.RetentionDays.ONE_MONTH,
65
+ removalPolicy: cdk.RemovalPolicy.DESTROY
66
+ });
67
+ this.bucket.grantReadWrite(cacheHandler);
68
+ this.secret.grantRead(cacheHandler);
69
+ this.functionUrl = cacheHandler.addFunctionUrl({
70
+ authType: lambda.FunctionUrlAuthType.NONE
71
+ });
72
+ }
73
+ };
74
+ export {
75
+ TurborepoRemoteCache
76
+ };
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@wabicloud/turborepo-remote-cache-serverless",
3
+ "version": "0.1.0",
4
+ "description": "AWS CDK construct for deploying a Turborepo remote cache backed by S3 and Lambda",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "bin": {
22
+ "wabicloud-turbo-cache": "./dist/cli.js"
23
+ },
24
+ "files": [
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "test": "vitest run",
30
+ "test:watch": "vitest",
31
+ "typecheck": "tsc --noEmit",
32
+ "prepublishOnly": "pnpm build"
33
+ },
34
+ "keywords": [
35
+ "turborepo",
36
+ "remote-cache",
37
+ "aws",
38
+ "cdk",
39
+ "serverless",
40
+ "s3",
41
+ "lambda"
42
+ ],
43
+ "license": "MIT",
44
+ "peerDependencies": {
45
+ "aws-cdk-lib": "^2.0.0",
46
+ "constructs": "^10.0.0"
47
+ },
48
+ "dependencies": {
49
+ "jose": "^6.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "@aws-sdk/client-s3": "^3.0.0",
53
+ "@aws-sdk/client-secrets-manager": "^3.0.0",
54
+ "@aws-sdk/credential-providers": "^3.0.0",
55
+ "@aws-sdk/s3-request-presigner": "^3.0.0",
56
+ "@aws-sdk/util-format-url": "^3.0.0",
57
+ "@smithy/hash-node": "^4.0.0",
58
+ "@smithy/protocol-http": "^5.0.0",
59
+ "@smithy/url-parser": "^4.0.0",
60
+ "@types/node": "^25.3.0",
61
+ "aws-cdk-lib": "^2.0.0",
62
+ "constructs": "^10.0.0",
63
+ "tsup": "^8.0.0",
64
+ "typescript": "^5.0.0",
65
+ "vitest": "^3.0.0"
66
+ },
67
+ "pnpm": {
68
+ "onlyBuiltDependencies": [
69
+ "esbuild"
70
+ ]
71
+ }
72
+ }