feat(base64)!: Update packaging, expose encode/decode entry modules, bridge RESM/NESM
BREAKING CHANGE: No longer supports direct use from CommonJS
MODIFY
packages/base64/NEWS.md
packages/base64/NEWS.md
@@ -2,6 +2,14 @@ User-visible changes in base64:
## Next release
+* *BREAKING*: Removes CommonJS and UMD downgrade compatibility.
+ Supporting both Node.js ESM and the `node -r esm` shim requires the main
+ entry point module to be ESM regardless of environment.
+ UMD and CommonJS facets will likely return after all dependees have migrated
+ away from depending upon the `esm` JavaScript module emulator.
+* Separates entry points for `@endo/base64/encode.js` and
+ `@endo/base64/decode.js`, in addition to the combined entry point at
+ `@endo/base64`.
* Expose internal `package.json` through Node.js ESM `exports` for the benefit
of `svelte` tooling.

ADD
packages/base64/decode.js
+export { decodeBase64 } from './src/decode.js';

ADD
packages/base64/encode.js
+export { encodeBase64 } from './src/encode.js';

ADD
packages/base64/index.d.ts
+export { encodeBase64, decodeBase64 } from './index.js';

ADD
packages/base64/index.js
+export { encodeBase64 } from './src/encode.js';
+export { decodeBase64 } from './src/decode.js';

ADD
packages/base64/jsconfig.json
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "noEmit": true,
+ "downlevelIteration": true,
+ "strictNullChecks": true,
+ "moduleResolution": "node"
+ },
+ "include": ["src/**/*.js", "index.d.ts"]
+}

