diff --git a/.github/workflows/audit-pending-releases.yml b/.github/workflows/audit-pending-releases.yml new file mode 100644 index 000000000..d8bd1c658 --- /dev/null +++ b/.github/workflows/audit-pending-releases.yml @@ -0,0 +1,49 @@ +on: + push: + branches: + - 'release-please**' + +env: + CORE_PACKAGE: core + +name: Audit Pending Releases +jobs: + npm-release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.ref }} + + # if this is an SDK release, make sure there's no pending releases for @openfeature/core + - name: Check for Pending Dependency PRs + if: ${{ !endsWith(github.ref_name, env.CORE_PACKAGE) }} + run: | + if [ $(gh pr list --search '"release ${{ env.CORE_PACKAGE }}" in:title' | wc -l) -gt 0 ]; \ + then echo "Pending @openfeaure/${{ env.CORE_PACKAGE }} release. Please release @openfeaure/${{ env.CORE_PACKAGE }} first!" && exit 1; \ + else echo "No pending @openfeaure/${{ env.CORE_PACKAGE }} releases"; \ + fi + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 16 + registry-url: "https://registry.npmjs.org" + cache: 'npm' + + # if this is an @openfeature/core release, but the SDKs to use this version as a peer, and commit back + - name: Update Peer Version in Dependants + if: ${{ endsWith(github.ref_name, env.CORE_PACKAGE) }} + run: | + npm run update-core-peers && \ + ! git diff-files --quiet && \ + ( echo 'Updated peer dependency in dependants, commiting...' + git add --all && \ + git config user.name "openfeature-peer-update-bot" && \ + git config user.email "openfeature-peer-update-bot@openfeature.dev" && \ + git commit -m 'chore: bump @openfeaure/${{ env.CORE_PACKAGE }} peer' -s && \ + git push ) || echo 'Peer dependency in dependants is already up to date.' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pr-checks.yaml b/.github/workflows/pr-checks.yaml index b46960a9e..69d53fa9a 100644 --- a/.github/workflows/pr-checks.yaml +++ b/.github/workflows/pr-checks.yaml @@ -53,6 +53,9 @@ jobs: - name: Install run: npm ci + - name: Install + run: npm run build + - name: Docs run: npm run docs diff --git a/.github/workflows/publish-experimental.yml b/.github/workflows/publish-experimental.yml deleted file mode 100644 index 7567c5d51..000000000 --- a/.github/workflows/publish-experimental.yml +++ /dev/null @@ -1,40 +0,0 @@ -# Publishes a experimental version if a PR comment includes "/publish". - -name: publish-experimental - -on: - issue_comment: - types: - - created - -jobs: - publish-experimental: - if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/publish') }} - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - registry-url: 'https://registry.npmjs.org' - - # the issue_comment event doesn't contain the ref of the PR in question. The build-in "hub" command can get it based on issue number - - name: Checkout Pull Request - run: hub pr checkout ${{ github.event.issue.number }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Install - run: npm ci - - - name: Build - run: npm run build - - # create an experimental version at this SHA, with minor incremented (vX.X+1.X-experimental-4742ef14cc0ea07e3569eee56899937452a55a9c) - - name: Version - run: npm version minor --no-git-tag-version && npm version "$(npm run current-version -s)-experimental-$(git rev-parse HEAD)" --no-git-tag-version - - - name: Publish - run: npm publish --tag experimental --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7214ea3cf..1d7335586 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,10 @@ We value having as few runtime dependencies as possible. The addition of any dep ### Modules This repository uses [NPM workspaces](https://docs.npmjs.com/cli/v9/using-npm/workspaces) to establish a simple monorepo. -Within the root project, there is one common project (`packages/shared`) which features common interfaces and code, consumed by the published modules (`packages/server` and `packages/client`). The shared module is bundled transparently into the published modules - it is not published itself. Changes in `packages/shared` will result in releases of the dependant modules via Release Please. +Within the root project, there is one common project (`packages/shared`) which features common interfaces and code, consumed by the published modules (`packages/server` and `packages/client`). +The shared module is built and published separately, and is a peer dependency of the SDK packages. +Consumers need not install it separately, since `npm` and `yarn` automatically install required peers. +In order to prevent regressions cause by incompatibilities due to version mismatches, the SDKs are locked to a particular version of the `@openfeature/core` module, and the CI enforces that it's released before any dependant SDKs (see [the related workflow](./.github/workflows/audit-pending-releases.yml)). ### Testing @@ -45,8 +48,6 @@ for the client e2e tests. Both ES modules and CommonJS modules are supported, so consumers can use both `require` and `import` functions to utilize this module. This is accomplished by building 2 variations of the output, under `dist/esm` and `dist/cjs`, respectively. To force resolution of the `dist/esm/**.js*` files as modules, a package json with only the context `{"type": "module"}` is included at a in a `postbuild` step. Type declarations are included at `/dist/types/` -For testing purposes, you can add a comment containing "/publish" in any PR. This will publish an experimental SDK version with the git SHA appended to the version number. - ## Pull Request All contributions to the OpenFeature project are welcome via GitHub pull requests. diff --git a/jest.config.ts b/jest.config.ts index f85620cea..fe9f61623 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -119,12 +119,18 @@ export default { testEnvironment: 'node', preset: 'ts-jest', testMatch: ['/packages/server/test/**/*.spec.ts'], + moduleNameMapper: { + '@openfeature/core': '/packages/shared/src' + }, }, { displayName: 'client', testEnvironment: 'node', preset: 'ts-jest', testMatch: ['/packages/client/test/**/*.spec.ts'], + moduleNameMapper: { + '@openfeature/core': '/packages/shared/src' + } }, { displayName: 'server-e2e', @@ -133,6 +139,9 @@ export default { testMatch: ['/packages/server/e2e/**/*.spec.ts'], modulePathIgnorePatterns: ['.*/node-modules/'], setupFiles: ['/packages/server/e2e/step-definitions/setup.ts'], + moduleNameMapper: { + '@openfeature/core': '/packages/shared/src' + }, }, { displayName: 'client-e2e', @@ -144,6 +153,7 @@ export default { moduleNameMapper: { '^uuid$': require.resolve('uuid'), '^(.*)\\.js$': ['$1', '$1.js'], + '@openfeature/core': '/packages/shared/src' }, }, ], diff --git a/package-lock.json b/package-lock.json index 9e08a4901..e384847c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "shx": "^0.3.4", "ts-jest": "^29.0.5", "ts-node": "^10.8.2", - "typedoc": "^0.24.8", + "typedoc": "^0.25.3", "typescript": "^4.7.4", "uuid": "^9.0.0" }, @@ -845,13 +845,13 @@ } }, "node_modules/@grpc/grpc-js": { - "version": "1.8.20", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.20.tgz", - "integrity": "sha512-SPse1wE4PcIFojOISsAnrWXCBsCBwDdcDqz2SS0T8nBSxg9jwmCK70Jy7ypRn2nIspwLy3Ls5TNaKNHo+6dF8A==", + "version": "1.9.8", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.8.tgz", + "integrity": "sha512-FFPzDS333Vw8hvf+1FaEsaCYVPBdNdUCw7zArTiF7+6gOzln967b4GBCBekKGqoKEgna8d3Ayxv8t+IvazXG3g==", "dev": true, "peer": true, "dependencies": { - "@grpc/proto-loader": "^0.7.0", + "@grpc/proto-loader": "^0.7.8", "@types/node": ">=12.12.47" }, "engines": { @@ -859,15 +859,14 @@ } }, "node_modules/@grpc/proto-loader": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.8.tgz", - "integrity": "sha512-GU12e2c8dmdXb7XUlOgYWZ2o2i+z9/VeACkxTA/zzAe2IjclC5PnVL0lpgjhrqfpDYHzM8B1TF6pqWegMYAzlA==", + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.10.tgz", + "integrity": "sha512-CAqDfoaQ8ykFd9zqBDn4k6iWT9loLAlc2ETmDFS9JCD70gDcnA4L3AFEo2iV7KyAtAAHFW9ftq1Fz+Vsgq80RQ==", "dev": true, "peer": true, "dependencies": { - "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^4.0.0", + "long": "^5.0.0", "protobufjs": "^7.2.4", "yargs": "^17.7.2" }, @@ -878,6 +877,13 @@ "node": ">=6" } }, + "node_modules/@grpc/proto-loader/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", + "dev": true, + "peer": true + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", @@ -1337,6 +1343,10 @@ "node": ">= 8" } }, + "node_modules/@openfeature/core": { + "resolved": "packages/shared", + "link": true + }, "node_modules/@openfeature/flagd-provider": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@openfeature/flagd-provider/-/flagd-provider-0.9.0.tgz", @@ -1383,10 +1393,6 @@ "resolved": "packages/server", "link": true }, - "node_modules/@openfeature/shared": { - "resolved": "packages/shared", - "link": true - }, "node_modules/@openfeature/web-sdk": { "resolved": "packages/client", "link": true @@ -1689,9 +1695,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.7", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.7.tgz", - "integrity": "sha512-HLyetab6KVPSiF+7pFcUyMeLsx25LDNDemw9mGsJBkai/oouwrjTycocSDYopMEwFhN2Y4s9oPyOCZNofgSt2g==", + "version": "29.5.6", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.6.tgz", + "integrity": "sha512-/t9NnzkOpXb4Nfvg17ieHE6EeSjDS2SGSpNYfoLbUAeL/EOueU/RSdOWFpfQTXBEM7BguYW1XQ0EbM+6RlIh6w==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1730,13 +1736,10 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "18.18.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.7.tgz", - "integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } + "version": "18.18.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.6.tgz", + "integrity": "sha512-wf3Vz+jCmOQ2HV1YUJuCWdL64adYxumkrxtc+H1VUQlnQI04+5HtH+qZCOE21lBE7gIrt+CwX2Wv8Acrw5Ak6w==", + "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -4243,20 +4246,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.1", "dev": true, @@ -10488,9 +10477,9 @@ } }, "node_modules/protobufjs": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.4.tgz", - "integrity": "sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ==", + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.5.tgz", + "integrity": "sha512-gGXRSXvxQ7UiPgfw8gevrfRWcTlSbOFg+p/N+JVJEK5VhueL2miT6qTymqAmjr1Q5WbOCyJbyrk6JfWKwlFn6A==", "dev": true, "hasInstallScript": true, "peer": true, @@ -12261,24 +12250,24 @@ } }, "node_modules/typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", + "version": "0.25.3", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.3.tgz", + "integrity": "sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", - "minimatch": "^9.0.0", + "minimatch": "^9.0.3", "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { - "node": ">= 14.14" + "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { @@ -12291,9 +12280,9 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -12333,12 +12322,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, "node_modules/union-value": { "version": "1.0.1", "dev": true, @@ -12825,7 +12808,10 @@ "version": "0.4.2", "license": "Apache-2.0", "devDependencies": { - "@openfeature/shared": "*" + "@openfeature/core": "*" + }, + "peerDependencies": { + "@openfeature/core": ">=0.1.0" } }, "packages/react": { @@ -12833,9 +12819,11 @@ "version": "0.0.1-experimental", "license": "Apache-2.0", "devDependencies": { + "@openfeature/core": "*", "@openfeature/web-sdk": "*" }, "peerDependencies": { + "@openfeature/core": "0.1.0", "@openfeature/web-sdk": ">=0.4.0", "react": ">=18.0.0" } @@ -12845,15 +12833,18 @@ "version": "1.6.3", "license": "Apache-2.0", "devDependencies": { - "@openfeature/shared": "*" + "@openfeature/core": "*" }, "engines": { "node": ">=16" + }, + "peerDependencies": { + "@openfeature/core": "0.1.0" } }, "packages/shared": { - "name": "@openfeature/shared", - "version": "0.0.13", + "name": "@openfeature/core", + "version": "0.1.0", "license": "Apache-2.0", "devDependencies": {} } diff --git a/package.json b/package.json index 289a0938c..bf023348e 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "clean": "shx rm -rf ./dist", "build": "npm run build --workspace=packages/shared --workspace=packages/server --workspace=packages/client --workspace=packages/react", "publish-all": "npm run publish-if-not-exists --workspace=packages/server --workspace=packages/client --workspace=packages/react", - "docs": "typedoc" + "docs": "typedoc", + "core-version": "npm run version --workspace=packages/shared", + "update-core-peers": "export OPENFEATURE_CORE_VERSION=$(npm run --silent core-version) && npm run update-core-peer --workspace=packages/server --workspace=packages/client --workspace=packages/react" }, "repository": { "type": "git", @@ -66,7 +68,7 @@ "shx": "^0.3.4", "ts-jest": "^29.0.5", "ts-node": "^10.8.2", - "typedoc": "^0.24.8", + "typedoc": "^0.25.3", "typescript": "^4.7.4", "uuid": "^9.0.0" }, diff --git a/packages/client/e2e/step-definitions/evaluation.spec.ts b/packages/client/e2e/step-definitions/evaluation.spec.ts index 5bcc36bbf..017661b71 100644 --- a/packages/client/e2e/step-definitions/evaluation.spec.ts +++ b/packages/client/e2e/step-definitions/evaluation.spec.ts @@ -6,7 +6,7 @@ import { EvaluationContext, ResolutionDetails, StandardResolutionReasons, -} from '@openfeature/shared'; +} from '@openfeature/core'; import { OpenFeature, ProviderEvents } from '../..'; // load the feature file. const feature = loadFeature('packages/client/e2e/features/evaluation.feature'); diff --git a/packages/client/package.json b/packages/client/package.json index 4bba82403..f7f6fefc5 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -17,15 +17,15 @@ "test": "jest --verbose", "lint": "eslint ./", "clean": "shx rm -rf ./dist", - "build:web-esm": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --platform=browser --format=esm --outfile=./dist/esm/index.js --analyze", - "build:web-cjs": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --platform=browser --format=cjs --outfile=./dist/cjs/index.js --analyze", + "build:web-esm": "esbuild src/index.ts --bundle --external:@openfeature/core --sourcemap --target=es2016 --platform=browser --format=esm --outfile=./dist/esm/index.js --analyze", + "build:web-cjs": "esbuild src/index.ts --bundle --external:@openfeature/core --sourcemap --target=es2016 --platform=browser --format=cjs --outfile=./dist/cjs/index.js --analyze", "build:rollup-types": "rollup -c ../../rollup.config.mjs", "build": "npm run clean && npm run build:web-esm && npm run build:web-cjs && npm run build:rollup-types", "postbuild": "shx cp ./../../package.esm.json ./dist/esm/package.json", "current-version": "echo $npm_package_version", "prepack": "shx cp ./../../LICENSE ./LICENSE", "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi", - "docs": "typedoc" + "update-core-peer": "npm install --save-peer --save-exact @openfeature/core@$OPENFEATURE_CORE_VERSION" }, "repository": { "type": "git", @@ -45,11 +45,10 @@ "url": "https://github.com/open-feature/js-sdk/issues" }, "homepage": "https://github.com/open-feature/js-sdk#readme", - "devDependencies": { - "@openfeature/shared": "*" + "peerDependencies": { + "@openfeature/core": ">=0.1.0" }, - "typedoc": { - "displayName": "OpenFeature Web SDK", - "entryPoint": "./src/index.ts" + "devDependencies": { + "@openfeature/core": "*" } } diff --git a/packages/client/src/client/client.ts b/packages/client/src/client/client.ts index 5750ea79a..6bd96b9d0 100644 --- a/packages/client/src/client/client.ts +++ b/packages/client/src/client/client.ts @@ -1,4 +1,4 @@ -import { ClientMetadata, EvaluationLifeCycle, Eventing, ManageLogger } from '@openfeature/shared'; +import { ClientMetadata, EvaluationLifeCycle, Eventing, ManageLogger } from '@openfeature/core'; import { Features } from '../evaluation'; export interface Client extends EvaluationLifeCycle, Features, ManageLogger, Eventing { diff --git a/packages/client/src/client/open-feature-client.ts b/packages/client/src/client/open-feature-client.ts index fb22f5780..370ec7792 100644 --- a/packages/client/src/client/open-feature-client.ts +++ b/packages/client/src/client/open-feature-client.ts @@ -17,7 +17,7 @@ import { ResolutionDetails, SafeLogger, StandardResolutionReasons, -} from '@openfeature/shared'; +} from '@openfeature/core'; import { FlagEvaluationOptions } from '../evaluation'; import { OpenFeature } from '../open-feature'; import { Provider } from '../provider'; diff --git a/packages/client/src/evaluation/evaluation.ts b/packages/client/src/evaluation/evaluation.ts index 74d1ffe57..8555dd530 100644 --- a/packages/client/src/evaluation/evaluation.ts +++ b/packages/client/src/evaluation/evaluation.ts @@ -1,4 +1,4 @@ -import { EvaluationDetails, Hook, HookHints, JsonValue } from '@openfeature/shared'; +import { EvaluationDetails, Hook, HookHints, JsonValue } from '@openfeature/core'; export interface FlagEvaluationOptions { hooks?: Hook[]; diff --git a/packages/client/src/index.ts b/packages/client/src/index.ts index a45964d60..af13fff41 100644 --- a/packages/client/src/index.ts +++ b/packages/client/src/index.ts @@ -1,5 +1,6 @@ +import 'events'; // we need this to trigger the bundling of the browser events module: https://www.npmjs.com/package/events export * from './client'; export * from './provider'; export * from './evaluation'; export * from './open-feature'; -export * from '@openfeature/shared'; +export * from '@openfeature/core'; diff --git a/packages/client/src/open-feature.ts b/packages/client/src/open-feature.ts index d9ebd7264..6b5aa8a9b 100644 --- a/packages/client/src/open-feature.ts +++ b/packages/client/src/open-feature.ts @@ -1,4 +1,4 @@ -import { EvaluationContext, ManageContext, OpenFeatureCommonAPI } from '@openfeature/shared'; +import { EvaluationContext, ManageContext, OpenFeatureCommonAPI } from '@openfeature/core'; import { Client, OpenFeatureClient } from './client'; import { NOOP_PROVIDER, Provider } from './provider'; diff --git a/packages/client/src/provider/no-op-provider.ts b/packages/client/src/provider/no-op-provider.ts index 2a746b7c8..8493bf3bd 100644 --- a/packages/client/src/provider/no-op-provider.ts +++ b/packages/client/src/provider/no-op-provider.ts @@ -1,4 +1,4 @@ -import { JsonValue, ProviderStatus, ResolutionDetails } from '@openfeature/shared'; +import { JsonValue, ProviderStatus, ResolutionDetails } from '@openfeature/core'; import { Provider } from './provider'; const REASON_NO_OP = 'No-op'; diff --git a/packages/client/src/provider/provider.ts b/packages/client/src/provider/provider.ts index 4c44d39d7..16a4bafe3 100644 --- a/packages/client/src/provider/provider.ts +++ b/packages/client/src/provider/provider.ts @@ -1,4 +1,4 @@ -import { CommonProvider, EvaluationContext, Hook, JsonValue, Logger, ResolutionDetails } from '@openfeature/shared'; +import { CommonProvider, EvaluationContext, Hook, JsonValue, Logger, ResolutionDetails } from '@openfeature/core'; /** * Interface that providers must implement to resolve flag values for their particular diff --git a/packages/client/test/open-feature.spec.ts b/packages/client/test/open-feature.spec.ts index 0cced3691..24cf03e4c 100644 --- a/packages/client/test/open-feature.spec.ts +++ b/packages/client/test/open-feature.spec.ts @@ -1,4 +1,4 @@ -import { Paradigm } from '@openfeature/shared'; +import { Paradigm } from '@openfeature/core'; import { OpenFeature, OpenFeatureAPI, OpenFeatureClient, Provider, ProviderStatus } from '../src'; const mockProvider = (config?: { initialStatus?: ProviderStatus; runsOn?: Paradigm }) => { diff --git a/packages/client/typedoc.json b/packages/client/typedoc.json new file mode 100644 index 000000000..88ea8bd77 --- /dev/null +++ b/packages/client/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "@openfeature/web-sdk", + "includeVersion": true, + "entryPoints": [ + "src/index.ts", + ] +} \ No newline at end of file diff --git a/packages/react/package.json b/packages/react/package.json index 438e082fe..57590028c 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -25,7 +25,7 @@ "current-version": "echo $npm_package_version", "prepack": "shx cp ./../../LICENSE ./LICENSE", "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi", - "docs": "typedoc" + "update-core-peer": "npm install --save-peer --save-exact @openfeature/core@$OPENFEATURE_CORE_VERSION" }, "repository": { "type": "git", @@ -47,14 +47,12 @@ }, "homepage": "https://github.com/open-feature/js-sdk#readme", "peerDependencies": { + "@openfeature/core": "0.1.0", "@openfeature/web-sdk": ">=0.4.0", "react": ">=18.0.0" }, "devDependencies": { + "@openfeature/core": "*", "@openfeature/web-sdk": "*" - }, - "typedoc": { - "displayName": "OpenFeature React SDK", - "entryPoint": "./src/index.ts" } } diff --git a/packages/react/typedoc.json b/packages/react/typedoc.json new file mode 100644 index 000000000..76a22f57e --- /dev/null +++ b/packages/react/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "@openfeature/react-sdk", + "includeVersion": true, + "entryPoints": [ + "src/index.ts", + ] +} \ No newline at end of file diff --git a/packages/server/e2e/step-definitions/evaluation.spec.ts b/packages/server/e2e/step-definitions/evaluation.spec.ts index 9cb4c254e..1794ffdb0 100644 --- a/packages/server/e2e/step-definitions/evaluation.spec.ts +++ b/packages/server/e2e/step-definitions/evaluation.spec.ts @@ -7,7 +7,7 @@ import { ResolutionDetails, StandardResolutionReasons, ProviderEvents, -} from '@openfeature/shared'; +} from '@openfeature/core'; import { OpenFeature } from '../..'; // load the feature file. const feature = loadFeature('packages/server/e2e/features/evaluation.feature'); diff --git a/packages/server/package.json b/packages/server/package.json index 386dfa26a..6ee5a14a4 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -14,18 +14,18 @@ }, "types": "./dist/types.d.ts", "scripts": { - "test": "jest --verbose", + "test": "jest --verbose", "lint": "eslint ./", "clean": "shx rm -rf ./dist", - "build:esm": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --platform=node --format=esm --outfile=./dist/esm/index.js --analyze", - "build:cjs": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --platform=node --format=cjs --outfile=./dist/cjs/index.js --analyze", + "build:esm": "esbuild src/index.ts --bundle --external:@openfeature/core --sourcemap --target=es2016 --platform=node --format=esm --outfile=./dist/esm/index.js --analyze", + "build:cjs": "esbuild src/index.ts --bundle --external:@openfeature/core --sourcemap --target=es2016 --platform=node --format=cjs --outfile=./dist/cjs/index.js --analyze", "build:rollup-types": "rollup -c ../../rollup.config.mjs", "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:rollup-types", "postbuild": "shx cp ./../../package.esm.json ./dist/esm/package.json", "current-version": "echo $npm_package_version", "prepack": "shx cp ./../../LICENSE ./LICENSE", "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi", - "docs": "typedoc" + "update-core-peer": "npm install --save-peer --save-exact @openfeature/core@$OPENFEATURE_CORE_VERSION" }, "repository": { "type": "git", @@ -47,11 +47,10 @@ "engines": { "node": ">=16" }, - "devDependencies": { - "@openfeature/shared": "*" + "peerDependencies": { + "@openfeature/core": "0.1.0" }, - "typedoc": { - "displayName": "OpenFeature Server SDK", - "entryPoint": "./src/index.ts" + "devDependencies": { + "@openfeature/core": "*" } } diff --git a/packages/server/src/client/client.ts b/packages/server/src/client/client.ts index 57d29bce8..cec24693c 100644 --- a/packages/server/src/client/client.ts +++ b/packages/server/src/client/client.ts @@ -1,4 +1,4 @@ -import { ClientMetadata, EvaluationLifeCycle, Eventing, ManageContext, ManageLogger } from '@openfeature/shared'; +import { ClientMetadata, EvaluationLifeCycle, Eventing, ManageContext, ManageLogger } from '@openfeature/core'; import { Features } from '../evaluation'; export interface Client diff --git a/packages/server/src/client/open-feature-client.ts b/packages/server/src/client/open-feature-client.ts index 9e2d4ef24..af91e565c 100644 --- a/packages/server/src/client/open-feature-client.ts +++ b/packages/server/src/client/open-feature-client.ts @@ -18,7 +18,7 @@ import { SafeLogger, StandardResolutionReasons, statusMatchesEvent -} from '@openfeature/shared'; +} from '@openfeature/core'; import { FlagEvaluationOptions } from '../evaluation'; import { OpenFeature } from '../open-feature'; import { Provider } from '../provider'; diff --git a/packages/server/src/evaluation/evaluation.ts b/packages/server/src/evaluation/evaluation.ts index 1a782468f..979d7818f 100644 --- a/packages/server/src/evaluation/evaluation.ts +++ b/packages/server/src/evaluation/evaluation.ts @@ -1,4 +1,4 @@ -import { EvaluationContext, EvaluationDetails, Hook, HookHints, JsonValue } from '@openfeature/shared'; +import { EvaluationContext, EvaluationDetails, Hook, HookHints, JsonValue } from '@openfeature/core'; export interface FlagEvaluationOptions { hooks?: Hook[]; diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 116336b6f..3a865a48b 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -3,4 +3,4 @@ export * from './provider'; export * from './evaluation'; export * from './open-feature'; export * from './transaction-context'; -export * from '@openfeature/shared'; +export * from '@openfeature/core'; diff --git a/packages/server/src/open-feature.ts b/packages/server/src/open-feature.ts index 962bb20d1..804c050ee 100644 --- a/packages/server/src/open-feature.ts +++ b/packages/server/src/open-feature.ts @@ -5,7 +5,7 @@ import { EvaluationContext, objectOrUndefined, stringOrUndefined, -} from '@openfeature/shared'; +} from '@openfeature/core'; import { ManageTransactionContextPropagator, NOOP_TRANSACTION_CONTEXT_PROPAGATOR, diff --git a/packages/server/src/provider/in-memory-provider/flag-configuration.ts b/packages/server/src/provider/in-memory-provider/flag-configuration.ts index 0ca3e4350..2bbfc9173 100644 --- a/packages/server/src/provider/in-memory-provider/flag-configuration.ts +++ b/packages/server/src/provider/in-memory-provider/flag-configuration.ts @@ -3,7 +3,7 @@ * It might cause confusion since these types are not a part of the general API, * but just for the in-memory provider. */ -import { EvaluationContext, JsonValue } from '@openfeature/shared'; +import { EvaluationContext, JsonValue } from '@openfeature/core'; type Variants = Record; diff --git a/packages/server/src/provider/in-memory-provider/in-memory-provider.ts b/packages/server/src/provider/in-memory-provider/in-memory-provider.ts index 223be4182..00e868501 100644 --- a/packages/server/src/provider/in-memory-provider/in-memory-provider.ts +++ b/packages/server/src/provider/in-memory-provider/in-memory-provider.ts @@ -11,7 +11,7 @@ import { ResolutionDetails, StandardResolutionReasons, TypeMismatchError -} from '@openfeature/shared'; +} from '@openfeature/core'; import { Provider } from '../provider'; import { Flag, FlagConfiguration } from './flag-configuration'; import { VariantFoundError } from './variant-not-found-error'; diff --git a/packages/server/src/provider/in-memory-provider/variant-not-found-error.ts b/packages/server/src/provider/in-memory-provider/variant-not-found-error.ts index d7542e848..3553a7c09 100644 --- a/packages/server/src/provider/in-memory-provider/variant-not-found-error.ts +++ b/packages/server/src/provider/in-memory-provider/variant-not-found-error.ts @@ -1,4 +1,4 @@ -import { ErrorCode, OpenFeatureError } from '@openfeature/shared'; +import { ErrorCode, OpenFeatureError } from '@openfeature/core'; /** * A custom error for the in-memory provider. diff --git a/packages/server/src/provider/no-op-provider.ts b/packages/server/src/provider/no-op-provider.ts index f91874bcd..7a056f718 100644 --- a/packages/server/src/provider/no-op-provider.ts +++ b/packages/server/src/provider/no-op-provider.ts @@ -1,4 +1,4 @@ -import { ResolutionDetails, JsonValue, ProviderStatus } from '@openfeature/shared'; +import { ResolutionDetails, JsonValue, ProviderStatus } from '@openfeature/core'; import { Provider } from './provider'; const REASON_NO_OP = 'No-op'; diff --git a/packages/server/src/provider/provider.ts b/packages/server/src/provider/provider.ts index 906d7cb24..83b23788b 100644 --- a/packages/server/src/provider/provider.ts +++ b/packages/server/src/provider/provider.ts @@ -1,4 +1,4 @@ -import { CommonProvider, EvaluationContext, Hook, JsonValue, Logger, ResolutionDetails } from '@openfeature/shared'; +import { CommonProvider, EvaluationContext, Hook, JsonValue, Logger, ResolutionDetails } from '@openfeature/core'; /** * Interface that providers must implement to resolve flag values for their particular diff --git a/packages/server/src/transaction-context/no-op-transaction-context-propagator.ts b/packages/server/src/transaction-context/no-op-transaction-context-propagator.ts index 0dbeaaa5b..7897f6fd2 100644 --- a/packages/server/src/transaction-context/no-op-transaction-context-propagator.ts +++ b/packages/server/src/transaction-context/no-op-transaction-context-propagator.ts @@ -1,4 +1,4 @@ -import { EvaluationContext } from '@openfeature/shared'; +import { EvaluationContext } from '@openfeature/core'; import { TransactionContextPropagator } from './transaction-context'; class NoopTransactionContextPropagator implements TransactionContextPropagator { diff --git a/packages/server/src/transaction-context/transaction-context.ts b/packages/server/src/transaction-context/transaction-context.ts index d69c5f86a..925fefb77 100644 --- a/packages/server/src/transaction-context/transaction-context.ts +++ b/packages/server/src/transaction-context/transaction-context.ts @@ -1,4 +1,4 @@ -import { EvaluationContext } from '@openfeature/shared'; +import { EvaluationContext } from '@openfeature/core'; /** * Transaction context is a mechanism for adding transaction specific context that diff --git a/packages/server/test/in-memory-provider.spec.ts b/packages/server/test/in-memory-provider.spec.ts index 28880e210..48be64489 100644 --- a/packages/server/test/in-memory-provider.spec.ts +++ b/packages/server/test/in-memory-provider.spec.ts @@ -1,4 +1,4 @@ -import { ErrorCode, FlagNotFoundError, ProviderEvents, StandardResolutionReasons, TypeMismatchError } from '@openfeature/shared'; +import { ErrorCode, FlagNotFoundError, ProviderEvents, StandardResolutionReasons, TypeMismatchError } from '@openfeature/core'; import { InMemoryProvider } from '../src'; import { VariantFoundError } from '../src/provider/in-memory-provider/variant-not-found-error'; diff --git a/packages/server/test/open-feature.spec.ts b/packages/server/test/open-feature.spec.ts index a84229623..05dbb8e7f 100644 --- a/packages/server/test/open-feature.spec.ts +++ b/packages/server/test/open-feature.spec.ts @@ -1,4 +1,4 @@ -import { Paradigm } from '@openfeature/shared'; +import { Paradigm } from '@openfeature/core'; import { OpenFeature, OpenFeatureAPI, OpenFeatureClient, Provider, ProviderStatus } from '../src'; const mockProvider = (config?: { initialStatus?: ProviderStatus; runsOn?: Paradigm }) => { diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json index d0164246a..0e8c768cd 100644 --- a/packages/server/tsconfig.json +++ b/packages/server/tsconfig.json @@ -44,7 +44,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist/esm", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ diff --git a/packages/server/typedoc.json b/packages/server/typedoc.json new file mode 100644 index 000000000..124ef48c2 --- /dev/null +++ b/packages/server/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "@openfeature/server-sdk", + "includeVersion": true, + "entryPoints": [ + "src/index.ts", + ] +} \ No newline at end of file diff --git a/packages/shared/README.md b/packages/shared/README.md new file mode 100644 index 000000000..0bdddc97b --- /dev/null +++ b/packages/shared/README.md @@ -0,0 +1,51 @@ + + +

