diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a1c0c00 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# EditorConfig is awesome: https://EditorConfig.org + +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..07ac76f --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,14 @@ +module.exports = { + overrides: [ + { + files: ['*.js', '*.jsx', '*.ts', '*.tsx'], + extends: 'standard-with-typescript', + parserOptions: { + project: './tsconfig.json' + }, + rules: { + '@typescript-eslint/strict-boolean-expressions': 'off' + } + } + ] +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 39724d7..76332f1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [18.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [14.x] + node-version: [18.x] steps: - uses: actions/checkout@v2 - name: Use Node.js ${{ matrix.node-version }} @@ -32,4 +32,4 @@ jobs: node-version: ${{ matrix.node-version }} - run: npm install - name: Run Standard.js linter - run: npm run standard + run: npm run lint diff --git a/.gitignore b/.gitignore index cab290e..2ae83b1 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ yarn-debug.log* yarn-error.log* lerna-debug.log* +package-lock.json +yarn.lock + # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json @@ -23,7 +26,8 @@ coverage *.lcov # nyc test coverage -.nyc_output +/.nyc_output +/coverage # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) .grunt @@ -42,7 +46,7 @@ node_modules/ jspm_packages/ # TypeScript v1 declaration files -typings/ +types/ # TypeScript cache *.tsbuildinfo @@ -80,7 +84,6 @@ typings/ # Nuxt.js build / generate output .nuxt -dist # Gatsby files .cache/ @@ -103,4 +106,13 @@ dist # TernJS port file .tern-port -package-lock.json +# Editor files +*~ +*.sw[nop] +/.vscode + +# Output +dist + +# MacOS +.DS_Store diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..8ead549 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 18.16.0 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ad9ac98..0000000 --- a/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: node_js -node_js: - - "12" - -sudo: false - -notifications: - email: - on_success: change - on_failure: change diff --git a/CHANGELOG.md b/CHANGELOG.md index e061946..4f2cfb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # did-web-driver ChangeLog +## 4.0.0 - +Note: API and usage should remain the same. + +### Changed +- **BREAKING**: Convert to Typescript. +- **BREAKING**: Switch back to Digital Bazaar's `http-client` fork. +- **BREAKING**: Use DCC `bnid` v3 (which uses base-x instead of base58-universal). + ## 3.0.1 - 2022-12-05 ### Changed diff --git a/build-dist.sh b/build-dist.sh deleted file mode 100755 index 740c486..0000000 --- a/build-dist.sh +++ /dev/null @@ -1,14 +0,0 @@ -mkdir ./dist/esm -cat >dist/esm/index.js <dist/esm/package.json <=12.0" + "node": ">=18.0" + }, + "standard": { + "globals": [ + "it" + ] } } diff --git a/rollup.config.js b/rollup.config.js deleted file mode 100644 index fa06c87..0000000 --- a/rollup.config.js +++ /dev/null @@ -1,15 +0,0 @@ -import pkg from './package.json' - -export default [ - { - input: './src/index.js', - output: [ - { - dir: 'dist', - format: 'cjs', - preserveModules: true - } - ], - external: Object.keys(pkg.dependencies).concat(['crypto', 'util']) - } -] diff --git a/src/DidWebResolver.js b/src/DidWebResolver.ts similarity index 82% rename from src/DidWebResolver.js rename to src/DidWebResolver.ts index 32a407a..cdaa995 100644 --- a/src/DidWebResolver.js +++ b/src/DidWebResolver.ts @@ -1,8 +1,9 @@ -import { httpClient } from '@digitalcredentials/http-client' +/* eslint-disable @typescript-eslint/strict-boolean-expressions */ +import { httpClient } from '@digitalbazaar/http-client' import * as didIo from '@digitalcredentials/did-io' -import ed25519Context from 'ed25519-signature-2020-context' -import x25519Context from 'x25519-key-agreement-2020-context' -import didContext from 'did-context' +import * as ed25519Context from 'ed25519-signature-2020-context' +import * as x25519Context from 'x25519-key-agreement-2020-context' +import * as didContext from 'did-context' import { decodeSecretKeySeed } from '@digitalcredentials/bnid' import { URL } from 'whatwg-url' @@ -16,7 +17,7 @@ const DEFAULT_KEY_MAP = { keyAgreement: 'X25519KeyAgreementKey2020' } -export function didFromUrl ({ url } = {}) { +export function didFromUrl ({ url }: { url?: string } = {}): string { if (!url) { throw new TypeError('Cannot convert url to did, missing url.') } @@ -37,11 +38,11 @@ export function didFromUrl ({ url } = {}) { const didJsonSuffix = '/did.json' const wellKnownSuffix = '/.well-known' - if (pathname && pathname.endsWith(didJsonSuffix)) { + if (pathname?.endsWith(didJsonSuffix)) { pathname = pathname.substring(0, pathname.length - didJsonSuffix.length) } - if (pathname && pathname.endsWith(wellKnownSuffix)) { + if (pathname?.endsWith(wellKnownSuffix)) { pathname = pathname.substring(0, pathname.length - wellKnownSuffix.length) } @@ -52,19 +53,16 @@ export function didFromUrl ({ url } = {}) { return 'did:web:' + encodeURIComponent(host) + pathComponent } -export function urlFromDid ({ did } = {}) { - if (!did) { - throw new TypeError('Cannot convert did to url, missing did.') - } - if (!did.startsWith('did:web:')) { - throw new TypeError(`DID Method not supported: "${did}".`) +export function urlFromDid ({ did }: { did: string | undefined }): string { + if (!did?.startsWith('did:web:')) { + throw new TypeError(`DID Method not supported: "${did ?? ''}".`) } const [didUrl, hashFragment] = did.split('#') // eslint-disable-next-line no-unused-vars // const [didResource, query] = didUrl.split('?') - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_did, _web, urlNoProtocol, ...pathFragments] = didUrl.split(':') if (urlNoProtocol.includes('/')) { @@ -119,8 +117,11 @@ export function urlFromDid ({ did } = {}) { * DID Document initialized with keys, as well as the map of the corresponding * key pairs (by key id). */ -export async function initKeys ({ didDocument, cryptoLd, keyMap } = {}) { - const doc = { ...didDocument } +export async function initKeys ( + { didDocument, cryptoLd, keyMap }: + { didDocument?: object, cryptoLd?: any, keyMap?: any } = {} +): Promise<{ didDocument: object, keyPairs: Map }> { + const doc: any = { ...didDocument } if (!doc.id) { throw new TypeError( 'DID Document "id" property is required to initialize keys.') @@ -155,13 +156,19 @@ export async function initKeys ({ didDocument, cryptoLd, keyMap } = {}) { } export class DidWebResolver { + public cryptoLd: any + public keyMap: object + public method: string + public logger: any + /** * @param cryptoLd {CryptoLD} * @param keyMap {object} * @param [logger] {object} Logger object (with .log, .error, .warn, * etc methods). */ - constructor ({ cryptoLd, keyMap = DEFAULT_KEY_MAP, logger = console } = {}) { + constructor ({ cryptoLd, keyMap = DEFAULT_KEY_MAP, logger = console }: + { cryptoLd?: any, keyMap?: object, logger?: any } = {}) { this.method = 'web' // did:web:... (used for didIo resolver harness) this.cryptoLd = cryptoLd this.keyMap = keyMap @@ -182,18 +189,23 @@ export class DidWebResolver { * Either an `id` or a `url` is required: * @param [id] {string} - A did:web DID. If absent, will be converted from url * @param [url] {string} + * @param [seed] {string|Uint8Array} * * @param [keyMap] {object} A hashmap of key types by purpose. * + * @param cryptoLd * @parma [cryptoLd] {object} CryptoLD instance with support for supported * crypto suites installed. * - * @returns {Promise<{didDocument: object, keyPairs: Map, + * @returns {Promise<{didDocument: object, keyPairs: object, * methodFor: Function}>} Resolves with the generated DID Document, along * with the corresponding key pairs used to generate it (for storage in a * KMS). */ - async generate ({ id, url, seed, keyMap, cryptoLd = this.cryptoLd } = {}) { + async generate ( + { id, url, seed, keyMap, cryptoLd = this.cryptoLd }: + { id?: string, url?: string, seed?: string | Uint8Array, keyMap?: any, cryptoLd?: any } = {}): + Promise<{ didDocument: any, keyPairs: object, methodFor: Function }> { if (!id && !url) { throw new TypeError('A "url" or an "id" parameter is required.') } @@ -203,7 +215,7 @@ export class DidWebResolver { ) } - const did = id || didFromUrl({ url }) + const did = id ?? didFromUrl({ url }) if (seed) { const keyPair = await _keyPairFromSecretSeed({ @@ -224,13 +236,13 @@ export class DidWebResolver { id: did } - const result = await initKeys({ didDocument, cryptoLd, keyMap }) + const result: any = await initKeys({ didDocument, cryptoLd, keyMap }) const keyPairs = result.keyPairs didDocument = result.didDocument // Convenience function that returns the public/private key pair instance // for a given purpose (authentication, assertionMethod, keyAgreement, etc). - const methodFor = ({ purpose }) => { + const methodFor = ({ purpose }: { purpose: string }): any => { const { id: methodId } = didIo.findVerificationMethod({ doc: didDocument, purpose }) @@ -258,8 +270,8 @@ export class DidWebResolver { * * @returns {Promise} Plain parsed JSON object of the DID Document. */ - async get ({ did, url, agent, logger = this.logger }) { - const didUrl = url || urlFromDid({ did }) + async get ({ did, url, agent, logger = this.logger }: { did?: string | undefined, url?: string | undefined, agent?: any, logger?: any }): Promise { + const didUrl = url ?? urlFromDid({ did }) if (!didUrl) { throw new TypeError('A DID or a URL is required.') } @@ -271,11 +283,12 @@ export class DidWebResolver { logger.info(`Fetching "${urlAuthority}" via http client.`) const result = await httpClient.get(urlAuthority, { agent }) didDocument = result.data - } catch (e) { + } catch (e: any) { // status is HTTP status code // data is JSON error from the server if available const { data, status } = e - logger.error(`Http ${status} error:`, data) + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + logger.error(`Http ${status ?? ''} error:`, data) throw e } if (didDocument && keyIdFragment) { @@ -319,14 +332,7 @@ export class DidWebResolver { * @returns {object} Returns the public key object (obtained from the DID * Document), without a `@context`. */ - publicMethodFor ({ didDocument, purpose } = {}) { - if (!didDocument) { - throw new TypeError('The "didDocument" parameter is required.') - } - if (!purpose) { - throw new TypeError('The "purpose" parameter is required.') - } - + publicMethodFor ({ didDocument, purpose }: { didDocument: any, purpose: string }): any { const method = didIo.findVerificationMethod({ doc: didDocument, purpose }) if (!method) { throw new Error(`No verification method found for purpose "${purpose}"`) @@ -343,7 +349,7 @@ export class DidWebResolver { * * @return {Promise} */ -async function _keyPairFromSecretSeed ({ seed, controller, cryptoLd } = {}) { +async function _keyPairFromSecretSeed ({ seed, controller, cryptoLd }: { seed: string | Uint8Array, controller?: string, cryptoLd?: any }): Promise { let seedBytes if (typeof seed === 'string') { // Currently only supports base58 multibase / identity multihash encoding. diff --git a/src/declarations.d.ts b/src/declarations.d.ts new file mode 100644 index 0000000..5b22a79 --- /dev/null +++ b/src/declarations.d.ts @@ -0,0 +1,11 @@ +declare module '@digitalbazaar/http-client' +declare module '@digitalcredentials/did-io' +declare module 'ed25519-signature-2020-context' +declare module 'x25519-key-agreement-2020-context' +declare module 'did-context' +declare module '@digitalcredentials/bnid' +declare module '@digitalcredentials/ed25519-verification-key-2020' +declare module '@digitalcredentials/x25519-key-agreement-key-2020' +declare module 'crypto-ld' +declare module 'whatwg-url' +declare module 'dirty-chai' diff --git a/src/index.js b/src/index.ts similarity index 55% rename from src/index.js rename to src/index.ts index 4d4f9bd..2a19c58 100644 --- a/src/index.js +++ b/src/index.ts @@ -1,7 +1,7 @@ -import { DidWebResolver, didFromUrl, urlFromDid } from './DidWebResolver.js' +import { DidWebResolver, didFromUrl, urlFromDid } from './DidWebResolver' -const driver = options => { +const driver = (options: { cryptoLd?: any, keyMap?: object | undefined, logger?: any } | undefined): DidWebResolver => { return new DidWebResolver(options) } diff --git a/test/unit/DidWebResolver.spec.js b/test/DidWebResolver.spec.ts similarity index 52% rename from test/unit/DidWebResolver.spec.js rename to test/DidWebResolver.spec.ts index d88fed4..c06cfa2 100644 --- a/test/unit/DidWebResolver.spec.js +++ b/test/DidWebResolver.spec.ts @@ -1,16 +1,13 @@ -import chai from 'chai' -import dirtyChai from 'dirty-chai' +/* eslint-disable @typescript-eslint/strict-boolean-expressions */ +import { assert } from 'chai' -import { DidWebResolver, urlFromDid, didFromUrl } from '../../src' +import { DidWebResolver, urlFromDid, didFromUrl } from '../src' import { Ed25519VerificationKey2020 } from '@digitalcredentials/ed25519-verification-key-2020' import { X25519KeyAgreementKey2020 } from '@digitalcredentials/x25519-key-agreement-key-2020' import { CryptoLD } from 'crypto-ld' -chai.use(dirtyChai) -chai.should() -const { expect } = chai const cryptoLd = new CryptoLD() cryptoLd.use(Ed25519VerificationKey2020) @@ -19,7 +16,7 @@ cryptoLd.use(X25519KeyAgreementKey2020) describe('DidWebDriver', () => { describe('constructor', () => { it('should exist', () => { - expect(new DidWebResolver()).to.exist() + assert(new DidWebResolver()) }) }) @@ -33,12 +30,12 @@ describe('DidWebDriver', () => { didDocument, purpose: 'keyAgreement' }) - expect(keyAgreementKey.type).to.equal('X25519KeyAgreementKey2020') + assert.equal(keyAgreementKey.type, 'X25519KeyAgreementKey2020') }) }) describe('generate()', () => { - let didWeb + let didWeb: DidWebResolver beforeEach(async () => { didWeb = new DidWebResolver({ cryptoLd }) @@ -48,18 +45,14 @@ describe('DidWebDriver', () => { const url = 'https://example.com' const { didDocument, keyPairs } = await didWeb.generate({ url }) - expect(didDocument).to.have.property('@context') - expect(didDocument.id).to.equal('did:web:example.com') - expect(didDocument.capabilityInvocation[0].type) - .to.equal('Ed25519VerificationKey2020') - expect(didDocument.authentication[0].type) - .to.equal('Ed25519VerificationKey2020') - expect(didDocument.assertionMethod[0].type) - .to.equal('Ed25519VerificationKey2020') - expect(didDocument.capabilityDelegation[0].type) - .to.equal('Ed25519VerificationKey2020') + assert.property(didDocument, '@context') + assert.equal(didDocument.id, 'did:web:example.com') + assert.equal(didDocument.capabilityInvocation[0].type, 'Ed25519VerificationKey2020') + assert.equal(didDocument.authentication[0].type, 'Ed25519VerificationKey2020') + assert.equal(didDocument.assertionMethod[0].type, 'Ed25519VerificationKey2020') + assert.equal(didDocument.capabilityDelegation[0].type, 'Ed25519VerificationKey2020') - expect(keyPairs).to.exist() + assert(keyPairs) }) it('should return methodFor convenience function', async () => { @@ -68,10 +61,10 @@ describe('DidWebDriver', () => { const keyAgreementKey = methodFor({ purpose: 'keyAgreement' }) - expect(keyAgreementKey).to.have.property('type', 'X25519KeyAgreementKey2020') - expect(keyAgreementKey).to.have.property('controller', 'did:web:example.com') - expect(keyAgreementKey).to.have.property('publicKeyMultibase') - expect(keyAgreementKey).to.have.property('privateKeyMultibase') + assert.property(keyAgreementKey, 'type', 'X25519KeyAgreementKey2020') + assert.property(keyAgreementKey, 'controller', 'did:web:example.com') + assert.property(keyAgreementKey, 'publicKeyMultibase') + assert.property(keyAgreementKey, 'privateKeyMultibase') }) it('should generate from seed', async () => { @@ -79,37 +72,26 @@ describe('DidWebDriver', () => { const url = 'https://example.com' const { didDocument, methodFor } = await didWeb.generate({ url, seed }) - expect(didDocument).to.have.property('id', 'did:web:example.com') + assert.property(didDocument, 'id', 'did:web:example.com') const assertionKey = methodFor({ purpose: 'assertionMethod' }) - expect(assertionKey).to.have.property('id', 'did:web:example.com#z6MkmDMjfkjs9XPCN1LfoQQRHz1mJ8PEdiVYC66XKhj3wGyB') - expect(assertionKey).to.have.property('type', 'Ed25519VerificationKey2020') - expect(assertionKey).to.have.property('controller', 'did:web:example.com') - expect(assertionKey).to.have.property('publicKeyMultibase', 'z6MkmDMjfkjs9XPCN1LfoQQRHz1mJ8PEdiVYC66XKhj3wGyB') - expect(assertionKey).to.have.property('privateKeyMultibase') + assert.property(assertionKey, 'id', 'did:web:example.com#z6MkmDMjfkjs9XPCN1LfoQQRHz1mJ8PEdiVYC66XKhj3wGyB') + assert.property(assertionKey, 'type', 'Ed25519VerificationKey2020') + assert.property(assertionKey, 'controller', 'did:web:example.com') + assert.property(assertionKey, 'publicKeyMultibase', 'z6MkmDMjfkjs9XPCN1LfoQQRHz1mJ8PEdiVYC66XKhj3wGyB') + assert.property(assertionKey, 'privateKeyMultibase') }) }) describe('urlFromDid()', () => { - it('should error on missing did', () => { - let error - try { - urlFromDid() - } catch (e) { - error = e - } - expect(error.message).to.equal('Cannot convert did to url, missing did.') - }) - it('should error on non-did:web dids', () => { let error try { urlFromDid({ did: 'did:example:1234' }) - } catch (e) { + } catch (e: any) { error = e } - expect(error.message) - .to.equal('DID Method not supported: "did:example:1234".') + assert.equal(error.message, 'DID Method not supported: "did:example:1234".') }) it('should error on pattern did:web:domain/path/subpath', () => { @@ -124,53 +106,50 @@ describe('DidWebDriver', () => { let error try { urlFromDid({ did }) - } catch (e) { + } catch (e: any) { error = e } if (error) { - expect(error.message) - .to.contain('domain-name cannot contain a path.') + assert.include(error.message, 'domain-name cannot contain a path.') } else { - expect.fail('should have thrown error for did: ' + did) + assert.fail('should have thrown error for did: ' + did) } }) }) it('should convert first id fragment to pathname plus default path', () => { - expect(urlFromDid({ did: 'did:web:example.com' })) - .to.equal('https://example.com/.well-known/did.json') + assert.equal(urlFromDid({ did: 'did:web:example.com' }), 'https://example.com/.well-known/did.json') }) it('should url-decode host', () => { - expect(urlFromDid({ did: 'did:web:localhost%3A8080' })) - .to.equal('https://localhost:8080/.well-known/did.json') + assert.equal(urlFromDid({ did: 'did:web:localhost%3A8080' }), 'https://localhost:8080/.well-known/did.json') }) it('should preserve hash fragments for dids without paths', () => { const url = urlFromDid({ did: 'did:web:localhost%3A8080#keyId' }) - expect(url).to.equal('https://localhost:8080/.well-known/did.json#keyId') + assert.equal(url, 'https://localhost:8080/.well-known/did.json#keyId') }) // See: https://w3c-ccg.github.io/did-method-web/#example-creating-the-did-with-optional-path it('should work with optional path', () => { const url = urlFromDid({ did: 'did:web:w3c-ccg.github.io:user:alice' }) - expect(url).to.equal('https://w3c-ccg.github.io/user/alice/did.json') + assert.equal(url, 'https://w3c-ccg.github.io/user/alice/did.json') }) // See: https://w3c-ccg.github.io/did-method-web/#example-creating-the-did-with-optional-path-and-port it('should work with optional path and port', () => { const url = urlFromDid({ did: 'did:web:example.com%3A3000:user:alice' }) - expect(url).to.equal('https://example.com:3000/user/alice/did.json') + assert.equal(url, 'https://example.com:3000/user/alice/did.json') }) it('should preserve hash fragments for dids with optional path', () => { const url = urlFromDid({ did: 'did:web:w3c-ccg.github.io:user:alice#keyId' }) - expect(url).to.equal('https://w3c-ccg.github.io/user/alice/did.json#keyId') + assert.equal(url, 'https://w3c-ccg.github.io/user/alice/did.json#keyId') }) it('should preserve hash fragments for dids with optional path and port', () => { const url = urlFromDid({ did: 'did:web:example.com%3A3000:user:alice#keyId' }) - expect(url).to.equal('https://example.com:3000/user/alice/did.json#keyId') + assert.equal(url, 'https://example.com:3000/user/alice/did.json#keyId') }) }) @@ -179,62 +158,55 @@ describe('DidWebDriver', () => { let error try { didFromUrl() - } catch (e) { + } catch (e: any) { error = e } - expect(error.message).to.equal('Cannot convert url to did, missing url.') + assert.equal(error.message, 'Cannot convert url to did, missing url.') }) it('should error on http URLs', () => { let error try { didFromUrl({ url: 'http://example.com' }) - } catch (e) { + } catch (e: any) { error = e } - expect(error.message).to.equal('did:web does not support non-HTTPS URLs.') + assert.equal(error.message, 'did:web does not support non-HTTPS URLs.') }) it('should error on invalid URLs', () => { let error try { didFromUrl({ url: 'non-url' }) - } catch (e) { + } catch (e: any) { error = e } - expect(error.message).to.equal('Invalid url: "non-url".') + assert.equal(error.message, 'Invalid url: "non-url".') }) it('should convert host to did identifier', () => { - expect(didFromUrl({ url: 'https://localhost' })) - .to.equal('did:web:localhost') - expect(didFromUrl({ url: 'https://example.com' })) - .to.equal('did:web:example.com') + assert.equal(didFromUrl({ url: 'https://localhost' }), 'did:web:localhost') + assert.equal(didFromUrl({ url: 'https://example.com' }), 'did:web:example.com') }) it('should url-encode host', () => { - expect(didFromUrl({ url: 'https://localhost:8080' })) - .to.equal('did:web:localhost%3A8080') + assert.equal(didFromUrl({ url: 'https://localhost:8080' }), 'did:web:localhost%3A8080') }) it('should leave off the default / path', () => { - expect(didFromUrl({ url: 'https://example.com/' })) - .to.equal('did:web:example.com') + assert.equal(didFromUrl({ url: 'https://example.com/' }), 'did:web:example.com') }) it('should encode path / separators as :', () => { - expect(didFromUrl({ url: 'https://example.com/path/subpath/did.json' })) - .to.equal('did:web:example.com:path:subpath') + assert.equal(didFromUrl({ url: 'https://example.com/path/subpath/did.json' }), 'did:web:example.com:path:subpath') }) it('should drop the default /.well-known/did.json pathname', () => { - expect(didFromUrl({ url: 'https://example.com/.well-known/did.json' })) - .to.equal('did:web:example.com') + assert.equal(didFromUrl({ url: 'https://example.com/.well-known/did.json' }), 'did:web:example.com') }) it('should url-encode path fragments', () => { - expect(didFromUrl({ url: 'https://example.com/path/some+subpath' })) - .to.equal('did:web:example.com:path:some%2Bsubpath') + assert.equal(didFromUrl({ url: 'https://example.com/path/some+subpath' }), 'did:web:example.com:path:some%2Bsubpath') }) }) }) diff --git a/test/karma.conf.js b/test/karma.conf.js deleted file mode 100644 index 2e68a43..0000000 --- a/test/karma.conf.js +++ /dev/null @@ -1,40 +0,0 @@ -module.exports = (config) => { - const bundler = process.env.BUNDLER || 'webpack' - const frameworks = ['mocha'] - const files = ['**/*.spec.js'] - const reporters = ['mocha'] - const browsers = ['ChromeHeadless'] - const client = { - mocha: { - timeout: 2000 - } - } - // main bundle preprocessors - const preprocessors = [] - preprocessors.push(bundler) - preprocessors.push('sourcemap') - - return config.set({ - frameworks, - files, - reporters, - basePath: '', - port: 9876, - colors: true, - browsers, - client, - singleRun: true, - preprocessors: { - 'unit/*.js': preprocessors - }, - webpack: { - devtool: 'inline-source-map', - mode: 'development', - node: { - Buffer: false, - crypto: false, - setImmediate: false - } - } - }) -} diff --git a/tsconfig.esm.json b/tsconfig.esm.json new file mode 100644 index 0000000..be48886 --- /dev/null +++ b/tsconfig.esm.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es2022", + "lib": ["es2022", "dom"], + "module": "es6", + "moduleResolution": "node", + "outDir": "dist/esm", + "sourceMap": true, + "declaration": true, + "declarationMap": true, + "noImplicitAny": true, + "removeComments": false, + "preserveConstEnums": true, + "baseUrl": ".", + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "resolveJsonModule": true + }, + "ts-node": { + "files": true + }, + "include": [ + "src/**/*", + ".eslintrc.js", + "karma.conf.js" + ], + "exclude": ["node_modules", "dist"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e992e83 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es2022", + "lib": ["es2022", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist/", + "sourceMap": true, + "declaration": false, + "noImplicitAny": true, + "removeComments": false, + "preserveConstEnums": true, + "baseUrl": ".", + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "skipDefaultLibCheck": true, + "resolveJsonModule": true + }, + "ts-node": { + "files": true + }, + "include": [ + "src/**/*", + "test/**/*", + ".eslintrc.cjs", + "karma.conf.js" + ], + "exclude": ["node_modules", "dist"] +} diff --git a/tsconfig.spec.json b/tsconfig.spec.json new file mode 100644 index 0000000..5bf0e78 --- /dev/null +++ b/tsconfig.spec.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "strict": true, + "target": "es2022", + "lib": ["es2022", "dom"], + "module": "commonjs", + "moduleResolution": "node", + "outDir": "dist/esm", + "noImplicitAny": true, + "removeComments": false, + "preserveConstEnums": true, + "baseUrl": ".", + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "resolveJsonModule": true + }, + "ts-node": { + "files": true + }, + "include": [ + "src/**/*", + "test/**/*.spec.ts", + ".eslintrc.js", + "karma.conf.js" + ], + "exclude": ["node_modules", "dist"] +}