@forge/feature-flags-node 1.1.3-next.0-experimental-6a5594a → 1.1.3

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/CHANGELOG.md CHANGED
@@ -1,15 +1,11 @@
1
1
  # @forge/feature-flags-node
2
2
 
3
- ## 1.1.3-next.0-experimental-6a5594a
4
-
5
- ### Major Changes
6
-
7
- - 6a5594a: Added new identifiers for targeting
3
+ ## 1.1.3
8
4
 
9
5
  ### Patch Changes
10
6
 
11
7
  - Updated dependencies [504cd62]
12
- - @forge/api@6.1.2-next.0-experimental-6a5594a
8
+ - @forge/api@6.1.2
13
9
 
14
10
  ## 1.1.3-next.0
15
11
 
package/README.md CHANGED
@@ -22,15 +22,13 @@ export const handler = async (payload, context) => {
22
22
  // Initialize the feature flags service
23
23
  const featureFlags = new ForgeFeatureFlags();
24
24
  await featureFlags.initialize({
25
- environment: environmentType?.toLowerCase() || "development"
25
+ environment: environmentType?.toLowerCase() || "development" // Optional, defaults to 'development'
26
26
  });
27
27
 
28
28
  // Define a user
29
29
  const user = {
30
- identifiers:{
31
- accountId: context?.principal?.accountId,
32
- },
33
- attributes: {
30
+ userID: context?.principal?.accountId,
31
+ custom: {
34
32
  license: context?.license?.isActive
35
33
  }
36
34
  };
@@ -64,16 +62,6 @@ export const handler = async (payload, context) => {
64
62
  environment: getAppContext().environmentType?.toLowerCase() || "development"
65
63
  });
66
64
 
67
- // Define a user
68
- const user = {
69
- identifiers:{
70
- installContext: context?.installContext,
71
- },
72
- custom: {
73
- issues: 4
74
- }
75
- };
76
-
77
65
  // Use feature flags...
78
66
  const isEnabled = featureFlags.checkFlag(user, "new-feature");
79
67
 
@@ -144,12 +132,8 @@ Checks if the service is initialized.
144
132
 
145
133
  ```typescript
146
134
  interface ForgeUser {
147
- identifiers?: {
148
- installContext?: string;
149
- accountId?: string;
150
- };
135
+ userID: string;
151
136
  custom?: Record<string, string | number | boolean>;
152
- attributes?: Record<string, string | number | boolean>;
153
137
  }
154
138
  ```
155
139
 
@@ -3,8 +3,6 @@ export declare class ForgeDataAdapter implements IDataAdapter {
3
3
  private readonly pollingIntervalMs;
4
4
  private readonly pollingEnabled;
5
5
  private readonly cache;
6
- private metrics;
7
- private tags;
8
6
  constructor(pollingIntervalMs?: number, pollingEnabled?: boolean);
9
7
  get(key: string): Promise<AdapterResponse>;
10
8
  private fetchFromAtlassianServers;
@@ -1 +1 @@
1
- {"version":3,"file":"data-adapter.d.ts","sourceRoot":"","sources":["../src/data-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAM7D,qBAAa,gBAAiB,YAAW,YAAY;IASjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc;IATjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,OAAO,CAAgE;IAC/E,OAAO,CAAC,IAAI,CAGV;gBAGiB,iBAAiB,GAAE,MAAc,EACjC,cAAc,GAAE,OAAc;IAM3C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;YAoDlC,yBAAyB;IAuCjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IA8B/C,oBAAoB,IAAI,MAAM;CAG/B"}
1
+ {"version":3,"file":"data-adapter.d.ts","sourceRoot":"","sources":["../src/data-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAK7D,qBAAa,gBAAiB,YAAW,YAAY;IAIjD,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAJjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;gBAGrC,iBAAiB,GAAE,MAAc,EACjC,cAAc,GAAE,OAAc;IAM3C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;YA+ClC,yBAAyB;IAiCjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU9C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ/B,yBAAyB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IA8B/C,oBAAoB,IAAI,MAAM;CAG/B"}
@@ -6,23 +6,16 @@ class ForgeDataAdapter {
6
6
  pollingIntervalMs;
7
7
  pollingEnabled;
8
8
  cache = new Map();
9
- metrics = (0, api_1.__getRuntime)()?.metrics;
10
- tags = {
11
- environment: (0, api_1.__getRuntime)()?.appContext?.environmentType || 'unknown',
12
- appId: (0, api_1.__getRuntime)()?.appContext?.appId || 'unknown'
13
- };
14
9
  constructor(pollingIntervalMs = 60000, pollingEnabled = true) {
15
10
  this.pollingIntervalMs = pollingIntervalMs;
16
11
  this.pollingEnabled = pollingEnabled;
17
12
  }
18
13
  async get(key) {
19
14
  try {
20
- this.metrics?.counter('forge.feature-flags.data-adapter.get', this.tags).incr();
21
15
  const data = await this.fetchFromAtlassianServers();
22
16
  if (data) {
23
17
  const serializedData = JSON.stringify(data);
24
18
  this.cache.set(key, serializedData);
25
- this.metrics?.counter('forge.feature-flags.data-adapter.get.success', this.tags).incr();
26
19
  return {
27
20
  result: serializedData,
28
21
  time: Date.now()
@@ -30,23 +23,19 @@ class ForgeDataAdapter {
30
23
  }
31
24
  const cachedValue = this.cache.get(key);
32
25
  if (cachedValue) {
33
- this.metrics?.counter('forge.feature-flags.data-adapter.get.cached', this.tags).incr();
34
26
  return {
35
27
  result: cachedValue,
36
28
  time: Date.now()
37
29
  };
38
30
  }
39
- this.metrics?.counter('forge.feature-flags.data-adapter.get.empty', this.tags).incr();
40
31
  return {
41
32
  result: undefined,
42
33
  time: Date.now()
43
34
  };
44
35
  }
45
36
  catch {
46
- this.metrics?.counter('forge.feature-flags.data-adapter.get.failure', this.tags).incr();
47
37
  const cachedValue = this.cache.get(key);
48
38
  if (cachedValue) {
49
- this.metrics?.counter('forge.feature-flags.data-adapter.get.cached', this.tags).incr();
50
39
  return {
51
40
  result: cachedValue,
52
41
  time: Date.now()
@@ -60,17 +49,11 @@ class ForgeDataAdapter {
60
49
  }
61
50
  async fetchFromAtlassianServers() {
62
51
  const runtime = (0, api_1.__getRuntime)();
63
- if (runtime?.proxy?.tokenExpiry && runtime?.proxy?.tokenExpiry * 1000 < Date.now()) {
64
- this.metrics
65
- ?.counter('forge.feature-flags.data-adapter.fetchFromAtlassianServers.tokenExpired', this.tags)
66
- .incr();
52
+ if (runtime.proxy?.tokenExpiry && runtime.proxy.tokenExpiry * 1000 < Date.now()) {
67
53
  return null;
68
54
  }
69
- const remainingTime = runtime?.lambdaContext?.getRemainingTimeInMillis?.();
55
+ const remainingTime = runtime.lambdaContext?.getRemainingTimeInMillis?.();
70
56
  if (remainingTime !== undefined && remainingTime < 5000) {
71
- this.metrics
72
- ?.counter('forge.feature-flags.data-adapter.fetchFromAtlassianServers.remainingTimeComplete', this.tags)
73
- .incr();
74
57
  return null;
75
58
  }
76
59
  const response = await (0, api_1.__fetchProduct)({ provider: 'app', remote: 'feature-flags', type: 'feature-flags' })('/', {
@@ -101,10 +84,10 @@ class ForgeDataAdapter {
101
84
  }
102
85
  try {
103
86
  const runtime = (0, api_1.__getRuntime)();
104
- if (runtime?.proxy?.tokenExpiry && runtime?.proxy?.tokenExpiry * 1000 < Date.now()) {
87
+ if (runtime.proxy?.tokenExpiry && runtime.proxy.tokenExpiry * 1000 < Date.now()) {
105
88
  return false;
106
89
  }
107
- const remainingTime = runtime?.lambdaContext?.getRemainingTimeInMillis?.();
90
+ const remainingTime = runtime.lambdaContext?.getRemainingTimeInMillis?.();
108
91
  if (remainingTime !== undefined && remainingTime < 10000) {
109
92
  return false;
110
93
  }
package/out/index.d.ts CHANGED
@@ -2,33 +2,12 @@ export interface ForgeFeatureFlagConfig {
2
2
  environment?: 'development' | 'staging' | 'production';
3
3
  }
4
4
  export interface ForgeUser {
5
- userID?: string;
5
+ userID: string;
6
6
  custom?: Record<string, string | number | boolean>;
7
- attributes?: Record<string, string | number | boolean>;
8
- identifiers?: {
9
- installContext?: string;
10
- accountId?: string;
11
- };
12
- }
13
- export interface Counter {
14
- incr(): void;
15
- decr(): void;
16
- }
17
- export interface TimerStop {
18
- stop(): void;
19
- }
20
- export interface Timer {
21
- measure(): TimerStop;
22
- }
23
- export interface Metrics {
24
- counter(name: string, tags?: Record<string, string>): Counter;
25
- timing(name: string, tags?: Record<string, string>): Timer;
26
7
  }
27
8
  export declare class ForgeFeatureFlags {
28
9
  private initialized;
29
10
  private dataAdapter;
30
- private metrics;
31
- private tags;
32
11
  initialize(config?: ForgeFeatureFlagConfig): Promise<void>;
33
12
  checkFlag(user: ForgeUser, flagName: string): boolean;
34
13
  getFeatureFlags(user: ForgeUser, flagNames: string[]): Record<string, boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;CACxD;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IACvD,WAAW,CAAC,EAAE;QACZ,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,IAAI,IAAI,CAAC;IACb,IAAI,IAAI,IAAI,CAAC;CACd;AACD,MAAM,WAAW,SAAS;IACxB,IAAI,IAAI,IAAI,CAAC;CACd;AACD,MAAM,WAAW,KAAK;IACpB,OAAO,IAAI,SAAS,CAAC;CACtB;AACD,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;IAC9D,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;CAC5D;AAKD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,IAAI,CAGV;IAIW,UAAU,CAAC,MAAM,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;IAsCpE,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IASrD,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAexE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAe/B,aAAa,IAAI,OAAO;IAI/B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,WAAW;CAOpB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB;IACrC,WAAW,CAAC,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;CACxD;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CACpD;AAKD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAiC;IAKvC,UAAU,CAAC,MAAM,GAAE,sBAA2B,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BpE,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAQrD,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAcxE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAe/B,aAAa,IAAI,OAAO;IAI/B,OAAO,CAAC,iBAAiB;IAMzB,OAAO,CAAC,WAAW;CAMpB"}
package/out/index.js CHANGED
@@ -4,54 +4,35 @@ exports.ForgeFeatureFlags = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const statsig_node_1 = tslib_1.__importDefault(require("statsig-node"));
6
6
  const data_adapter_1 = require("./data-adapter");
7
- const api_1 = require("@forge/api");
8
7
  class ForgeFeatureFlags {
9
8
  initialized = false;
10
9
  dataAdapter = null;
11
- metrics = (0, api_1.__getRuntime)()?.metrics;
12
- tags = {
13
- environment: (0, api_1.__getRuntime)()?.appContext?.environmentType || 'unknown',
14
- appId: (0, api_1.__getRuntime)()?.appContext?.appId || 'unknown'
15
- };
16
10
  async initialize(config = {}) {
17
11
  if (this.initialized) {
18
12
  return;
19
13
  }
20
- this.metrics?.counter('forge.feature-flags.initialize', this.tags).incr();
21
- const timer = this.metrics?.timing('forge.feature-flags.initialize', this.tags).measure();
22
14
  try {
23
15
  statsig_node_1.default.shutdown();
24
16
  }
25
17
  catch { }
26
- const remainingTime = (0, api_1.__getRuntime)()?.lambdaContext?.getRemainingTimeInMillis?.();
27
- const disableRulesetsSync = remainingTime && remainingTime < 60000 ? true : false;
28
- if (disableRulesetsSync) {
29
- this.metrics?.counter('forge.feature-flags.disableRulesetsSync', this.tags).incr();
30
- }
31
18
  this.dataAdapter = new data_adapter_1.ForgeDataAdapter(60000, true);
32
19
  const statsigOptions = {
33
20
  environment: { tier: config.environment || 'development' },
34
- disableRulesetsSync: disableRulesetsSync,
21
+ disableRulesetsSync: false,
35
22
  disableIdListsSync: true,
36
23
  initTimeoutMs: 3000,
37
24
  localMode: true,
38
- disableAllLogging: true,
39
- disableDiagnostics: true,
40
25
  dataAdapter: this.dataAdapter
41
26
  };
42
- await statsig_node_1.default.initialize('secret-forge-internal-key', statsigOptions);
27
+ await statsig_node_1.default.initialize('forge-internal-key', statsigOptions);
43
28
  this.initialized = true;
44
- timer?.stop();
45
- this.metrics?.counter('forge.feature-flags.initialize.success', this.tags).incr();
46
29
  }
47
30
  checkFlag(user, flagName) {
48
31
  this.ensureInitialized();
49
- this.metrics?.counter('forge.feature-flags.checkFlag', this.tags).incr();
50
32
  return statsig_node_1.default.checkGate(this.convertUser(user), flagName);
51
33
  }
52
34
  getFeatureFlags(user, flagNames) {
53
35
  this.ensureInitialized();
54
- this.metrics?.counter('forge.feature-flags.getFeatureFlags', this.tags).incr();
55
36
  const results = {};
56
37
  for (const flagName of flagNames) {
57
38
  results[flagName] = statsig_node_1.default.checkGate(this.convertUser(user), flagName);
@@ -67,7 +48,6 @@ class ForgeFeatureFlags {
67
48
  await this.dataAdapter.shutdown();
68
49
  }
69
50
  this.initialized = false;
70
- this.metrics?.counter('forge.feature-flags.shutdown', this.tags).incr();
71
51
  }
72
52
  isInitialized() {
73
53
  return this.initialized;
@@ -80,8 +60,7 @@ class ForgeFeatureFlags {
80
60
  convertUser(user) {
81
61
  return {
82
62
  userID: user.userID,
83
- custom: { ...(user.custom || {}), ...(user.attributes || {}) },
84
- customIDs: user.identifiers || {}
63
+ custom: user.custom
85
64
  };
86
65
  }
87
66
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/feature-flags-node",
3
- "version": "1.1.3-next.0-experimental-6a5594a",
3
+ "version": "1.1.3",
4
4
  "description": "Feature Flags Node SDK for Atlassian Forge apps running on Node Runtime",
5
5
  "author": "Atlassian",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -15,7 +15,7 @@
15
15
  "@types/node": "20.19.1"
16
16
  },
17
17
  "dependencies": {
18
- "@forge/api": "^6.1.2-next.0-experimental-6a5594a",
18
+ "@forge/api": "^6.1.2",
19
19
  "statsig-node": "^6.4.3"
20
20
  },
21
21
  "publishConfig": {