What is the Problem Being Solved?
Deep imports are import statements that reach deeper than the entry module for a package. For example, import { E, Far } from "@endo/far" is a shallow import and import "@endo/lockdown/commit-debug.js" is a deep import.
Agoric makes extensive use of deep imports that even reach into the src subdirectory of a package, as in "@agoric/zoe/src/contractSupport/index.js". We otherwise prefer to avoid deep imports that reach into the src tree, since the layout under src should not be a public API. Elsewhere, we’ve settled on a pattern where deep imports can occur but are limited to being in the top-level of the package, like "@endo/lockdown/commit.js" or "@endo/base64/encode.js".
Node 16+ and Endo respect the "exports" property in package.json which expresses the entirely of the importable surface of the package and forbids all other deep imports. To maintain a compatibility bridge between older versions of Node.js and tools that do not yet recognize the existence of "exports" we arrived at a pattern of use where we would only use "exports" entries with identical keys and values. We also learned that some tools need an entry for "package.json".
{
"main": "./src/index.js",
"exports": {
".": "./src/index.js",
"./package.json": "./package.json"
}
}
We have made some regrettable design choices for the naming of deep imports up to this point, but to maintain backward compatibility, we need to preserve working import expressions.
Description of the Design
To that end, I propose that we introduce an "exports" directive to every public package of Agoric SDK and populate it with an entry for every existing use of a deep import. For example:
{
"name": "zoe",
"exports": {
"./src/contractSupport/index.js": "./src/contractSupport/index.js",
"./package.json": "./package.json"
}
}
Making these entry-points explicit will prevent future unintended creep of the public API of our packages. Then, we can being the process of normalizing our design philosophy for intentional package exports.
For example, we can then add a top-level contract-support.js to @agoric/zoe:
export * from './src/contractSupport/index.js';
And make this alias public for all future use:
{
"name": "zoe",
"exports": {
"./contract-support.js": "./contract-support.js",
"./src/contractSupport/index.js": "./src/contractSupport/index.js",
"./package.json": "./package.json"
}
}
Security Considerations
Scaling Considerations
Test Plan
Upgrade Considerations
What is the Problem Being Solved?
Deep imports are
importstatements that reach deeper than the entry module for a package. For example,import { E, Far } from "@endo/far"is a shallow import andimport "@endo/lockdown/commit-debug.js"is a deep import.Agoric makes extensive use of deep imports that even reach into the
srcsubdirectory of a package, as in"@agoric/zoe/src/contractSupport/index.js". We otherwise prefer to avoid deep imports that reach into thesrctree, since the layout undersrcshould not be a public API. Elsewhere, we’ve settled on a pattern where deep imports can occur but are limited to being in the top-level of the package, like"@endo/lockdown/commit.js"or"@endo/base64/encode.js".Node 16+ and Endo respect the
"exports"property inpackage.jsonwhich expresses the entirely of the importable surface of the package and forbids all other deep imports. To maintain a compatibility bridge between older versions of Node.js and tools that do not yet recognize the existence of"exports"we arrived at a pattern of use where we would only use"exports"entries with identical keys and values. We also learned that some tools need an entry for"package.json".{ "main": "./src/index.js", "exports": { ".": "./src/index.js", "./package.json": "./package.json" } }We have made some regrettable design choices for the naming of deep imports up to this point, but to maintain backward compatibility, we need to preserve working import expressions.
Description of the Design
To that end, I propose that we introduce an
"exports"directive to every public package of Agoric SDK and populate it with an entry for every existing use of a deep import. For example:{ "name": "zoe", "exports": { "./src/contractSupport/index.js": "./src/contractSupport/index.js", "./package.json": "./package.json" } }Making these entry-points explicit will prevent future unintended creep of the public API of our packages. Then, we can being the process of normalizing our design philosophy for intentional package exports.
For example, we can then add a top-level
contract-support.jsto@agoric/zoe:And make this alias public for all future use:
{ "name": "zoe", "exports": { "./contract-support.js": "./contract-support.js", "./src/contractSupport/index.js": "./src/contractSupport/index.js", "./package.json": "./package.json" } }Security Considerations
Scaling Considerations
Test Plan
Upgrade Considerations