diff --git a/.github/workflows/sdk-spec.yml b/.github/workflows/sdk-spec.yml new file mode 100644 index 0000000..cfb2ea1 --- /dev/null +++ b/.github/workflows/sdk-spec.yml @@ -0,0 +1,17 @@ +name: SDK spec + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + sdk-spec: + # Keep the ref in `uses:` and `spec-ref` in sync. + uses: Flagsmith/sdk-spec/.github/workflows/run-spec.yml@v0.3.0 + with: + spec-ref: v0.3.0 + language: nodejs diff --git a/.npmignore b/.npmignore index c4c7620..f13707b 100644 --- a/.npmignore +++ b/.npmignore @@ -1 +1,2 @@ ./.idea +sdk-spec/ diff --git a/renovate.json b/renovate.json index b7a5f2e..b1830e2 100644 --- a/renovate.json +++ b/renovate.json @@ -4,6 +4,15 @@ "ignorePresets": [":semanticPrefixFixDepsChoreOthers"], "semanticCommitType": "deps", "git-submodules": { "enabled": true }, + "customManagers": [ + { + "customType": "regex", + "managerFilePatterns": ["/^\\.github/workflows/sdk-spec\\.yml$/"], + "matchStrings": ["spec-ref: (?v[\\d.]+)"], + "depNameTemplate": "Flagsmith/sdk-spec", + "datasourceTemplate": "github-tags" + } + ], "packageRules": [ { "matchUpdateTypes": [ @@ -23,6 +32,11 @@ "matchManagers": ["git-submodules"], "versioning": "semver-coerced", "enabled": true + }, + { + "matchPackageNames": ["Flagsmith/sdk-spec"], + "groupName": "SDK spec", + "enabled": true } ] } diff --git a/sdk-spec/Dockerfile b/sdk-spec/Dockerfile new file mode 100644 index 0000000..faea9da --- /dev/null +++ b/sdk-spec/Dockerfile @@ -0,0 +1,23 @@ +# Runs this SDK, built from source, under the Flagsmith SDK behavioural spec. +# docker build -f sdk-spec/Dockerfile --build-context harness=/harness/nodejs . +FROM docker.io/library/node:24-slim AS build + +WORKDIR /sdk +COPY package.json package-lock.json tsconfig*.json .npmignore ./ +# Skip the `prepare` script, which installs Git hooks. +RUN npm ci --ignore-scripts +COPY index.ts ./ +COPY sdk ./sdk +COPY flagsmith-engine ./flagsmith-engine +RUN npm run build && npm pack --ignore-scripts --pack-destination /tmp + +FROM docker.io/library/node:24-slim + +WORKDIR /sdk +COPY --from=build /tmp/flagsmith-nodejs-*.tgz /tmp/ +RUN npm install --no-save --no-audit --no-fund /tmp/flagsmith-nodejs-*.tgz && rm /tmp/*.tgz + +COPY --from=harness harness.mts /harness/harness.mts +COPY sdk-spec/steps.mts ./sdk-spec/steps.mts + +ENTRYPOINT ["node", "/harness/harness.mts", "sdk-spec/steps.mts"] diff --git a/sdk-spec/steps.mts b/sdk-spec/steps.mts new file mode 100644 index 0000000..9d4b3c8 --- /dev/null +++ b/sdk-spec/steps.mts @@ -0,0 +1,34 @@ +/** + * Steps for the Flagsmith SDK behavioural spec: https://github.com/Flagsmith/sdk-spec + * + * Each function implements the Gherkin step in the comment above it. + */ + +import { Flagsmith, type Flags, type FlagsmithValue } from '@flagsmith/nodejs'; + +function asSpecFlags(flags: Flags) { + return flags.allFlags().map(flag => ({ + feature: flag.featureName, + enabled: flag.enabled, + value: flag.value + })); +} + +// Create the SDK client +export function createClient(environmentKey: string, apiUrl: string) { + return new Flagsmith({ environmentKey, apiUrl }); +} + +// When the application gets the environment flags +export async function getEnvironmentFlags(flagsmith: Flagsmith) { + return asSpecFlags(await flagsmith.getEnvironmentFlags()); +} + +// When the application gets the flags for identity "{identifier}" with traits: +export async function getIdentityFlags( + flagsmith: Flagsmith, + identifier: string, + traits: Record +) { + return asSpecFlags(await flagsmith.getIdentityFlags(identifier, traits)); +}