MODIFY
packages/base64/package.json
packages/base64/package.json
"name": "@endo/base64",
"version": "0.1.0+1-dev",
"description": "Transcodes base64",
- "author": "Agoric",
+ "keywords": ["base64", "endo", "ses"],
+ "author": "Endo contributors",
"license": "Apache-2.0",
- "type": "module",
- "parsers": {
- "js": "mjs"
+ "homepage": "https://github.com/endojs/endo/tree/master/packages/base64#readme",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/endojs/endo.git"
+ },
+ "bugs": {
+ "url": "https://github.com/endojs/endo/issues"
},
+ "type": "module",
"main": "./dist/base64.cjs",
- "module": "./src/main.js",
+ "module": "./index.js",
"browser": "./dist/base64.umd.js",
"unpkg": "./dist/base64.umd.js",
- "types": "./types/main.d.ts",
+ "types": "./index.d.ts",
"exports": {
- "./package.json": "./package.json",
- ".": {
- "import": "./src/main.js",
- "require": "./dist/base64.cjs",
- "browser": "./dist/base64.umd.js"
- }
+ ".": "./index.js",
+ "./encode.js": "./encode.js",
+ "./decode.js": "./decode.js",
+ "./package.json": "./package.json"
},
"scripts": {
- "build": "yarn build:types && yarn build:dist",
- "build:dist": "rollup --config rollup.config.js",
- "build:types": "tsc src/*.js --declaration --allowJs --emitDeclarationOnly --outDir types",
- "clean": "rm -rf dist",
- "cover": "nyc ava",
- "lint": "eslint '**/*.js'",
+ "build": "exit 0",
+ "lint": "yarn lint:types && yarn lint:js",
"lint-fix": "eslint --fix '**/*.js'",
- "prepublish": "yarn clean && yarn build",
+ "lint:js": "eslint '**/*.js'",
+ "lint:types": "tsc --build jsconfig.json",
"test": "ava"
},
"dependencies": {},
"devDependencies": {
"@agoric/eslint-config": "^0.3.6",
- "@rollup/plugin-commonjs": "^13.0.0",
- "@rollup/plugin-node-resolve": "^6.1.0",
+ "@agoric/eslint-plugin": "^0.3.2",
"ava": "^3.12.1",
"babel-eslint": "^10.0.3",
"eslint": "^7.23.0",
"eslint-plugin-eslint-comments": "^3.1.2",
"eslint-plugin-import": "^2.19.1",
"eslint-plugin-prettier": "^3.1.2",
- "nyc": "^15.1.0",
"prettier": "^1.19.1",
- "rollup": "1.31.0",
- "rollup-plugin-terser": "^5.1.3",
"typescript": "^4.0.5"
},
"files": [
"LICENSE*",
- "dist",
- "src",
- "types"
+ "decode.js",
+ "encode.js",
+ "index.d.ts",
+ "index.js",
+ "src"
],
"publishConfig": {
"access": "public"

DELETE
packages/base64/rollup.config.js
-import resolve from '@rollup/plugin-node-resolve';
-import commonjs from '@rollup/plugin-commonjs';
-import { terser } from 'rollup-plugin-terser';
-import fs from 'fs';
-
-const metaPath = new URL('package.json', import.meta.url).pathname;
-const meta = JSON.parse(fs.readFileSync(metaPath, 'utf-8'));
-const name = meta.name.split('/').pop();
-const umd = meta.umd || name;
-
-export default [
- {
- input: 'src/main.js',
- output: [
- {
- file: `dist/${name}.mjs`,
- format: 'esm',
- },
- {
- file: `dist/${name}.cjs`,
- format: 'cjs',
- },
- ],
- plugins: [resolve(), commonjs()],
- },
- {
- input: 'src/main.js',
- output: {
- file: `dist/${name}.umd.js`,
- format: 'umd',
- name: umd,
- },
- plugins: [resolve(), commonjs()],
- },
- {
- input: 'src/main.js',
- output: {
- file: `dist/${name}.umd.min.js`,
- format: 'umd',
- name: umd,
- },
- plugins: [resolve(), commonjs(), terser()],
- },
-];

ADD
packages/base64/src/common.js
+// @ts-check
+
+export const padding = '=';
+
+export const alphabet64 =
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+/**
+ * The numeric value corresponding to each letter of the alphabet.
+ * If an alphabet is named for the Greek letters alpha and beta, then clearly a
+ * monodu is named for the corresponding Greek numbers mono and duo.
+ *
+ * @type {Record<string, number>}
+ */
+export const monodu64 = {};
+for (let i = 0; i < alphabet64.length; i += 1) {
+ const c = alphabet64[i];
+ monodu64[c] = i;
+}

ADD
packages/base64/src/decode.js
+// @ts-check
+/* eslint no-bitwise: ["off"] */
+
+import { monodu64, padding } from './common.js';
+
+/**
+ * Decodes a Base64 string into bytes, as specified in
+ * https://tools.ietf.org/html/rfc4648#section-4
+ *
+ * @param {string} string Base64-encoded string
+ * @param {string} [name] The name of the string as it will appear in error
+ * messages.
+ * @returns {Uint8Array} decoded bytes
+ */
+export function decodeBase64(string, name = '<unknowwn>') {
+ const data = new Uint8Array(Math.ceil((string.length * 4) / 3));
+ let register = 0;
+ let quantum = 0;
+ let i = 0; // index in string
+ let j = 0; // index in data
+
+ while (i < string.length && string[i] !== padding) {
+ const number = monodu64[string[i]];
+ if (number === undefined) {
+ throw Error(`Invalid base64 character ${string[i]} in string ${name}`);
+ }
+ register = (register << 6) | number;
+ quantum += 6;
+ if (quantum >= 8) {
+ quantum -= 8;
+ data[j] = register >>> quantum;
+ j += 1;
+ register &= (1 << quantum) - 1;
+ }
+ i += 1;
+ }
+
+ while (i < string.length && quantum % 8 !== 0) {
+ if (string[i] !== padding) {
+ throw Error(`Missing padding at offset ${i} of string ${name}`);
+ }
+ i += 1;
+ quantum += 6;
+ }
+
+ if (i < string.length) {
+ throw Error(
+ `Base64 string has trailing garbage ${string.substr(
+ i,
+ )} in string ${name}`,
+ );
+ }
+
+ return data.subarray(0, j);
+}

ADD
packages/base64/src/encode.js
+// @ts-check
+/* eslint no-bitwise: ["off"] */
+
+import { alphabet64, padding } from './common.js';
+
+/**
+ * Encodes bytes into a Base64 string, as specified in
+ * https://tools.ietf.org/html/rfc4648#section-4
+ *
+ * @param {Uint8Array} data
+ * @returns {string} base64 encoding
+ */
+export function encodeBase64(data) {
+ // A cursory benchmark shows that string concatenation is about 25% faster
+ // than building an array and joining it in v8, in 2020, for strings of about
+ // 100 long.
+ let string = '';
+ let register = 0;
+ let quantum = 0;
+
+ for (let i = 0; i < data.length; i += 1) {
+ const b = data[i];
+ register = (register << 8) | b;
+ quantum += 8;
+ if (quantum === 24) {
+ string +=
+ alphabet64[(register >>> 18) & 0x3f] +
+ alphabet64[(register >>> 12) & 0x3f] +
+ alphabet64[(register >>> 6) & 0x3f] +
+ alphabet64[(register >>> 0) & 0x3f];
+ register = 0;
+ quantum = 0;
+ }
+ }
+
+ switch (quantum) {
+ case 0:
+ break;
+ case 8:
+ string +=
+ alphabet64[(register >>> 2) & 0x3f] +
+ alphabet64[(register << 4) & 0x3f] +
+ padding +
+ padding;
+ break;
+ case 16:
+ string +=
+ alphabet64[(register >>> 10) & 0x3f] +
+ alphabet64[(register >>> 4) & 0x3f] +
+ alphabet64[(register << 2) & 0x3f] +
+ padding;
+ break;
+ default:
+ throw Error(`internal: bad quantum ${quantum}`);
+ }
+ return string;
+}

DELETE
packages/base64/src/main.js
-/* eslint no-bitwise: ["off"] */
-// @ts-check
-
-const padding = '=';
-
-const alphabet64 =
- 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
-
-/**
- * The numeric value corresponding to each letter of the alphabet.
- * If an alphabet is named for the Greek letters alpha and beta, then clearly a
- * monodu is named for the corresponding Greek numbers mono and duo.
- *
- * @type {Record<string, number>}
- */
-const monodu64 = {};
-for (let i = 0; i < alphabet64.length; i += 1) {
- const c = alphabet64[i];
- monodu64[c] = i;
-}
-
-/**
- * Encodes bytes into a Base64 string, as specified in
- * https://tools.ietf.org/html/rfc4648#section-4
- *
- * @param {Uint8Array} data
- * @returns {string} base64 encoding
- */
-export function encodeBase64(data) {
- // A cursory benchmark shows that string concatenation is about 25% faster
- // than building an array and joining it in v8, in 2020, for strings of about
- // 100 long.
- let string = '';
- let register = 0;
- let quantum = 0;
-
- for (let i = 0; i < data.length; i += 1) {
- const b = data[i];
- register = (register << 8) | b;
- quantum += 8;
- if (quantum === 24) {
- string +=
- alphabet64[(register >>> 18) & 0x3f] +
- alphabet64[(register >>> 12) & 0x3f] +
- alphabet64[(register >>> 6) & 0x3f] +
- alphabet64[(register >>> 0) & 0x3f];
- register = 0;
- quantum = 0;
- }
- }
-
- switch (quantum) {
- case 0:
- break;
- case 8:
- string +=
- alphabet64[(register >>> 2) & 0x3f] +
- alphabet64[(register << 4) & 0x3f] +
- padding +
- padding;
- break;
- case 16:
- string +=
- alphabet64[(register >>> 10) & 0x3f] +
- alphabet64[(register >>> 4) & 0x3f] +
- alphabet64[(register << 2) & 0x3f] +
- padding;
- break;
- default:
- throw Error(`internal: bad quantum ${quantum}`);
- }
- return string;
-}
-
-/**
- * Decodes a Base64 string into bytes, as specified in
- * https://tools.ietf.org/html/rfc4648#section-4
- *
- * @param {string} string Base64-encoded string
- * @param {string} [name] The name of the string as it will appear in error
- * messages.
- * @returns {Uint8Array} decoded bytes
- */
-export function decodeBase64(string, name = '<unknowwn>') {
- const data = new Uint8Array(Math.ceil((string.length * 4) / 3));
- let register = 0;
- let quantum = 0;
- let i = 0; // index in string
- let j = 0; // index in data
-
- while (i < string.length && string[i] !== padding) {
- const number = monodu64[string[i]];
- if (number === undefined) {
- throw Error(`Invalid base64 character ${string[i]} in string ${name}`);
- }
- register = (register << 6) | number;
- quantum += 6;
- if (quantum >= 8) {
- quantum -= 8;
- data[j] = register >>> quantum;
- j += 1;
- register &= (1 << quantum) - 1;
- }
- i += 1;
- }
-
- while (i < string.length && quantum % 8 !== 0) {
- if (string[i] !== padding) {
- throw Error(`Missing padding at offset ${i} of string ${name}`);
- }
- i += 1;
- quantum += 6;
- }
-
- if (i < string.length) {
- throw Error(
- `Base64 string has trailing garbage ${string.substr(
- i,
- )} in string ${name}`,
- );
- }
-
- return data.subarray(0, j);
-}

MODIFY
packages/base64/test/bench-main.js
packages/base64/test/bench-main.js
// syscall, by exponentially probing for the number of operations that can be
// executed within each benchmark's deadline.
-import { encodeBase64, decodeBase64 } from '../src/main.js';
+import { encodeBase64, decodeBase64 } from '../index.js';
const timeout = 1000; // ms

MODIFY
packages/base64/test/test-main.js
packages/base64/test/test-main.js
import test from 'ava';
-import { encodeBase64, decodeBase64 } from '../src/main.js';
+import { encodeBase64, decodeBase64 } from '../index.js';
function stringToBytes(string) {
const data = new Uint8Array(string.length);

feat(base64)!: Update packaging, expose encode/decode entry modules, bridge RESM/NESM

BREAKING CHANGE: No longer supports direct use from CommonJS