From fc8396dfc36aebd4151f3f36918cd8e7e263bbf2 Mon Sep 17 00:00:00 2001 From: George Fu Date: Wed, 8 May 2024 17:08:39 +0000 Subject: [PATCH 1/9] chore(core): create submodule exports in core --- packages/core/README.md | 10 ++++++++ packages/core/package.json | 21 ++++++++++++++++- packages/core/scripts/lint.js | 19 +++++---------- packages/core/src/index.ts | 2 +- .../emitWarningIfUnsupportedVersion.spec.ts | 0 .../client/emitWarningIfUnsupportedVersion.ts | 0 .../core/src/{ => submodules}/client/index.ts | 0 scripts/compilation/Inliner.js | 23 +++++++++++++++---- 8 files changed, 56 insertions(+), 19 deletions(-) rename packages/core/src/{ => submodules}/client/emitWarningIfUnsupportedVersion.spec.ts (100%) rename packages/core/src/{ => submodules}/client/emitWarningIfUnsupportedVersion.ts (100%) rename packages/core/src/{ => submodules}/client/index.ts (100%) diff --git a/packages/core/README.md b/packages/core/README.md index 0bbfa21259f2..aa3b45121e17 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -3,3 +3,13 @@ This package provides common or core functionality to the AWS SDK for JavaScript (v3). You do not need to explicitly install this package, since it will be transitively installed by AWS SDK clients. + +## Core Submodules + +Core submodules are organized for distribution via the `package.json` `exports` field. + +`exports` is supported by default by the latest Node.js, webpack, and esbuild. For react-native, it can be +enabled via instructions found at [reactnative.dev/blog](https://reactnative.dev/blog/2023/06/21/package-exports-support). + +Each `index.ts` file corresponding to the pattern `./src/submodules//index.ts` will be +published as a separate `dist-cjs` bundled submodule index using the inliner build script. diff --git a/packages/core/package.json b/packages/core/package.json index 49be79f4d576..dde158c53270 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -3,7 +3,7 @@ "version": "3.575.0", "description": "Core functions & classes shared by multiple AWS SDK clients", "scripts": { - "build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'", + "build": "yarn lint && concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'", "build:cjs": "node ../../scripts/compilation/inline core", "build:es": "tsc -p tsconfig.es.json", "build:include:deps": "lerna run --scope $npm_package_name --include-dependencies build", @@ -18,6 +18,25 @@ "main": "./dist-cjs/index.js", "module": "./dist-es/index.js", "types": "./dist-types/index.d.ts", + "exports": { + ".": { + "node": "./dist-cjs/index.js", + "import": "./dist-es/index.js", + "require": "./dist-cjs/index.js", + "types": "./dist-types/index.d.ts" + }, + "./package.json": { + "node": "./package.json", + "import": "./package.json", + "require": "./package.json" + }, + "./client": { + "node": "./dist-cjs/client/index.js", + "import": "./dist-es/client/index.js", + "require": "./dist-cjs/client/index.js", + "types": "./dist-types/client/index.d.ts" + } + }, "sideEffects": false, "author": { "name": "AWS SDK for JavaScript Team", diff --git a/packages/core/scripts/lint.js b/packages/core/scripts/lint.js index ffaa9c4edf5f..87777172deb3 100644 --- a/packages/core/scripts/lint.js +++ b/packages/core/scripts/lint.js @@ -5,20 +5,13 @@ const assert = require("assert"); const root = path.join(__dirname, ".."); const pkgJson = require(path.join(root, "package.json")); -const srcFolders = fs.readdirSync(path.join(root, "src")); +const submodules = fs.readdirSync(path.join(root, "src", "submodules")); -assert(pkgJson.exports === undefined, "We cannot support package.json exports yet."); - -/** - * We probably can't enable package.json exports until - * dropping support for Node.js 14.x and TypeScript 4.6. - */ -process.exit(0); - -for (const srcFolder of srcFolders) { - if (fs.lstatSync(path.join(root, "src", srcFolder)).isDirectory()) { - if (!pkgJson.exports["./" + srcFolder]) { - throw new Error(`${srcFolder} is missing exports statement in package.json`); +for (const submodule of submodules) { + const submodulePath = path.join(root, "src", "submodules", submodule); + if (fs.existsSync(submodulePath) && fs.lstatSync(submodulePath).isDirectory()) { + if (!pkgJson.exports[`./${submodule}`]) { + throw new Error(`${submodule} submodule is missing exports statement in package.json`); } } } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 532feb93c8c9..b7d910c6d646 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,3 +1,3 @@ -export * from "./client/index"; export * from "./httpAuthSchemes/index"; export * from "./protocols/index"; +export * from "./submodules/client/index"; diff --git a/packages/core/src/client/emitWarningIfUnsupportedVersion.spec.ts b/packages/core/src/submodules/client/emitWarningIfUnsupportedVersion.spec.ts similarity index 100% rename from packages/core/src/client/emitWarningIfUnsupportedVersion.spec.ts rename to packages/core/src/submodules/client/emitWarningIfUnsupportedVersion.spec.ts diff --git a/packages/core/src/client/emitWarningIfUnsupportedVersion.ts b/packages/core/src/submodules/client/emitWarningIfUnsupportedVersion.ts similarity index 100% rename from packages/core/src/client/emitWarningIfUnsupportedVersion.ts rename to packages/core/src/submodules/client/emitWarningIfUnsupportedVersion.ts diff --git a/packages/core/src/client/index.ts b/packages/core/src/submodules/client/index.ts similarity index 100% rename from packages/core/src/client/index.ts rename to packages/core/src/submodules/client/index.ts diff --git a/scripts/compilation/Inliner.js b/scripts/compilation/Inliner.js index 717da9a71716..5b0a0f4145ac 100644 --- a/scripts/compilation/Inliner.js +++ b/scripts/compilation/Inliner.js @@ -19,6 +19,7 @@ module.exports = class Inliner { this.isPackage = fs.existsSync(path.join(root, "packages", pkg)); this.isLib = fs.existsSync(path.join(root, "lib", pkg)); this.isClient = !this.isPackage && !this.isLib; + this.isCore = pkg === "core"; this.subfolder = this.isPackage ? "packages" : this.isLib ? "lib" : "clients"; this.packageDirectory = path.join(root, this.subfolder, pkg); @@ -149,9 +150,9 @@ module.exports = class Inliner { (variant) => "*/" + path.basename(variant).replace(/.js$/, "") ); - await esbuild.build({ + const buildOptions = { platform: this.platform, - target: ["node14"], + target: ["node16"], bundle: true, format: "cjs", mainFields: ["main"], @@ -164,7 +165,21 @@ module.exports = class Inliner { keepNames: true, packages: "external", external: ["@smithy/*", "@aws-sdk/*", "node_modules/*", ...this.variantExternalsForEsBuild], - }); + }; + + await esbuild.build(buildOptions); + + if (this.isCore) { + const submodules = fs.readdirSync(path.join(root, this.subfolder, this.package, "src", "subfolders")); + for (const submodule of submodules) { + await esbuild.build({ + ...buildOptions, + entryPoints: [path.join(root, this.subfolder, this.package, "src", submodule, "index.ts")], + outfile: path.join(root, this.subfolder, this.package, "dist-cjs", submodule, "index.js"), + }); + } + } + return this; } @@ -173,7 +188,7 @@ module.exports = class Inliner { * These now become re-exports of the index to preserve deep-import behavior. */ async rewriteStubs() { - if (this.bailout) { + if (this.bailout || this.isCore) { return this; } From 901338dc4c8c643ca51b99de34345d35cb495df0 Mon Sep 17 00:00:00 2001 From: George Fu Date: Wed, 8 May 2024 17:31:06 +0000 Subject: [PATCH 2/9] chore(core): organize submodules --- packages/core/package.json | 12 +++++++++++ packages/core/scripts/lint.js | 5 ++++- packages/core/src/index.ts | 20 +++++++++++++++++-- .../aws_sdk/AwsSdkSigV4Signer.spec.ts | 0 .../aws_sdk/AwsSdkSigV4Signer.ts | 0 .../httpAuthSchemes/aws_sdk/index.ts | 0 .../aws_sdk/resolveAwsSdkSigV4Config.ts | 0 .../{ => submodules}/httpAuthSchemes/index.ts | 0 .../httpAuthSchemes/utils/getDateHeader.ts | 0 .../utils/getSkewCorrectedDate.spec.ts | 0 .../utils/getSkewCorrectedDate.ts | 0 .../utils/getUpdatedSystemClockOffset.spec.ts | 0 .../utils/getUpdatedSystemClockOffset.ts | 0 .../httpAuthSchemes/utils/index.ts | 0 .../utils/isClockSkewed.spec.ts | 0 .../httpAuthSchemes/utils/isClockSkewed.ts | 0 .../protocols/coercing-serializers.spec.ts | 0 .../protocols/coercing-serializers.ts | 0 .../src/{ => submodules}/protocols/common.ts | 0 .../src/{ => submodules}/protocols/index.ts | 0 .../protocols/json/awsExpectUnion.spec.ts | 0 .../protocols/json/awsExpectUnion.ts | 0 .../protocols/json/parseJsonBody.ts | 0 .../protocols/xml/parseXmlBody.spec.ts | 0 .../protocols/xml/parseXmlBody.ts | 0 scripts/compilation/Inliner.js | 10 +++++++--- 26 files changed, 41 insertions(+), 6 deletions(-) rename packages/core/src/{ => submodules}/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.spec.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/aws_sdk/index.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/index.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/getDateHeader.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/getSkewCorrectedDate.spec.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/getSkewCorrectedDate.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/getUpdatedSystemClockOffset.spec.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/getUpdatedSystemClockOffset.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/index.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/isClockSkewed.spec.ts (100%) rename packages/core/src/{ => submodules}/httpAuthSchemes/utils/isClockSkewed.ts (100%) rename packages/core/src/{ => submodules}/protocols/coercing-serializers.spec.ts (100%) rename packages/core/src/{ => submodules}/protocols/coercing-serializers.ts (100%) rename packages/core/src/{ => submodules}/protocols/common.ts (100%) rename packages/core/src/{ => submodules}/protocols/index.ts (100%) rename packages/core/src/{ => submodules}/protocols/json/awsExpectUnion.spec.ts (100%) rename packages/core/src/{ => submodules}/protocols/json/awsExpectUnion.ts (100%) rename packages/core/src/{ => submodules}/protocols/json/parseJsonBody.ts (100%) rename packages/core/src/{ => submodules}/protocols/xml/parseXmlBody.spec.ts (100%) rename packages/core/src/{ => submodules}/protocols/xml/parseXmlBody.ts (100%) diff --git a/packages/core/package.json b/packages/core/package.json index dde158c53270..83a5f5a97b16 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -35,6 +35,18 @@ "import": "./dist-es/client/index.js", "require": "./dist-cjs/client/index.js", "types": "./dist-types/client/index.d.ts" + }, + "./httpAuthSchemes": { + "node": "./dist-cjs/httpAuthSchemes/index.js", + "import": "./dist-es/httpAuthSchemes/index.js", + "require": "./dist-cjs/httpAuthSchemes/index.js", + "types": "./dist-types/httpAuthSchemes/index.d.ts" + }, + "./protocols": { + "node": "./dist-cjs/protocols/index.js", + "import": "./dist-es/protocols/index.js", + "require": "./dist-cjs/protocols/index.js", + "types": "./dist-types/protocols/index.d.ts" } }, "sideEffects": false, diff --git a/packages/core/scripts/lint.js b/packages/core/scripts/lint.js index 87777172deb3..ae0d96cf08af 100644 --- a/packages/core/scripts/lint.js +++ b/packages/core/scripts/lint.js @@ -1,6 +1,5 @@ const fs = require("fs"); const path = require("path"); -const assert = require("assert"); const root = path.join(__dirname, ".."); @@ -15,3 +14,7 @@ for (const submodule of submodules) { } } } + +/** + * Check for cross-submodule relative imports. + */ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index b7d910c6d646..16d273de4deb 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,3 +1,19 @@ -export * from "./httpAuthSchemes/index"; -export * from "./protocols/index"; +/** + * Submodules annotated with "deprecated" are legacy from prior to the submodule system. + * They are exported from the package's root index to preserve backwards compatibility. + * + * New development should go in a proper submodule and not be exported from the root index. + */ + +/** + * Deprecated submodule. + */ export * from "./submodules/client/index"; +/** + * Deprecated submodule. + */ +export * from "./submodules/httpAuthSchemes/index"; +/** + * Deprecated submodule. + */ +export * from "./submodules/protocols/index"; diff --git a/packages/core/src/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.spec.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.spec.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.spec.ts rename to packages/core/src/submodules/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.spec.ts diff --git a/packages/core/src/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.ts rename to packages/core/src/submodules/httpAuthSchemes/aws_sdk/AwsSdkSigV4Signer.ts diff --git a/packages/core/src/httpAuthSchemes/aws_sdk/index.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/index.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/aws_sdk/index.ts rename to packages/core/src/submodules/httpAuthSchemes/aws_sdk/index.ts diff --git a/packages/core/src/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts b/packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts rename to packages/core/src/submodules/httpAuthSchemes/aws_sdk/resolveAwsSdkSigV4Config.ts diff --git a/packages/core/src/httpAuthSchemes/index.ts b/packages/core/src/submodules/httpAuthSchemes/index.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/index.ts rename to packages/core/src/submodules/httpAuthSchemes/index.ts diff --git a/packages/core/src/httpAuthSchemes/utils/getDateHeader.ts b/packages/core/src/submodules/httpAuthSchemes/utils/getDateHeader.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/getDateHeader.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/getDateHeader.ts diff --git a/packages/core/src/httpAuthSchemes/utils/getSkewCorrectedDate.spec.ts b/packages/core/src/submodules/httpAuthSchemes/utils/getSkewCorrectedDate.spec.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/getSkewCorrectedDate.spec.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/getSkewCorrectedDate.spec.ts diff --git a/packages/core/src/httpAuthSchemes/utils/getSkewCorrectedDate.ts b/packages/core/src/submodules/httpAuthSchemes/utils/getSkewCorrectedDate.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/getSkewCorrectedDate.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/getSkewCorrectedDate.ts diff --git a/packages/core/src/httpAuthSchemes/utils/getUpdatedSystemClockOffset.spec.ts b/packages/core/src/submodules/httpAuthSchemes/utils/getUpdatedSystemClockOffset.spec.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/getUpdatedSystemClockOffset.spec.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/getUpdatedSystemClockOffset.spec.ts diff --git a/packages/core/src/httpAuthSchemes/utils/getUpdatedSystemClockOffset.ts b/packages/core/src/submodules/httpAuthSchemes/utils/getUpdatedSystemClockOffset.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/getUpdatedSystemClockOffset.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/getUpdatedSystemClockOffset.ts diff --git a/packages/core/src/httpAuthSchemes/utils/index.ts b/packages/core/src/submodules/httpAuthSchemes/utils/index.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/index.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/index.ts diff --git a/packages/core/src/httpAuthSchemes/utils/isClockSkewed.spec.ts b/packages/core/src/submodules/httpAuthSchemes/utils/isClockSkewed.spec.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/isClockSkewed.spec.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/isClockSkewed.spec.ts diff --git a/packages/core/src/httpAuthSchemes/utils/isClockSkewed.ts b/packages/core/src/submodules/httpAuthSchemes/utils/isClockSkewed.ts similarity index 100% rename from packages/core/src/httpAuthSchemes/utils/isClockSkewed.ts rename to packages/core/src/submodules/httpAuthSchemes/utils/isClockSkewed.ts diff --git a/packages/core/src/protocols/coercing-serializers.spec.ts b/packages/core/src/submodules/protocols/coercing-serializers.spec.ts similarity index 100% rename from packages/core/src/protocols/coercing-serializers.spec.ts rename to packages/core/src/submodules/protocols/coercing-serializers.spec.ts diff --git a/packages/core/src/protocols/coercing-serializers.ts b/packages/core/src/submodules/protocols/coercing-serializers.ts similarity index 100% rename from packages/core/src/protocols/coercing-serializers.ts rename to packages/core/src/submodules/protocols/coercing-serializers.ts diff --git a/packages/core/src/protocols/common.ts b/packages/core/src/submodules/protocols/common.ts similarity index 100% rename from packages/core/src/protocols/common.ts rename to packages/core/src/submodules/protocols/common.ts diff --git a/packages/core/src/protocols/index.ts b/packages/core/src/submodules/protocols/index.ts similarity index 100% rename from packages/core/src/protocols/index.ts rename to packages/core/src/submodules/protocols/index.ts diff --git a/packages/core/src/protocols/json/awsExpectUnion.spec.ts b/packages/core/src/submodules/protocols/json/awsExpectUnion.spec.ts similarity index 100% rename from packages/core/src/protocols/json/awsExpectUnion.spec.ts rename to packages/core/src/submodules/protocols/json/awsExpectUnion.spec.ts diff --git a/packages/core/src/protocols/json/awsExpectUnion.ts b/packages/core/src/submodules/protocols/json/awsExpectUnion.ts similarity index 100% rename from packages/core/src/protocols/json/awsExpectUnion.ts rename to packages/core/src/submodules/protocols/json/awsExpectUnion.ts diff --git a/packages/core/src/protocols/json/parseJsonBody.ts b/packages/core/src/submodules/protocols/json/parseJsonBody.ts similarity index 100% rename from packages/core/src/protocols/json/parseJsonBody.ts rename to packages/core/src/submodules/protocols/json/parseJsonBody.ts diff --git a/packages/core/src/protocols/xml/parseXmlBody.spec.ts b/packages/core/src/submodules/protocols/xml/parseXmlBody.spec.ts similarity index 100% rename from packages/core/src/protocols/xml/parseXmlBody.spec.ts rename to packages/core/src/submodules/protocols/xml/parseXmlBody.spec.ts diff --git a/packages/core/src/protocols/xml/parseXmlBody.ts b/packages/core/src/submodules/protocols/xml/parseXmlBody.ts similarity index 100% rename from packages/core/src/protocols/xml/parseXmlBody.ts rename to packages/core/src/submodules/protocols/xml/parseXmlBody.ts diff --git a/scripts/compilation/Inliner.js b/scripts/compilation/Inliner.js index 5b0a0f4145ac..b65c39f566ed 100644 --- a/scripts/compilation/Inliner.js +++ b/scripts/compilation/Inliner.js @@ -170,12 +170,16 @@ module.exports = class Inliner { await esbuild.build(buildOptions); if (this.isCore) { - const submodules = fs.readdirSync(path.join(root, this.subfolder, this.package, "src", "subfolders")); + const submodules = fs.readdirSync(path.join(root, this.subfolder, this.package, "src", "submodules")); for (const submodule of submodules) { + fs.rmSync(path.join(path.join(root, this.subfolder, this.package, "dist-cjs", "submodules", submodule)), { + recursive: true, + force: true, + }); await esbuild.build({ ...buildOptions, - entryPoints: [path.join(root, this.subfolder, this.package, "src", submodule, "index.ts")], - outfile: path.join(root, this.subfolder, this.package, "dist-cjs", submodule, "index.js"), + entryPoints: [path.join(root, this.subfolder, this.package, "src", "submodules", submodule, "index.ts")], + outfile: path.join(root, this.subfolder, this.package, "dist-cjs", "submodules", submodule, "index.js"), }); } } From 827158a2876f5cea38ba4bfae3f5d370b46514c4 Mon Sep 17 00:00:00 2001 From: George Fu Date: Wed, 8 May 2024 18:03:17 +0000 Subject: [PATCH 3/9] chore(core): submodules linting --- packages/core/package.json | 24 ++++---- packages/core/scripts/lint.js | 58 ++++++++++++++++++- .../core/src/submodules/protocols/index.ts | 3 + packages/core/tsconfig.cjs.json | 7 ++- packages/core/tsconfig.es.json | 7 ++- packages/core/tsconfig.types.json | 7 ++- 6 files changed, 90 insertions(+), 16 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 83a5f5a97b16..3a8695eb798d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -31,22 +31,22 @@ "require": "./package.json" }, "./client": { - "node": "./dist-cjs/client/index.js", - "import": "./dist-es/client/index.js", - "require": "./dist-cjs/client/index.js", - "types": "./dist-types/client/index.d.ts" + "node": "./dist-cjs/submodules/client/index.js", + "import": "./dist-es/submodules/client/index.js", + "require": "./dist-cjs/submodules/client/index.js", + "types": "./dist-types/submodules/client/index.d.ts" }, "./httpAuthSchemes": { - "node": "./dist-cjs/httpAuthSchemes/index.js", - "import": "./dist-es/httpAuthSchemes/index.js", - "require": "./dist-cjs/httpAuthSchemes/index.js", - "types": "./dist-types/httpAuthSchemes/index.d.ts" + "node": "./dist-cjs/submodules/httpAuthSchemes/index.js", + "import": "./dist-es/submodules/httpAuthSchemes/index.js", + "require": "./dist-cjs/submodules/httpAuthSchemes/index.js", + "types": "./dist-types/submodules/httpAuthSchemes/index.d.ts" }, "./protocols": { - "node": "./dist-cjs/protocols/index.js", - "import": "./dist-es/protocols/index.js", - "require": "./dist-cjs/protocols/index.js", - "types": "./dist-types/protocols/index.d.ts" + "node": "./dist-cjs/submodules/protocols/index.js", + "import": "./dist-es/submodules/protocols/index.js", + "require": "./dist-cjs/submodules/protocols/index.js", + "types": "./dist-types/submodules/protocols/index.d.ts" } }, "sideEffects": false, diff --git a/packages/core/scripts/lint.js b/packages/core/scripts/lint.js index ae0d96cf08af..2a7aef6cea42 100644 --- a/packages/core/scripts/lint.js +++ b/packages/core/scripts/lint.js @@ -4,13 +4,35 @@ const path = require("path"); const root = path.join(__dirname, ".."); const pkgJson = require(path.join(root, "package.json")); +const tsconfigs = { + cjs: require(path.join(root, "tsconfig.cjs.json")), + es: require(path.join(root, "tsconfig.es.json")), + types: require(path.join(root, "tsconfig.types.json")), +}; const submodules = fs.readdirSync(path.join(root, "src", "submodules")); +const errors = []; + for (const submodule of submodules) { const submodulePath = path.join(root, "src", "submodules", submodule); if (fs.existsSync(submodulePath) && fs.lstatSync(submodulePath).isDirectory()) { if (!pkgJson.exports[`./${submodule}`]) { - throw new Error(`${submodule} submodule is missing exports statement in package.json`); + errors.push(`${submodule} submodule is missing exports statement in package.json`); + pkgJson.exports[`./${submodule}`] = { + node: `./dist-cjs/submodules/${submodule}/index.js`, + import: `./dist-es/submodules/${submodule}/index.js`, + require: `./dist-cjs/submodules/${submodule}/index.js`, + types: `./dist-types/submodules/${submodule}/index.d.ts`, + }; + fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n"); + } + for (const [kind, tsconfig] of Object.entries(tsconfigs)) { + if (!tsconfig.compilerOptions.paths?.[`@aws-sdk/core/${submodule}`]) { + errors.push(`${submodule} submodule is missing paths entry in tsconfig.${kind}.json`); + + tsconfig.compilerOptions.paths[`@aws-sdk/core/${submodule}`] = [`./src/submodules/${submodule}/index.ts`]; + fs.writeFileSync(path.join(root, `tsconfig.${kind}.json`), JSON.stringify(tsconfig, null, 2) + "\n"); + } } } } @@ -18,3 +40,37 @@ for (const submodule of submodules) { /** * Check for cross-submodule relative imports. */ + +const walk = require("../../../scripts/utils/walk"); + +(async () => { + for await (const item of walk(path.join(root, "src", "submodules"))) { + // depth within the submodule where 1 is at the root of the submodule. + const depth = item.split("core/src/submodules/")[1].split("/").length - 1; + const sourceCode = fs.readFileSync(item, "utf-8"); + + const relativeImports = []; + relativeImports.push( + ...new Set( + [...(sourceCode.toString().match(/(from |import\()"(.*?)";/g) || [])] + .map((_) => _.replace(/from "/g, "").replace(/";$/, "")) + .filter((_) => _.startsWith(".")) + ) + ); + + for (const i of relativeImports) { + const relativeImportDepth = i.split("..").length - 1; + if (relativeImportDepth >= depth) { + errors.push( + `relative import ${i} in ${item + .split("packages/") + .pop()} crosses submodule boundaries. Use @scope/package/submodule import instead.` + ); + } + } + } +})().then(() => { + if (errors.length) { + throw new Error(errors.join("\n")); + } +}); diff --git a/packages/core/src/submodules/protocols/index.ts b/packages/core/src/submodules/protocols/index.ts index 09a6ac214ca0..6185f6e15e8e 100644 --- a/packages/core/src/submodules/protocols/index.ts +++ b/packages/core/src/submodules/protocols/index.ts @@ -2,3 +2,6 @@ export * from "./coercing-serializers"; export * from "./json/awsExpectUnion"; export * from "./json/parseJsonBody"; export * from "./xml/parseXmlBody"; + +import * as client from "@aws-sdk/core/client"; +console.log(client); diff --git a/packages/core/tsconfig.cjs.json b/packages/core/tsconfig.cjs.json index 8f8d63427a46..2c52f5b4acc6 100644 --- a/packages/core/tsconfig.cjs.json +++ b/packages/core/tsconfig.cjs.json @@ -2,7 +2,12 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist-cjs", - "baseUrl": "." + "baseUrl": ".", + "paths": { + "@aws-sdk/core/client": ["./src/submodules/client/index.ts"], + "@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"], + "@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"] + } }, "extends": "../../tsconfig.cjs.json", "include": ["src/"] diff --git a/packages/core/tsconfig.es.json b/packages/core/tsconfig.es.json index ce87108ba14e..ddd0ab53bf6d 100644 --- a/packages/core/tsconfig.es.json +++ b/packages/core/tsconfig.es.json @@ -2,7 +2,12 @@ "compilerOptions": { "rootDir": "./src", "outDir": "./dist-es", - "baseUrl": "." + "baseUrl": ".", + "paths": { + "@aws-sdk/core/client": ["./src/submodules/client/index.ts"], + "@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"], + "@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"] + } }, "extends": "../../tsconfig.es.json", "include": ["src/"] diff --git a/packages/core/tsconfig.types.json b/packages/core/tsconfig.types.json index 6cdf9f52ea06..2cacd51b596c 100644 --- a/packages/core/tsconfig.types.json +++ b/packages/core/tsconfig.types.json @@ -2,7 +2,12 @@ "compilerOptions": { "baseUrl": ".", "declarationDir": "dist-types", - "rootDir": "src" + "rootDir": "src", + "paths": { + "@aws-sdk/core/client": ["./src/submodules/client/index.ts"], + "@aws-sdk/core/httpAuthSchemes": ["./src/submodules/httpAuthSchemes/index.ts"], + "@aws-sdk/core/protocols": ["./src/submodules/protocols/index.ts"] + } }, "extends": "../../tsconfig.types.json", "include": ["src/"] From 2e202651522a53206a38f27b65625f72e4fd68fd Mon Sep 17 00:00:00 2001 From: George Fu Date: Wed, 8 May 2024 18:15:02 +0000 Subject: [PATCH 4/9] chore(core): submodule readmes --- packages/core/README.md | 32 ++++++++++++++++--- packages/core/src/index.ts | 13 +++++--- packages/core/src/submodules/client/README.md | 3 ++ .../src/submodules/httpAuthSchemes/README.md | 3 ++ .../core/src/submodules/protocols/README.md | 3 ++ .../core/src/submodules/protocols/index.ts | 3 -- 6 files changed, 46 insertions(+), 11 deletions(-) create mode 100644 packages/core/src/submodules/client/README.md create mode 100644 packages/core/src/submodules/httpAuthSchemes/README.md create mode 100644 packages/core/src/submodules/protocols/README.md diff --git a/packages/core/README.md b/packages/core/README.md index aa3b45121e17..6056468b607b 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -1,15 +1,39 @@ -# @aws-sdk/core +# `@aws-sdk/core` This package provides common or core functionality to the AWS SDK for JavaScript (v3). You do not need to explicitly install this package, since it will be transitively installed by AWS SDK clients. -## Core Submodules +## `@aws-sdk/core` submodules Core submodules are organized for distribution via the `package.json` `exports` field. `exports` is supported by default by the latest Node.js, webpack, and esbuild. For react-native, it can be enabled via instructions found at [reactnative.dev/blog](https://reactnative.dev/blog/2023/06/21/package-exports-support). -Each `index.ts` file corresponding to the pattern `./src/submodules//index.ts` will be -published as a separate `dist-cjs` bundled submodule index using the inliner build script. +Think of `@aws-sdk/core` as a mono-package within the monorepo. +It preserves the benefits of modularization, for example to optimize Node.js initialization speed, +while making it easier to have a consistent version of core dependencies, reducing package sprawl when +installing an SDK client. + +### Guide for submodules + +- Each `index.ts` file corresponding to the pattern `./src/submodules//index.ts` will be + published as a separate `dist-cjs` bundled submodule index using the `Inliner.js` build script. +- create a folder as `./src/submodules/` including an `index.ts` file and a `README.md` file. + - The linter will throw an error on missing submodule metadata in `package.json` and the various `tsconfig.json` files, but it will automatically fix them if possible. +- a submodule is equivalent to a standalone `@aws-sdk/` package in that importing it in Node.js will resolve a separate bundle. +- submodules may not relatively import files from other submodules. Instead, directly use the `@scope/pkg/submodule` name as the import. + - The linter will check for this and throw an error. +- To the extent possible, correctly declaring submodule metadata is validated by the linter in `@aws-sdk/core`. + The linter runs during `yarn build` and also as `yarn lint`. + +### When should I create an `@aws-sdk/core/submodule` vs. `@aws-sdk/new-package`? + +Keep in mind that the core package is installed by all AWS SDK clients. + +If the component functionality is upstream of multiple clients, it is +a good candidate for a core submodule. For example, XML serialization. + +If the component's functionality is downstream of a client, for example S3 pre-signing, +it should be a standalone package with potentially a peer or runtime dependency on an AWS SDK client. diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 16d273de4deb..82163e053924 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,19 +1,24 @@ /** - * Submodules annotated with "deprecated" are legacy from prior to the submodule system. + * Submodules annotated with "Legacy" are from prior to the submodule system. * They are exported from the package's root index to preserve backwards compatibility. * * New development should go in a proper submodule and not be exported from the root index. */ /** - * Deprecated submodule. + * Legacy submodule. */ export * from "./submodules/client/index"; /** - * Deprecated submodule. + * Legacy submodule. */ export * from "./submodules/httpAuthSchemes/index"; /** - * Deprecated submodule. + * Legacy submodule. */ export * from "./submodules/protocols/index"; + +/** + * Warning: do not export any additional submodules from the root of this package. See readme.md for + * guide on developing submodules. + */ diff --git a/packages/core/src/submodules/client/README.md b/packages/core/src/submodules/client/README.md new file mode 100644 index 000000000000..c0a40eddb506 --- /dev/null +++ b/packages/core/src/submodules/client/README.md @@ -0,0 +1,3 @@ +# @aws-sdk/core/client + +This is a legacy submodule that is also exported at the root index. diff --git a/packages/core/src/submodules/httpAuthSchemes/README.md b/packages/core/src/submodules/httpAuthSchemes/README.md new file mode 100644 index 000000000000..6aa5849456be --- /dev/null +++ b/packages/core/src/submodules/httpAuthSchemes/README.md @@ -0,0 +1,3 @@ +# @aws-sdk/core/httpAuthSchemes + +This is a legacy submodule that is also exported at the root index. diff --git a/packages/core/src/submodules/protocols/README.md b/packages/core/src/submodules/protocols/README.md new file mode 100644 index 000000000000..37baa7927165 --- /dev/null +++ b/packages/core/src/submodules/protocols/README.md @@ -0,0 +1,3 @@ +# @aws-sdk/core/protocols + +This is a legacy submodule that is also exported at the root index. diff --git a/packages/core/src/submodules/protocols/index.ts b/packages/core/src/submodules/protocols/index.ts index 6185f6e15e8e..09a6ac214ca0 100644 --- a/packages/core/src/submodules/protocols/index.ts +++ b/packages/core/src/submodules/protocols/index.ts @@ -2,6 +2,3 @@ export * from "./coercing-serializers"; export * from "./json/awsExpectUnion"; export * from "./json/parseJsonBody"; export * from "./xml/parseXmlBody"; - -import * as client from "@aws-sdk/core/client"; -console.log(client); From 81749fe4112bf39a6ed856f5afd8c2932d89d89a Mon Sep 17 00:00:00 2001 From: George Fu Date: Thu, 9 May 2024 17:40:05 +0000 Subject: [PATCH 5/9] chore(core): update readme about Metro package exports support --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index dffd12e9fdd1..30662b280027 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,11 @@ import "react-native-url-polyfill/auto"; import { DynamoDB } from "@aws-sdk/client-dynamodb"; ``` +Specifically Metro bundler used by react-native, enable Package Exports Support: + +- https://metrobundler.dev/docs/package-exports/ +- https://reactnative.dev/blog/2023/06/21/package-exports-support + ## New features ### Modularized packages From 8ad6b5bfedd896884b0b12432528fc73d0c8b008 Mon Sep 17 00:00:00 2001 From: George Fu Date: Thu, 9 May 2024 18:14:03 +0000 Subject: [PATCH 6/9] chore(core): add compatibility redirect files for core submodules --- packages/core/client.js | 5 +++++ packages/core/httpAuthSchemes.js | 5 +++++ packages/core/protocols.js | 5 +++++ packages/core/scripts/lint.js | 17 +++++++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 packages/core/client.js create mode 100644 packages/core/httpAuthSchemes.js create mode 100644 packages/core/protocols.js diff --git a/packages/core/client.js b/packages/core/client.js new file mode 100644 index 000000000000..e3a644bd8589 --- /dev/null +++ b/packages/core/client.js @@ -0,0 +1,5 @@ +/** + * Do not edit: + * This is a compatibility redirect for contexts that do not understand package.json exports field. + */ +module.exports = require("./dist-cjs/submodules/client/index.js"); diff --git a/packages/core/httpAuthSchemes.js b/packages/core/httpAuthSchemes.js new file mode 100644 index 000000000000..17685b072299 --- /dev/null +++ b/packages/core/httpAuthSchemes.js @@ -0,0 +1,5 @@ +/** + * Do not edit: + * This is a compatibility redirect for contexts that do not understand package.json exports field. + */ +module.exports = require("./dist-cjs/submodules/httpAuthSchemes/index.js"); diff --git a/packages/core/protocols.js b/packages/core/protocols.js new file mode 100644 index 000000000000..e2916e8fb322 --- /dev/null +++ b/packages/core/protocols.js @@ -0,0 +1,5 @@ +/** + * Do not edit: + * This is a compatibility redirect for contexts that do not understand package.json exports field. + */ +module.exports = require("./dist-cjs/submodules/protocols/index.js"); diff --git a/packages/core/scripts/lint.js b/packages/core/scripts/lint.js index 2a7aef6cea42..eb60b3c32903 100644 --- a/packages/core/scripts/lint.js +++ b/packages/core/scripts/lint.js @@ -16,6 +16,7 @@ const errors = []; for (const submodule of submodules) { const submodulePath = path.join(root, "src", "submodules", submodule); if (fs.existsSync(submodulePath) && fs.lstatSync(submodulePath).isDirectory()) { + // package.json metadata. if (!pkgJson.exports[`./${submodule}`]) { errors.push(`${submodule} submodule is missing exports statement in package.json`); pkgJson.exports[`./${submodule}`] = { @@ -26,6 +27,7 @@ for (const submodule of submodules) { }; fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n"); } + // tsconfig metadata. for (const [kind, tsconfig] of Object.entries(tsconfigs)) { if (!tsconfig.compilerOptions.paths?.[`@aws-sdk/core/${submodule}`]) { errors.push(`${submodule} submodule is missing paths entry in tsconfig.${kind}.json`); @@ -34,6 +36,21 @@ for (const submodule of submodules) { fs.writeFileSync(path.join(root, `tsconfig.${kind}.json`), JSON.stringify(tsconfig, null, 2) + "\n"); } } + // compatibility redirect file. + const compatibilityRedirectFile = path.join(root, `${submodule}.js`); + if (!fs.existsSync(compatibilityRedirectFile)) { + errors.push(`${submodule} is missing compatibility redirect file in the package root folder.`); + fs.writeFileSync( + compatibilityRedirectFile, + ` +/** + * Do not edit: + * This is a compatibility redirect for contexts that do not understand package.json exports field. + */ +module.exports = require("./dist-cjs/submodules/${submodule}/index.js"); +` + ); + } } } From 328397ad61c3682ce569e9a1cfd13e00c900ef1d Mon Sep 17 00:00:00 2001 From: George Fu Date: Thu, 9 May 2024 19:37:40 +0000 Subject: [PATCH 7/9] chore(core): add files entry in pkg.json --- packages/core/package.json | 6 ++++++ packages/core/scripts/lint.js | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/packages/core/package.json b/packages/core/package.json index 3a8695eb798d..0b4444a03cbc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -49,6 +49,12 @@ "types": "./dist-types/submodules/protocols/index.d.ts" } }, + "files": [ + "dist-*/**", + "./client.js", + "./httpAuthSchemes.js", + "./protocols.js" + ], "sideEffects": false, "author": { "name": "AWS SDK for JavaScript Team", diff --git a/packages/core/scripts/lint.js b/packages/core/scripts/lint.js index eb60b3c32903..8766fc133807 100644 --- a/packages/core/scripts/lint.js +++ b/packages/core/scripts/lint.js @@ -27,6 +27,11 @@ for (const submodule of submodules) { }; fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n"); } + if (!pkgJson.files.includes(`./${submodule}.js`)) { + pkgJson.files.push(`./${submodule}.js`); + errors.push(`package.json files array missing ${submodule}.js compatibility redirect file.`); + fs.writeFileSync(path.join(root, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n"); + } // tsconfig metadata. for (const [kind, tsconfig] of Object.entries(tsconfigs)) { if (!tsconfig.compilerOptions.paths?.[`@aws-sdk/core/${submodule}`]) { From a088ae7104c0e78d0209a97aee551f0c0de66eea Mon Sep 17 00:00:00 2001 From: George Fu Date: Thu, 9 May 2024 19:41:22 +0000 Subject: [PATCH 8/9] chore(core): add files pkg.json enforcement --- packages/cloudfront-signer/package.json | 3 +++ .../package-json-enforcement.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/packages/cloudfront-signer/package.json b/packages/cloudfront-signer/package.json index e95354176fdd..3f151df6d1b4 100644 --- a/packages/cloudfront-signer/package.json +++ b/packages/cloudfront-signer/package.json @@ -24,6 +24,9 @@ "@smithy/url-parser": "^3.0.0", "tslib": "^2.6.2" }, + "files": [ + "dist-*/**" + ], "devDependencies": { "@tsconfig/recommended": "1.0.1", "concurrently": "7.0.0", diff --git a/scripts/runtime-dependency-version-check/package-json-enforcement.js b/scripts/runtime-dependency-version-check/package-json-enforcement.js index 584f39b8878c..d9bc06e6517d 100644 --- a/scripts/runtime-dependency-version-check/package-json-enforcement.js +++ b/scripts/runtime-dependency-version-check/package-json-enforcement.js @@ -55,6 +55,10 @@ module.exports = function (pkgJsonFilePath, overwrite = false) { errors.push(`browser and react-native fields are different in ${pkgJson.name}`); } + if (!pkgJson.files) { + errors.push(`no files entry in ${pkgJson.name}`); + } + if (typeof pkgJson.browser === "object" && typeof pkgJson["react-native"] === "object") { const browserCanonical = Object.entries(pkgJson.browser).reduce((acc, [k, v]) => { if (!k.includes("dist-cjs/") || typeof v === "boolean") { From 8711a1a23c7dcc5f2aa32e94776dc3bac51b8182 Mon Sep 17 00:00:00 2001 From: George Fu Date: Mon, 13 May 2024 20:41:20 +0000 Subject: [PATCH 9/9] chore(core): import submodules in core root index --- scripts/compilation/Inliner.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/compilation/Inliner.js b/scripts/compilation/Inliner.js index b65c39f566ed..589b35ec89da 100644 --- a/scripts/compilation/Inliner.js +++ b/scripts/compilation/Inliner.js @@ -167,7 +167,9 @@ module.exports = class Inliner { external: ["@smithy/*", "@aws-sdk/*", "node_modules/*", ...this.variantExternalsForEsBuild], }; - await esbuild.build(buildOptions); + if (!this.isCore) { + await esbuild.build(buildOptions); + } if (this.isCore) { const submodules = fs.readdirSync(path.join(root, this.subfolder, this.package, "src", "submodules"));