Skip to content

Commit e4075b2

Browse files
Add support for internal conditional matching (#1913)
* Add support for internal conditional matching * Bundle bump
1 parent 722d45c commit e4075b2

File tree

5 files changed

+217
-2
lines changed

5 files changed

+217
-2
lines changed

injected/docs/platform-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ The following placeholders are replaced during the build process:
6464
- **`$CONTENT_SCOPE$`** - Raw remote config object
6565
- **`$USER_UNPROTECTED_DOMAINS$`** - An array of user allowlisted domains
6666
- **`$USER_PREFERENCES$`** - An object containing:
67-
- `platform`: `{ name: '<ios | macos | extension | android>' }`
67+
- `platform`: `{ name: '<ios | macos | extension | android | windows>', internal: <boolean> }`
6868
- `debug`: boolean
6969
- `globalPrivacyControlValue`: boolean
7070
- `sessionKey`: `<CSRNG UUID 4 string>` (used for fingerprinting) - this should regenerate on browser close or every 24 hours

injected/src/config-feature.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export default class ConfigFeature {
133133
* @property {boolean} [context.frame] - true if the condition applies to frames
134134
* @property {boolean} [context.top] - true if the condition applies to the top frame
135135
* @property {string} [injectName] - the inject name to match against (e.g., "apple-isolated")
136+
* @property {boolean} [internal] - true if the condition applies to internal builds
136137
*/
137138

138139
/**
@@ -164,6 +165,7 @@ export default class ConfigFeature {
164165
minSupportedVersion: this._matchMinSupportedVersion,
165166
maxSupportedVersion: this._matchMaxSupportedVersion,
166167
injectName: this._matchInjectNameConditional,
168+
internal: this._matchInternalConditional,
167169
};
168170

169171
for (const key in conditionBlock) {
@@ -287,6 +289,18 @@ export default class ConfigFeature {
287289
return conditionBlock.injectName === currentInjectName;
288290
}
289291

292+
/**
293+
* Takes a condition block and returns true if the internal state matches the condition.
294+
* @param {ConditionBlock} conditionBlock
295+
* @returns {boolean}
296+
*/
297+
_matchInternalConditional(conditionBlock) {
298+
if (conditionBlock.internal === undefined) return false;
299+
const isInternal = this.#args?.platform?.internal;
300+
if (isInternal === undefined) return false;
301+
return Boolean(conditionBlock.internal) === Boolean(isInternal);
302+
}
303+
290304
/**
291305
* Takes a condition block and returns true if the platform version satisfies the `minSupportedFeature`
292306
* @param {ConditionBlock} conditionBlock

injected/src/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ export function isUnprotectedDomain(topLevelHostname, featureList) {
561561
* @typedef {object} Platform
562562
* @property {'ios' | 'macos' | 'extension' | 'android' | 'windows'} name
563563
* @property {string | number } [version]
564+
* @property {boolean} [internal] - Internal build flag
564565
*/
565566

566567
/**

injected/unit-test/content-feature.js

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,4 +790,204 @@ describe('ContentFeature class', () => {
790790
expect(result).toBe(false);
791791
});
792792
});
793+
794+
describe('internal condition', () => {
795+
it('should match when internal is true and condition is true', () => {
796+
class MyTestFeature extends ContentFeature {
797+
testMatchInternalConditional(conditionBlock) {
798+
return this._matchInternalConditional(conditionBlock);
799+
}
800+
}
801+
802+
const args = {
803+
site: {
804+
domain: 'example.com',
805+
url: 'http://example.com',
806+
},
807+
platform: {
808+
name: 'test',
809+
internal: true,
810+
},
811+
};
812+
813+
const feature = new MyTestFeature('test', {}, args);
814+
const result = feature.testMatchInternalConditional({
815+
internal: true,
816+
});
817+
expect(result).toBe(true);
818+
});
819+
820+
it('should match when internal is false and condition is false', () => {
821+
class MyTestFeature extends ContentFeature {
822+
testMatchInternalConditional(conditionBlock) {
823+
return this._matchInternalConditional(conditionBlock);
824+
}
825+
}
826+
827+
const args = {
828+
site: {
829+
domain: 'example.com',
830+
url: 'http://example.com',
831+
},
832+
platform: {
833+
name: 'test',
834+
internal: false,
835+
},
836+
};
837+
838+
const feature = new MyTestFeature('test', {}, args);
839+
const result = feature.testMatchInternalConditional({
840+
internal: false,
841+
});
842+
expect(result).toBe(true);
843+
});
844+
845+
it('should not match when internal is true but condition is false', () => {
846+
class MyTestFeature extends ContentFeature {
847+
testMatchInternalConditional(conditionBlock) {
848+
return this._matchInternalConditional(conditionBlock);
849+
}
850+
}
851+
852+
const args = {
853+
site: {
854+
domain: 'example.com',
855+
url: 'http://example.com',
856+
},
857+
platform: {
858+
name: 'test',
859+
internal: true,
860+
},
861+
};
862+
863+
const feature = new MyTestFeature('test', {}, args);
864+
const result = feature.testMatchInternalConditional({
865+
internal: false,
866+
});
867+
expect(result).toBe(false);
868+
});
869+
870+
it('should not match when internal is false but condition is true', () => {
871+
class MyTestFeature extends ContentFeature {
872+
testMatchInternalConditional(conditionBlock) {
873+
return this._matchInternalConditional(conditionBlock);
874+
}
875+
}
876+
877+
const args = {
878+
site: {
879+
domain: 'example.com',
880+
url: 'http://example.com',
881+
},
882+
platform: {
883+
name: 'test',
884+
internal: false,
885+
},
886+
};
887+
888+
const feature = new MyTestFeature('test', {}, args);
889+
const result = feature.testMatchInternalConditional({
890+
internal: true,
891+
});
892+
expect(result).toBe(false);
893+
});
894+
895+
it('should handle undefined internal state gracefully', () => {
896+
class MyTestFeature extends ContentFeature {
897+
testMatchInternalConditional(conditionBlock) {
898+
return this._matchInternalConditional(conditionBlock);
899+
}
900+
}
901+
902+
const args = {
903+
site: {
904+
domain: 'example.com',
905+
url: 'http://example.com',
906+
},
907+
platform: {
908+
name: 'test',
909+
// internal not set
910+
},
911+
};
912+
913+
const feature = new MyTestFeature('test', {}, args);
914+
const result = feature.testMatchInternalConditional({
915+
internal: true,
916+
});
917+
expect(result).toBe(false);
918+
});
919+
920+
it('should handle missing internal condition', () => {
921+
class MyTestFeature extends ContentFeature {
922+
testMatchInternalConditional(conditionBlock) {
923+
return this._matchInternalConditional(conditionBlock);
924+
}
925+
}
926+
927+
const args = {
928+
site: {
929+
domain: 'example.com',
930+
url: 'http://example.com',
931+
},
932+
platform: {
933+
name: 'test',
934+
internal: true,
935+
},
936+
};
937+
938+
const feature = new MyTestFeature('test', {}, args);
939+
const result = feature.testMatchInternalConditional({});
940+
expect(result).toBe(false);
941+
});
942+
943+
it('should handle truthy values for internal condition', () => {
944+
class MyTestFeature extends ContentFeature {
945+
testMatchInternalConditional(conditionBlock) {
946+
return this._matchInternalConditional(conditionBlock);
947+
}
948+
}
949+
950+
const args = {
951+
site: {
952+
domain: 'example.com',
953+
url: 'http://example.com',
954+
},
955+
platform: {
956+
name: 'test',
957+
internal: 1, // truthy value
958+
},
959+
};
960+
961+
const feature = new MyTestFeature('test', {}, args);
962+
const result = feature.testMatchInternalConditional({
963+
internal: true,
964+
});
965+
expect(result).toBe(true);
966+
});
967+
968+
it('should handle falsy values for internal condition', () => {
969+
class MyTestFeature extends ContentFeature {
970+
testMatchInternalConditional(conditionBlock) {
971+
return this._matchInternalConditional(conditionBlock);
972+
}
973+
}
974+
975+
const args = {
976+
site: {
977+
domain: 'example.com',
978+
url: 'http://example.com',
979+
},
980+
platform: {
981+
name: 'test',
982+
internal: 0, // falsy value
983+
},
984+
};
985+
986+
const feature = new MyTestFeature('test', {}, args);
987+
const result = feature.testMatchInternalConditional({
988+
internal: false,
989+
});
990+
expect(result).toBe(true);
991+
});
992+
});
793993
});

injected/unit-test/verify-artifacts.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const ROOT = join(cwd(import.meta.url), '..', '..');
77
console.log(ROOT);
88
const BUILD = join(ROOT, 'build');
99

10-
let CSS_OUTPUT_SIZE = 780_000;
10+
let CSS_OUTPUT_SIZE = 800_000;
1111
if (process.platform === 'win32') {
1212
CSS_OUTPUT_SIZE = CSS_OUTPUT_SIZE * 1.1; // 10% larger for Windows due to line endings
1313
}

0 commit comments

Comments
 (0)