@eightyfourthousand/lib-instr 2026.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +12 -0
- package/.eslintrc.json +18 -0
- package/README.md +7 -0
- package/jest.config.ts +10 -0
- package/package.json +26 -0
- package/postcss.config.mjs +9 -0
- package/project.json +24 -0
- package/src/index.ts +4 -0
- package/src/lib/browser-client.ts +22 -0
- package/src/lib/feature-flags.tsx +77 -0
- package/src/lib/instr-provider.tsx +7 -0
- package/src/lib/server-client.ts +24 -0
- package/src/lib/static-features.ts +21 -0
- package/src/lib/use-instr.ts +3 -0
- package/src/ssr.ts +1 -0
- package/src/static.ts +1 -0
- package/tsconfig.json +20 -0
- package/tsconfig.lib.json +28 -0
- package/tsconfig.spec.json +22 -0
package/.babelrc
ADDED
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
|
3
|
+
"ignorePatterns": ["!**/*", "storybook-static"],
|
|
4
|
+
"overrides": [
|
|
5
|
+
{
|
|
6
|
+
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
|
7
|
+
"rules": {}
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"files": ["*.ts", "*.tsx"],
|
|
11
|
+
"rules": {}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"files": ["*.js", "*.jsx"],
|
|
15
|
+
"rules": {}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|
package/README.md
ADDED
package/jest.config.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
displayName: 'lib-instr',
|
|
3
|
+
preset: '../../jest.preset.js',
|
|
4
|
+
transform: {
|
|
5
|
+
'^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nx/react/plugins/jest',
|
|
6
|
+
'^.+\\.[tj]sx?$': ['babel-jest', { presets: ['@nx/react/babel'] }],
|
|
7
|
+
},
|
|
8
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
|
9
|
+
coverageDirectory: '../../coverage/libs/lib-utils',
|
|
10
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@eightyfourthousand/lib-instr",
|
|
3
|
+
"version": "2026.3.0",
|
|
4
|
+
"description": "Feature flag and instrumentation helpers for 84000 applications.",
|
|
5
|
+
"private": false,
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/84000/84000-apps.git",
|
|
9
|
+
"directory": "libs/lib-instr"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/84000/84000-apps",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/84000/84000-apps/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"react": "^19.0.0",
|
|
21
|
+
"react-dom": "^19.0.0"
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"keywords": [],
|
|
25
|
+
"author": ""
|
|
26
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lib-instr",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "libs/lib-instr/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": ["type:utility", "scope:shared"],
|
|
7
|
+
"targets": {
|
|
8
|
+
"build": {
|
|
9
|
+
"executor": "@nx/js:tsc",
|
|
10
|
+
"outputs": ["{options.outputPath}"],
|
|
11
|
+
"options": {
|
|
12
|
+
"outputPath": "dist/libs/lib-instr",
|
|
13
|
+
"main": "libs/lib-instr/src/index.ts",
|
|
14
|
+
"tsConfig": "libs/lib-instr/tsconfig.lib.json",
|
|
15
|
+
"rootDir": "libs/lib-instr/src",
|
|
16
|
+
"generateExportsField": true,
|
|
17
|
+
"additionalEntryPoints": [
|
|
18
|
+
"libs/lib-instr/src/ssr.ts",
|
|
19
|
+
"libs/lib-instr/src/static.ts"
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import posthog from 'posthog-js';
|
|
2
|
+
|
|
3
|
+
export const initializeInstrumentation = () => {
|
|
4
|
+
const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY;
|
|
5
|
+
const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST;
|
|
6
|
+
|
|
7
|
+
if (!POSTHOG_KEY) {
|
|
8
|
+
console.warn('Missing NEXT_PUBLIC_POSTHOG_KEY environment variable');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!POSTHOG_HOST) {
|
|
12
|
+
console.warn('Missing NEXT_PUBLIC_POSTHOG_HOST environment variable');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (POSTHOG_KEY && POSTHOG_HOST) {
|
|
16
|
+
posthog.init(POSTHOG_KEY, {
|
|
17
|
+
api_host: POSTHOG_HOST,
|
|
18
|
+
defaults: '2025-05-24',
|
|
19
|
+
person_profiles: 'identified_only',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import {
|
|
2
|
+
useFeatureFlagEnabled as phUseFeatureFlagEnabled,
|
|
3
|
+
useFeatureFlagPayload as phUseFeatureFlagPayload,
|
|
4
|
+
useFeatureFlagVariantKey as phUseFeatureFlagVariantKey,
|
|
5
|
+
PostHogFeatureProps,
|
|
6
|
+
} from '@posthog/react';
|
|
7
|
+
import { JsonType } from 'posthog-js';
|
|
8
|
+
|
|
9
|
+
export type FeatureFlag =
|
|
10
|
+
| 'authority-pages'
|
|
11
|
+
| 'translation-hover-cards'
|
|
12
|
+
| 'studio-header-config'
|
|
13
|
+
| 'show-restriction-warning';
|
|
14
|
+
|
|
15
|
+
export type FeatureFlagPayload = {
|
|
16
|
+
apps?: string[];
|
|
17
|
+
[key: string]: JsonType;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Checks if a feature flag is enabled for the current application.
|
|
22
|
+
* If the feature flag has an "apps" payload, it checks if the current
|
|
23
|
+
* application is included in that list.
|
|
24
|
+
*
|
|
25
|
+
* @param flagKey - The key of the feature flag to check.
|
|
26
|
+
* @returns True if the feature flag is enabled for the current application, false otherwise.
|
|
27
|
+
*/
|
|
28
|
+
export const useFeatureFlagEnabled = (flagKey: FeatureFlag): boolean => {
|
|
29
|
+
if (!phUseFeatureFlagEnabled(flagKey)) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const APPLICATION_NAME = process.env.NEXT_PUBLIC_APPLICATION_NAME || '';
|
|
34
|
+
const { apps } = phUseFeatureFlagPayload(flagKey) as FeatureFlagPayload;
|
|
35
|
+
|
|
36
|
+
if (!apps?.length) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return apps.includes(APPLICATION_NAME);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export const useFeatureFlagPayload = (
|
|
44
|
+
flagKey: FeatureFlag,
|
|
45
|
+
): FeatureFlagPayload => {
|
|
46
|
+
return phUseFeatureFlagPayload(flagKey) as FeatureFlagPayload;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const useFeatureFlagVariantKey = (
|
|
50
|
+
flagKey: FeatureFlag,
|
|
51
|
+
): string | boolean | undefined => {
|
|
52
|
+
return phUseFeatureFlagVariantKey(flagKey);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type GatedFeatureProps = PostHogFeatureProps & {
|
|
56
|
+
flag: FeatureFlag;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const GatedFeature = ({ children, flag }: GatedFeatureProps) => {
|
|
60
|
+
const enabled = useFeatureFlagEnabled(flag);
|
|
61
|
+
return enabled ? children : null;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Returns the studio header config payload from PostHog.
|
|
66
|
+
* Returns undefined if the flag is not enabled or has no payload.
|
|
67
|
+
*/
|
|
68
|
+
export const useStudioHeaderConfig = (): unknown => {
|
|
69
|
+
const enabled = phUseFeatureFlagEnabled('studio-header-config');
|
|
70
|
+
const payload = phUseFeatureFlagPayload('studio-header-config');
|
|
71
|
+
|
|
72
|
+
if (!enabled) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return payload;
|
|
77
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import posthog from 'posthog-js';
|
|
3
|
+
import { PostHogProvider } from '@posthog/react';
|
|
4
|
+
|
|
5
|
+
export const InstrProvider = ({ children }: { children: ReactNode }) => {
|
|
6
|
+
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
|
|
7
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PostHog } from 'posthog-node';
|
|
2
|
+
|
|
3
|
+
export const createInstrumentationClient = () => {
|
|
4
|
+
const POSTHOG_KEY = process.env.NEXT_PUBLIC_POSTHOG_KEY;
|
|
5
|
+
const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST;
|
|
6
|
+
|
|
7
|
+
if (!POSTHOG_KEY) {
|
|
8
|
+
console.warn('Missing NEXT_PUBLIC_POSTHOG_KEY environment variable');
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (!POSTHOG_HOST) {
|
|
12
|
+
console.warn('Missing NEXT_PUBLIC_POSTHOG_HOST environment variable');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!POSTHOG_KEY || !POSTHOG_HOST) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return new PostHog(POSTHOG_KEY, {
|
|
20
|
+
host: POSTHOG_HOST,
|
|
21
|
+
flushAt: 1,
|
|
22
|
+
flushInterval: 0,
|
|
23
|
+
});
|
|
24
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// NOTE: PostHog does not currently support checking feature flags or remote
|
|
2
|
+
// config values during server-side rendering. Until that is supported, we will
|
|
3
|
+
// use this hard coded configuration.
|
|
4
|
+
|
|
5
|
+
export type StaticFeature = 'glossary-attestations';
|
|
6
|
+
|
|
7
|
+
const STATIC_FEATURE_FLAGS: Record<StaticFeature, string[]> = {
|
|
8
|
+
'glossary-attestations': ['scholars-room'],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const isStaticFeatureEnabled = (flagKey: StaticFeature) => {
|
|
12
|
+
const APPLICATION_NAME = process.env.NEXT_PUBLIC_APPLICATION_NAME || '';
|
|
13
|
+
|
|
14
|
+
const apps = STATIC_FEATURE_FLAGS[flagKey] || [];
|
|
15
|
+
|
|
16
|
+
if (!apps.length) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return apps.includes(APPLICATION_NAME);
|
|
21
|
+
};
|
package/src/ssr.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/server-client';
|
package/src/static.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/static-features';
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"jsx": "react-jsx",
|
|
4
|
+
"allowJs": false,
|
|
5
|
+
"esModuleInterop": false,
|
|
6
|
+
"allowSyntheticDefaultImports": true,
|
|
7
|
+
"strict": true
|
|
8
|
+
},
|
|
9
|
+
"files": [],
|
|
10
|
+
"include": [],
|
|
11
|
+
"references": [
|
|
12
|
+
{
|
|
13
|
+
"path": "./tsconfig.lib.json"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": "./tsconfig.spec.json"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"extends": "../../tsconfig.base.json"
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"types": [
|
|
7
|
+
"node",
|
|
8
|
+
"@nx/react/typings/cssmodule.d.ts",
|
|
9
|
+
"@nx/react/typings/image.d.ts",
|
|
10
|
+
"next",
|
|
11
|
+
"@nx/next/typings/image.d.ts"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"exclude": [
|
|
15
|
+
"jest.config.ts",
|
|
16
|
+
"src/**/*.spec.ts",
|
|
17
|
+
"src/**/*.test.ts",
|
|
18
|
+
"src/**/*.spec.tsx",
|
|
19
|
+
"src/**/*.test.tsx",
|
|
20
|
+
"src/**/*.spec.js",
|
|
21
|
+
"src/**/*.test.js",
|
|
22
|
+
"src/**/*.spec.jsx",
|
|
23
|
+
"src/**/*.test.jsx",
|
|
24
|
+
"**/*.stories.ts",
|
|
25
|
+
"**/*.stories.js"
|
|
26
|
+
],
|
|
27
|
+
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "../../dist/out-tsc",
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"moduleResolution": "node10",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"types": ["jest", "node"]
|
|
9
|
+
},
|
|
10
|
+
"include": [
|
|
11
|
+
"jest.config.ts",
|
|
12
|
+
"src/**/*.test.ts",
|
|
13
|
+
"src/**/*.spec.ts",
|
|
14
|
+
"src/**/*.test.tsx",
|
|
15
|
+
"src/**/*.spec.tsx",
|
|
16
|
+
"src/**/*.test.js",
|
|
17
|
+
"src/**/*.spec.js",
|
|
18
|
+
"src/**/*.test.jsx",
|
|
19
|
+
"src/**/*.spec.jsx",
|
|
20
|
+
"src/**/*.d.ts"
|
|
21
|
+
]
|
|
22
|
+
}
|