+ + + OpenFeature Logo + +

+ +

Shared js components (server and web)

+ + + +

+ + Specification + + + + Release + + +
+ + API Reference + + + NPM Download + + + codecov + + + CII Best Practices + +

+ + +[OpenFeature](https://openfeature.dev) is an open standard that provides a vendor-agnostic, community-driven API for feature flagging that works with your favorite feature flag management tool. + + + +## 🔩 Shared JS components + +> [!IMPORTANT] +> If you're developing a provider or hook, you probably do not want to use this package! + +This package comprises the common types and interfaces of the OpenFeature server and web SDKs. +If you are developing a provider or a hook, you should instead utilize the [server](../server/README.md) or [web](../client/README.md) SDKs. +This package is useful if you need to reference the underlying types common to all the JS SDKs, or if you're creating a utility that can be used to both server and web implementations. +Be sure to add this module as either a `devDependency` (if only build time assets such as types are required) or as a `peerDependency` with a permissive version expression. \ No newline at end of file diff --git a/packages/shared/package.json b/packages/shared/package.json index 176148cbc..2740585cc 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,8 +1,18 @@ { - "name": "@openfeature/shared", - "version": "0.0.13", - "main": "src/index", - "description": "Shared js/web components", + "name": "@openfeature/core", + "version": "0.1.0", + "description": "Shared OpenFeature JS components (server and web)", + "main": "./dist/cjs/index.js", + "files": [ + "dist/" + ], + "exports": { + "types": "./dist/types.d.ts", + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js", + "default": "./dist/cjs/index.js" + }, + "types": "./dist/types.d.ts", "devDependencies": {}, "scripts": { "test": "jest --verbose", @@ -12,7 +22,12 @@ "build:esm": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --format=esm --outfile=./dist/esm/index.js --analyze", "build:cjs": "esbuild src/index.ts --bundle --sourcemap --target=es2016 --format=cjs --outfile=./dist/cjs/index.js --analyze", "build:rollup-types": "rollup -c ../../rollup.config.mjs", - "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:rollup-types" + "build": "npm run clean && npm run build:esm && npm run build:cjs && npm run build:rollup-types", + "postbuild": "shx cp ./../../package.esm.json ./dist/esm/package.json", + "current-version": "echo $npm_package_version", + "prepack": "shx cp ./../../LICENSE ./LICENSE", + "publish-if-not-exists": "cp $NPM_CONFIG_USERCONFIG .npmrc && if [ \"$(npm show $npm_package_name@$npm_package_version version)\" = \"$(npm run current-version -s)\" ]; then echo 'already published, skipping'; else npm publish --access public; fi", + "version": "echo $npm_package_version" }, "repository": { "type": "git", diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index 624fa2800..adf8d22c8 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json @@ -10,7 +10,9 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ "target": "ES2015", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + "lib": [ + "ES2020" + ], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ @@ -90,12 +92,6 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "typedocOptions": { - "name": "OpenFeature SDK", - "entryPoints": [ - "src/index.ts" - ] - }, "include": [ "./src/**/*" ], diff --git a/packages/shared/typedoc.json b/packages/shared/typedoc.json new file mode 100644 index 000000000..4b97f3ab3 --- /dev/null +++ b/packages/shared/typedoc.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "name": "@openfeature/core", + "includeVersion": true, + "entryPoints": [ + "src/index.ts", + ] +} \ No newline at end of file diff --git a/rollup.config.mjs b/rollup.config.mjs index e128fe453..1d55f41f9 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -18,11 +18,6 @@ export default { } ], plugins: [ - alias({ - entries: [ - { find: '@openfeature/shared', replacement: '../shared/dist/types.d.ts' }, - ], - }), - dts({tsconfig: './tsconfig.json', respectExternal: true}), + dts({tsconfig: './tsconfig.json'}), ], }; \ No newline at end of file diff --git a/typedoc.json b/typedoc.json index f449dc6f2..29f21239d 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,9 +1,13 @@ { "$schema": "https://typedoc.org/schema.json", - "entryPointStrategy": "legacy-packages", + "entryPointStrategy": "packages", "entryPoints": [ "packages/server", - "packages/client" + "packages/client", + "packages/shared", + ], + "sort": [ + "source-order" ], "out": "typedoc" } \ No newline at end of file