@alanszp/split 20.4.4 → 20.5.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.
@@ -0,0 +1,7 @@
1
+ // Used by Jest
2
+ module.exports = {
3
+ presets: [
4
+ ["@babel/preset-env", { targets: { node: "current" } }],
5
+ "@babel/preset-typescript",
6
+ ],
7
+ };
@@ -0,0 +1,56 @@
1
+ import { BuildDocumentInput, FeatureFlagDocument, FlagPositions, OrgBitmasks } from "./types";
2
+ /**
3
+ * Encode the set of ON flags of a single org into a base64 bitmask string,
4
+ * using the same scheme as the JWT permissions.
5
+ *
6
+ * Flags whose treatment is `false`, or whose code is not present in
7
+ * `positions`, are skipped: the document only encodes flags whose bit position
8
+ * is known. Because positions are an input, an org can be encoded in isolation,
9
+ * which is what allows the document to be assembled org-by-org / in chunks.
10
+ */
11
+ export declare function encodeOrg(treatments: Record<string, boolean>, positions: FlagPositions): string;
12
+ /**
13
+ * Assemble a {@link FeatureFlagDocument} from precomputed flag positions and an
14
+ * already-encoded map of org bitmasks, computing the canonical hash.
15
+ *
16
+ * Use this when org bitmasks are produced incrementally (e.g. streaming orgs
17
+ * from the DB in chunks and calling {@link encodeOrg} per org); accumulate the
18
+ * results into an {@link OrgBitmasks} map and finalize once at the end.
19
+ *
20
+ * @param flags precomputed flag-code => bit position map.
21
+ * @param orgs map from org reference to its base64-encoded bitmask.
22
+ */
23
+ export declare function finalizeDocument(flags: FlagPositions, orgs: OrgBitmasks): FeatureFlagDocument;
24
+ /**
25
+ * Build a {@link FeatureFlagDocument} from precomputed flag positions and a
26
+ * list of org treatments.
27
+ *
28
+ * Bit positions are NOT derived here: they are an explicit input. Computing
29
+ * them (by convention, ordering flag codes by descending ON-frequency so the
30
+ * most common flags get the low positions and bitmasks stay small) is the
31
+ * backend's responsibility and is expected to be done with a single DB query
32
+ * (e.g. a window function over the flag ON counts). Keeping positions external
33
+ * makes the codec independent of the full org set, so the document can be
34
+ * encoded org-by-org / in chunks instead of requiring every org in memory.
35
+ *
36
+ * If the same org reference appears more than once in `input`, the last
37
+ * occurrence wins (its bitmask overwrites the previous one). Since positions
38
+ * are an input, a duplicate org can no longer skew anything else in the
39
+ * document.
40
+ *
41
+ * @param flags precomputed flag-code => bit position map.
42
+ * @param input list of `{ org, treatments }` entries.
43
+ * @returns the full feature flag document.
44
+ */
45
+ export declare function buildDocument(flags: FlagPositions, input: BuildDocumentInput): FeatureFlagDocument;
46
+ /**
47
+ * Decode whether a single flag is ON for a single org in the document.
48
+ *
49
+ * Returns `false` if the flag is not present in `doc.flags` or the org is not
50
+ * present in `doc.orgs`.
51
+ *
52
+ * @param doc the feature flag document.
53
+ * @param org the org reference to look up.
54
+ * @param flagCode the flag code to check.
55
+ */
56
+ export declare function decodeFlagForOrg(doc: FeatureFlagDocument, org: string, flagCode: string): boolean;
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeOrg = encodeOrg;
4
+ exports.finalizeDocument = finalizeDocument;
5
+ exports.buildDocument = buildDocument;
6
+ exports.decodeFlagForOrg = decodeFlagForOrg;
7
+ const node_crypto_1 = require("node:crypto");
8
+ const bitmask_1 = require("@alanszp/bitmask");
9
+ /**
10
+ * Encode the set of ON flags of a single org into a base64 bitmask string,
11
+ * using the same scheme as the JWT permissions.
12
+ *
13
+ * Flags whose treatment is `false`, or whose code is not present in
14
+ * `positions`, are skipped: the document only encodes flags whose bit position
15
+ * is known. Because positions are an input, an org can be encoded in isolation,
16
+ * which is what allows the document to be assembled org-by-org / in chunks.
17
+ */
18
+ function encodeOrg(treatments, positions) {
19
+ const bitmasks = [];
20
+ for (const [flagCode, isOn] of Object.entries(treatments)) {
21
+ if (!isOn) {
22
+ continue;
23
+ }
24
+ const position = positions[flagCode];
25
+ if (position === undefined) {
26
+ continue;
27
+ }
28
+ bitmasks.push(bitmask_1.BitmaskUtils.encodeFromPosition(position));
29
+ }
30
+ const combined = bitmask_1.BitmaskUtils.combineBitmasks(bitmasks);
31
+ return bitmask_1.BitmaskUtils.encodeToBase64(combined);
32
+ }
33
+ /**
34
+ * Serialize `flags` + `orgs` into a canonical, deterministic string with sorted
35
+ * keys, so that the same logical content always yields the same hash regardless
36
+ * of insertion order. The hash itself is never part of this serialization.
37
+ */
38
+ function canonicalContent(flags, orgs) {
39
+ const sortKeys = (obj) => {
40
+ const out = {};
41
+ for (const key of Object.keys(obj).sort()) {
42
+ out[key] = obj[key];
43
+ }
44
+ return out;
45
+ };
46
+ return JSON.stringify({
47
+ flags: sortKeys(flags),
48
+ orgs: sortKeys(orgs),
49
+ });
50
+ }
51
+ /**
52
+ * Compute the sha256 (hex) of the canonical content.
53
+ */
54
+ function hashContent(flags, orgs) {
55
+ return (0, node_crypto_1.createHash)("sha256")
56
+ .update(canonicalContent(flags, orgs))
57
+ .digest("hex");
58
+ }
59
+ /**
60
+ * Assemble a {@link FeatureFlagDocument} from precomputed flag positions and an
61
+ * already-encoded map of org bitmasks, computing the canonical hash.
62
+ *
63
+ * Use this when org bitmasks are produced incrementally (e.g. streaming orgs
64
+ * from the DB in chunks and calling {@link encodeOrg} per org); accumulate the
65
+ * results into an {@link OrgBitmasks} map and finalize once at the end.
66
+ *
67
+ * @param flags precomputed flag-code => bit position map.
68
+ * @param orgs map from org reference to its base64-encoded bitmask.
69
+ */
70
+ function finalizeDocument(flags, orgs) {
71
+ return { hash: hashContent(flags, orgs), flags, orgs };
72
+ }
73
+ /**
74
+ * Build a {@link FeatureFlagDocument} from precomputed flag positions and a
75
+ * list of org treatments.
76
+ *
77
+ * Bit positions are NOT derived here: they are an explicit input. Computing
78
+ * them (by convention, ordering flag codes by descending ON-frequency so the
79
+ * most common flags get the low positions and bitmasks stay small) is the
80
+ * backend's responsibility and is expected to be done with a single DB query
81
+ * (e.g. a window function over the flag ON counts). Keeping positions external
82
+ * makes the codec independent of the full org set, so the document can be
83
+ * encoded org-by-org / in chunks instead of requiring every org in memory.
84
+ *
85
+ * If the same org reference appears more than once in `input`, the last
86
+ * occurrence wins (its bitmask overwrites the previous one). Since positions
87
+ * are an input, a duplicate org can no longer skew anything else in the
88
+ * document.
89
+ *
90
+ * @param flags precomputed flag-code => bit position map.
91
+ * @param input list of `{ org, treatments }` entries.
92
+ * @returns the full feature flag document.
93
+ */
94
+ function buildDocument(flags, input) {
95
+ const orgs = {};
96
+ for (const { org, treatments } of input) {
97
+ orgs[org] = encodeOrg(treatments, flags);
98
+ }
99
+ return finalizeDocument(flags, orgs);
100
+ }
101
+ /**
102
+ * Decode whether a single flag is ON for a single org in the document.
103
+ *
104
+ * Returns `false` if the flag is not present in `doc.flags` or the org is not
105
+ * present in `doc.orgs`.
106
+ *
107
+ * @param doc the feature flag document.
108
+ * @param org the org reference to look up.
109
+ * @param flagCode the flag code to check.
110
+ */
111
+ function decodeFlagForOrg(doc, org, flagCode) {
112
+ const position = doc.flags[flagCode];
113
+ if (position === undefined) {
114
+ return false;
115
+ }
116
+ const encoded = doc.orgs[org];
117
+ if (encoded === undefined) {
118
+ return false;
119
+ }
120
+ const bitmask = bitmask_1.BitmaskUtils.decodeFromBase64(encoded);
121
+ const check = bitmask_1.BitmaskUtils.encodeFromPosition(position);
122
+ return bitmask_1.BitmaskUtils.checkBitmask(bitmask, check);
123
+ }
124
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/document/codec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const bitmask_1 = require("@alanszp/bitmask");
4
+ const codec_1 = require("./codec");
5
+ describe("feature flag document codec", () => {
6
+ describe("encodeOrg", () => {
7
+ it("encodes only ON flags whose position is known", () => {
8
+ const positions = { a: 0, b: 1, c: 2 };
9
+ // a ON (pos 0 => bit 1), c ON (pos 2 => bit 4) => 0b101 = 5.
10
+ const encoded = (0, codec_1.encodeOrg)({ a: true, b: false, c: true }, positions);
11
+ expect(encoded).toBe(bitmask_1.BitmaskUtils.encodeToBase64(BigInt(5)));
12
+ });
13
+ it("skips flags missing from the positions map", () => {
14
+ const positions = { a: 0 };
15
+ // `unknown` has no position => ignored; only a (bit 1) is set.
16
+ const encoded = (0, codec_1.encodeOrg)({ a: true, unknown: true }, positions);
17
+ expect(encoded).toBe(bitmask_1.BitmaskUtils.encodeToBase64(BigInt(1)));
18
+ });
19
+ it("produces a small string when only low positions are set", () => {
20
+ const positions = { f0: 0, f1: 1, f2: 2, f3: 3, f4: 4 };
21
+ const common = (0, codec_1.encodeOrg)({ f0: true }, positions);
22
+ const rare = (0, codec_1.encodeOrg)({ f0: true, f1: true, f2: true, f3: true, f4: true }, positions);
23
+ expect(common).toBe(bitmask_1.BitmaskUtils.encodeToBase64(BigInt(1)));
24
+ expect(common.length).toBeLessThanOrEqual(rare.length);
25
+ });
26
+ });
27
+ describe("buildDocument", () => {
28
+ const positions = { a: 0, b: 1, c: 2 };
29
+ it("uses the positions it is given verbatim (does not derive them)", () => {
30
+ const doc = (0, codec_1.buildDocument)(positions, [
31
+ { org: "o1", treatments: { a: true } },
32
+ ]);
33
+ expect(doc.flags).toBe(positions);
34
+ });
35
+ it("round-trips every flag for every org back to its treatment", () => {
36
+ const input = [
37
+ { org: "o1", treatments: { a: true, b: false, c: true } },
38
+ { org: "o2", treatments: { a: false, b: true, c: false } },
39
+ { org: "o3", treatments: { a: true, b: true, c: true } },
40
+ ];
41
+ const doc = (0, codec_1.buildDocument)(positions, input);
42
+ for (const { org, treatments } of input) {
43
+ for (const [flagCode, expected] of Object.entries(treatments)) {
44
+ expect((0, codec_1.decodeFlagForOrg)(doc, org, flagCode)).toBe(expected);
45
+ }
46
+ }
47
+ });
48
+ it("handles an org with no flags ON (empty bitmask)", () => {
49
+ const doc = (0, codec_1.buildDocument)(positions, [
50
+ { org: "empty", treatments: { a: false, b: false } },
51
+ { org: "full", treatments: { a: true, b: true } },
52
+ ]);
53
+ expect((0, codec_1.decodeFlagForOrg)(doc, "empty", "a")).toBe(false);
54
+ expect((0, codec_1.decodeFlagForOrg)(doc, "empty", "b")).toBe(false);
55
+ expect((0, codec_1.decodeFlagForOrg)(doc, "full", "a")).toBe(true);
56
+ expect((0, codec_1.decodeFlagForOrg)(doc, "full", "b")).toBe(true);
57
+ });
58
+ it("handles many flags / high positions correctly", () => {
59
+ const treatments = {};
60
+ const manyPositions = {};
61
+ for (let i = 0; i < 40; i++) {
62
+ manyPositions[`flag${i}`] = i;
63
+ treatments[`flag${i}`] = i % 2 === 0;
64
+ }
65
+ const doc = (0, codec_1.buildDocument)(manyPositions, [{ org: "o1", treatments }]);
66
+ for (const [flagCode, expected] of Object.entries(treatments)) {
67
+ expect((0, codec_1.decodeFlagForOrg)(doc, "o1", flagCode)).toBe(expected);
68
+ }
69
+ });
70
+ it("last occurrence wins when the same org appears twice", () => {
71
+ const doc = (0, codec_1.buildDocument)(positions, [
72
+ { org: "dup", treatments: { a: true, b: true } },
73
+ { org: "dup", treatments: { a: false, b: false } },
74
+ ]);
75
+ // Only the last entry is reflected; nothing else is skewed.
76
+ expect((0, codec_1.decodeFlagForOrg)(doc, "dup", "a")).toBe(false);
77
+ expect((0, codec_1.decodeFlagForOrg)(doc, "dup", "b")).toBe(false);
78
+ expect(Object.keys(doc.orgs)).toEqual(["dup"]);
79
+ });
80
+ });
81
+ describe("chunked assembly via encodeOrg + finalizeDocument", () => {
82
+ it("equals the single-shot buildDocument result", () => {
83
+ const positions = { a: 0, b: 1, c: 2 };
84
+ const input = [
85
+ { org: "o1", treatments: { a: true, b: false, c: true } },
86
+ { org: "o2", treatments: { a: false, b: true, c: false } },
87
+ ];
88
+ const oneShot = (0, codec_1.buildDocument)(positions, input);
89
+ // Simulate streaming orgs in separate chunks, encoding each on its own.
90
+ const orgs = {};
91
+ for (const { org, treatments } of input) {
92
+ orgs[org] = (0, codec_1.encodeOrg)(treatments, positions);
93
+ }
94
+ const chunked = (0, codec_1.finalizeDocument)(positions, orgs);
95
+ expect(chunked).toEqual(oneShot);
96
+ expect(chunked.hash).toBe(oneShot.hash);
97
+ });
98
+ });
99
+ describe("decodeFlagForOrg with missing entries", () => {
100
+ const doc = (0, codec_1.buildDocument)({ a: 0, b: 1 }, [{ org: "o1", treatments: { a: true, b: false } }]);
101
+ it("returns false for an unknown flag code", () => {
102
+ expect((0, codec_1.decodeFlagForOrg)(doc, "o1", "doesNotExist")).toBe(false);
103
+ });
104
+ it("returns false for an unknown org", () => {
105
+ expect((0, codec_1.decodeFlagForOrg)(doc, "unknownOrg", "a")).toBe(false);
106
+ });
107
+ it("returns false for an OFF flag", () => {
108
+ expect((0, codec_1.decodeFlagForOrg)(doc, "o1", "b")).toBe(false);
109
+ });
110
+ });
111
+ describe("hash", () => {
112
+ const positions = { x: 0, y: 1 };
113
+ it("is a 64-char hex sha256 string", () => {
114
+ const doc = (0, codec_1.buildDocument)(positions, [
115
+ { org: "o1", treatments: { x: true } },
116
+ ]);
117
+ expect(doc.hash).toMatch(/^[0-9a-f]{64}$/);
118
+ });
119
+ it("is deterministic regardless of org/flag insertion order", () => {
120
+ const a = (0, codec_1.buildDocument)({ x: 0, y: 1 }, [
121
+ { org: "o1", treatments: { x: true, y: false } },
122
+ { org: "o2", treatments: { x: false, y: true } },
123
+ ]);
124
+ const b = (0, codec_1.buildDocument)({ y: 1, x: 0 }, [
125
+ { org: "o2", treatments: { y: true, x: false } },
126
+ { org: "o1", treatments: { y: false, x: true } },
127
+ ]);
128
+ expect(a.flags).toEqual(b.flags);
129
+ expect(a.orgs).toEqual(b.orgs);
130
+ expect(a.hash).toBe(b.hash);
131
+ });
132
+ it("changes when content changes", () => {
133
+ const a = (0, codec_1.buildDocument)(positions, [
134
+ { org: "o1", treatments: { x: true } },
135
+ ]);
136
+ const b = (0, codec_1.buildDocument)(positions, [
137
+ { org: "o1", treatments: { x: false } },
138
+ ]);
139
+ expect(a.hash).not.toBe(b.hash);
140
+ });
141
+ });
142
+ });
143
+ //# sourceMappingURL=codec.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.test.js","sourceRoot":"","sources":["../../src/document/codec.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from "./types";
2
+ export * from "./codec";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./types"), exports);
18
+ __exportStar(require("./codec"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/document/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,0CAAwB"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Feature flag document types.
3
+ *
4
+ * The document is a deterministic, self-contained snapshot of which feature
5
+ * flags are ON for which orgs. It is meant to be serialized (e.g. to S3) and
6
+ * decoded by clients without needing to talk to Split.io.
7
+ *
8
+ * Encoding scheme (mirrors the JWT permissions scheme):
9
+ * - Each flag is assigned a bit `position` (see {@link FlagPositions}).
10
+ * - For each org, the set of ON flags is turned into a bitmask by OR-ing
11
+ * `1 << position` for every ON flag, and that bigint is base64-encoded using
12
+ * `@alanszp/bitmask`.
13
+ * - Positions are an INPUT to the codec, not derived by it. By convention the
14
+ * backend assigns them by descending ON-frequency (the flag that is ON for
15
+ * the most orgs gets position 0), computed with a single DB query. This keeps
16
+ * the BigInt magnitude (and thus the encoded strings) small, because the most
17
+ * common bits live in the low positions and orgs that only have rare flags
18
+ * get short strings. Keeping positions external lets the document be encoded
19
+ * org-by-org / in chunks instead of requiring every org in memory at once.
20
+ */
21
+ /**
22
+ * Map from flag code to its assigned bit position (0-based).
23
+ */
24
+ export type FlagPositions = Record<string, number>;
25
+ /**
26
+ * Map from org reference to the base64-encoded bitmask of its ON flags.
27
+ */
28
+ export type OrgBitmasks = Record<string, string>;
29
+ /**
30
+ * The full feature flag document.
31
+ */
32
+ export interface FeatureFlagDocument {
33
+ /**
34
+ * sha256 (hex) of the canonical, deterministic serialization of `flags` +
35
+ * `orgs`. Does NOT include itself in the computation.
36
+ */
37
+ hash: string;
38
+ /**
39
+ * Map from flag code to its bit position. Positions are computed by the
40
+ * backend (by convention, descending ON-frequency => most-ON flag gets
41
+ * position 0) and fed into the codec as an input.
42
+ */
43
+ flags: FlagPositions;
44
+ /**
45
+ * Map from org reference to its base64-encoded ON-flags bitmask.
46
+ */
47
+ orgs: OrgBitmasks;
48
+ }
49
+ /**
50
+ * Input entry for {@link buildDocument}: one org and the on/off treatment of
51
+ * each flag for that org. Flags whose treatment is `false` (or missing) are
52
+ * considered OFF.
53
+ */
54
+ export interface OrgTreatments {
55
+ /** Org reference. */
56
+ org: string;
57
+ /** Map from flag code to whether the flag is ON for this org. */
58
+ treatments: Record<string, boolean>;
59
+ }
60
+ /**
61
+ * Full input for {@link buildDocument}.
62
+ */
63
+ export type BuildDocumentInput = OrgTreatments[];
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ /**
3
+ * Feature flag document types.
4
+ *
5
+ * The document is a deterministic, self-contained snapshot of which feature
6
+ * flags are ON for which orgs. It is meant to be serialized (e.g. to S3) and
7
+ * decoded by clients without needing to talk to Split.io.
8
+ *
9
+ * Encoding scheme (mirrors the JWT permissions scheme):
10
+ * - Each flag is assigned a bit `position` (see {@link FlagPositions}).
11
+ * - For each org, the set of ON flags is turned into a bitmask by OR-ing
12
+ * `1 << position` for every ON flag, and that bigint is base64-encoded using
13
+ * `@alanszp/bitmask`.
14
+ * - Positions are an INPUT to the codec, not derived by it. By convention the
15
+ * backend assigns them by descending ON-frequency (the flag that is ON for
16
+ * the most orgs gets position 0), computed with a single DB query. This keeps
17
+ * the BigInt magnitude (and thus the encoded strings) small, because the most
18
+ * common bits live in the low positions and orgs that only have rare flags
19
+ * get short strings. Keeping positions external lets the document be encoded
20
+ * org-by-org / in chunks instead of requiring every org in memory at once.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/document/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from "./client";
2
+ export * from "./document";
package/dist/index.js CHANGED
@@ -16,4 +16,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  // Adding dummy code to deploy package
18
18
  __exportStar(require("./client"), exports);
19
+ __exportStar(require("./document"), exports);
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sCAAsC;AACtC,2CAAyB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,sCAAsC;AACtC,2CAAyB;AACzB,6CAA2B"}
package/jest.config.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}"],
3
+ roots: ["<rootDir>/src/"],
4
+ clearMocks: true,
5
+ resetMocks: true,
6
+ testEnvironment: "node",
7
+ moduleNameMapper: {
8
+ "@/(.*)": "<rootDir>/src/$1",
9
+ },
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alanszp/split",
3
- "version": "20.4.4",
3
+ "version": "20.5.0",
4
4
  "description": "Alan's split client",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -13,26 +13,34 @@
13
13
  "compile-watch": "tsc -w",
14
14
  "build": "pnpm run compile",
15
15
  "prepack": "pnpm run build",
16
+ "test": "TZ=Etc/UTC jest",
16
17
  "yalc-publish": "pnpm run yalc publish"
17
18
  },
18
19
  "peerDependencies": {
19
20
  "@alanszp/logger": "*"
20
21
  },
21
22
  "devDependencies": {
22
- "@alanszp/logger": "^20.4.4",
23
+ "@alanszp/logger": "^20.5.0",
24
+ "@babel/core": "^7.24.0",
25
+ "@babel/preset-env": "^7.29.5",
26
+ "@babel/preset-typescript": "^7.23.3",
27
+ "@types/jest": "^29.5.12",
23
28
  "@types/lodash": "^4.14.170",
24
29
  "@types/node": "^24.0.0",
30
+ "babel-jest": "^29.7.0",
31
+ "jest": "^29.7.0",
25
32
  "ts-node": "^10.0.0",
26
33
  "tslint": "^6.1.3",
27
34
  "typescript": "^5.9.3"
28
35
  },
29
36
  "dependencies": {
30
- "@alanszp/core": "^20.4.4",
31
- "@alanszp/shared-context": "^20.4.4",
32
- "@alanszp/typeorm": "^20.4.4",
37
+ "@alanszp/bitmask": "^20.5.0",
38
+ "@alanszp/core": "^20.5.0",
39
+ "@alanszp/shared-context": "^20.5.0",
40
+ "@alanszp/typeorm": "^20.5.0",
33
41
  "@splitsoftware/splitio": "^10.25.1",
34
42
  "ioredis": "^5.9.3",
35
43
  "lodash": "^4.17.23"
36
44
  },
37
- "gitHead": "113b57dc0fa86390b1b9ea9bdd9bc219825544f4"
45
+ "gitHead": "db82dba6b9d0976f56b256be6d552131b44217f6"
38
46
  }
package/tsconfig.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "outDir": "dist",
5
5
  "module": "commonjs",
6
6
  "target": "es6",
7
- "types": ["node"],
7
+ "types": ["jest", "node"],
8
8
  "esModuleInterop": true,
9
9
  "sourceMap": true,
10
10