@protontech/autofill 0.0.33835493 → 0.0.35481761

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.
Files changed (41) hide show
  1. package/features/feature.d.ts +13 -2
  2. package/features/feature.js +37 -17
  3. package/features/feature.spec.js +56 -3
  4. package/features/v1/abstract.field.d.ts +8377 -406
  5. package/features/v1/abstract.field.js +23 -23
  6. package/features/v1/abstract.form.d.ts +3428 -626
  7. package/features/v1/abstract.form.js +198 -199
  8. package/features/v1/field.email.d.ts +3421 -0
  9. package/features/v1/field.email.js +7 -7
  10. package/features/v1/field.otp.d.ts +71178 -0
  11. package/features/v1/field.otp.js +42 -42
  12. package/features/v1/field.password.d.ts +99166 -0
  13. package/features/v1/field.password.js +42 -42
  14. package/features/v1/field.username-hidden.d.ts +908 -0
  15. package/features/v1/field.username-hidden.js +7 -7
  16. package/features/v1/field.username.d.ts +42382 -0
  17. package/features/v1/field.username.js +11 -11
  18. package/features/v1/fields.sorted.gen.d.ts +1441 -0
  19. package/features/v1/fields.sorted.gen.js +344 -0
  20. package/features/v1/forms.sorted.gen.d.ts +734 -0
  21. package/features/v1/forms.sorted.gen.js +334 -0
  22. package/features/v1/index.d.ts +964 -84
  23. package/features/v1/index.js +9 -15
  24. package/features/v1/index.spec.js +34 -20
  25. package/models/perceptron/params/login-model.json +91 -91
  26. package/models/perceptron/params/new-password-model.json +21 -21
  27. package/models/perceptron/params/otp-model.json +29 -29
  28. package/models/perceptron/params/password-change-model.json +72 -72
  29. package/models/perceptron/params/password-model.json +23 -23
  30. package/models/perceptron/params/recovery-model.json +81 -81
  31. package/models/perceptron/params/register-model.json +99 -99
  32. package/models/perceptron/params/username-hidden-model.json +10 -10
  33. package/models/perceptron/params/username-model.json +7 -7
  34. package/models/random_forest/params/otp-model.json +306 -366
  35. package/package.json +3 -3
  36. package/rules/v1/index.js +2 -2
  37. package/scripts/gen-sorted-features.d.ts +1 -0
  38. package/scripts/gen-sorted-features.js +128 -0
  39. package/types/index.d.ts +2 -1
  40. package/utils/fathom.d.ts +1 -2
  41. package/utils/fathom.js +2 -2
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@protontech/autofill",
3
- "version": "0.0.33835493",
3
+ "version": "0.0.35481761",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "typecheck": "tsc --noEmit"
7
7
  },
8
8
  "dependencies": {
9
- "@protontech/fathom": "0.0.33835493",
10
- "@protontech/ml-inference": "0.0.33835493"
9
+ "@protontech/fathom": "0.0.35481761",
10
+ "@protontech/ml-inference": "0.0.35481761"
11
11
  },
12
12
  "devDependencies": {
13
13
  "@types/jest": "^29.5.14",
package/rules/v1/index.js CHANGED
@@ -12,12 +12,12 @@ import { isVisibleForm } from "@protontech/autofill/utils/visible";
12
12
  import { dom, out, rule, type } from "@protontech/fathom";
13
13
  const getRulesForFieldClass = (klass, featureComputer) => [
14
14
  rule(type(`${klass}-field`), type(klass), {}),
15
- ...featureComputer.features.map((feat) => rule(type(klass), featureScore(`${klass}-field`, feat), { name: `${klass}${FEATURE_SEPARATOR}${feat.name}` })),
15
+ ...featureComputer.features.map((featName) => rule(type(klass), featureScore(`${klass}-field`, featName), { name: `${klass}${FEATURE_SEPARATOR}${featName}` })),
16
16
  ...outRuleWithCache("field-candidate", klass),
17
17
  ];
18
18
  const getRulesForFormClass = (klass, featureComputer) => [
19
19
  rule(type("form"), type(klass), {}),
20
- ...featureComputer.features.map((feat) => rule(type(klass), featureScore("form", feat), { name: `${klass}${FEATURE_SEPARATOR}${feat.name}` })),
20
+ ...featureComputer.features.map((featName) => rule(type(klass), featureScore("form", featName), { name: `${klass}${FEATURE_SEPARATOR}${featName}` })),
21
21
  ...outRuleWithCache("form-candidate", klass),
22
22
  ];
23
23
  const noopRules = [
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,128 @@
1
+ import { topologicalSort, validateComputerInputs } from "@protontech/autofill/features/feature";
2
+ import * as abstractField from "@protontech/autofill/features/v1/abstract.field";
3
+ import * as abstractForm from "@protontech/autofill/features/v1/abstract.form";
4
+ import * as fieldEmail from "@protontech/autofill/features/v1/field.email";
5
+ import * as fieldOtp from "@protontech/autofill/features/v1/field.otp";
6
+ import * as fieldPassword from "@protontech/autofill/features/v1/field.password";
7
+ import * as fieldUsername from "@protontech/autofill/features/v1/field.username";
8
+ import * as fieldUsernameHidden from "@protontech/autofill/features/v1/field.username-hidden";
9
+ import { mkdirSync, writeFileSync } from "node:fs";
10
+ import { dirname } from "node:path";
11
+ const sources = [
12
+ ["./abstract.form", abstractForm],
13
+ ["./abstract.field", abstractField],
14
+ ["./field.email", fieldEmail],
15
+ ["./field.otp", fieldOtp],
16
+ ["./field.password", fieldPassword],
17
+ ["./field.username", fieldUsername],
18
+ ["./field.username-hidden", fieldUsernameHidden],
19
+ ];
20
+ const isFeature = (v) => typeof v === "object" && v !== null && typeof v.compute === "function";
21
+ const buildFeatureRefs = (sources) => {
22
+ const refs = new Map();
23
+ for (const [src, mod] of sources) {
24
+ for (const [id, val] of Object.entries(mod)) {
25
+ if (isFeature(val) && !refs.has(val))
26
+ refs.set(val, { id, src, path: [] });
27
+ }
28
+ }
29
+ for (const [src, mod] of sources) {
30
+ for (const [id, val] of Object.entries(mod)) {
31
+ if (!isFeature(val))
32
+ continue;
33
+ const walk = (node, path) => {
34
+ for (const [key, parent] of Object.entries(node.parents)) {
35
+ if (refs.has(parent))
36
+ continue;
37
+ const next = [...path, key];
38
+ refs.set(parent, { id, src, path: next });
39
+ walk(parent, next);
40
+ }
41
+ };
42
+ walk(val, []);
43
+ }
44
+ }
45
+ return refs;
46
+ };
47
+ const featureRefs = buildFeatureRefs(sources);
48
+ const refOf = (f) => {
49
+ const ref = featureRefs.get(f);
50
+ if (!ref)
51
+ throw new Error(`feature '${f.name}' has no exported declaration.`);
52
+ return ref;
53
+ };
54
+ const buildComputer = (name, recordSrc, record) => {
55
+ const outputs = Object.values(record);
56
+ const computer = {
57
+ name,
58
+ recordSrc,
59
+ sorted: topologicalSort(record),
60
+ features: outputs.filter((f) => !f.private).map((f) => f.name),
61
+ private: outputs.filter((f) => f.private).map((f) => f.name),
62
+ };
63
+ validateComputerInputs(computer);
64
+ return computer;
65
+ };
66
+ const BANNER = `// Generated by \`bazel run //pass_ml/js/autofill:write_sorted_features\`. Do not edit.\n\n`;
67
+ const RUNTIME_IMPORT = `import { getComputerForFeatures } from "@protontech/autofill/features/feature";`;
68
+ const fmtImportSpec = (id, alias) => (alias === id ? id : `${id} as ${alias}`);
69
+ const fmtImportLine = (prefix, src, specs) => `${prefix} { ${specs.join(", ")} } from "${src}";`;
70
+ const fmtNameList = (names) => names.map((n) => `"${n}"`).join(", ");
71
+ const fmtComputerExport = (name, recordType, sortedRefs, features, privateOutputs) => `export const ${name}Computer = getComputerForFeatures<typeof ${recordType}>({
72
+ sorted: [${sortedRefs.map((r) => ` ${r},`).join("\n")}],
73
+ features: [${fmtNameList(features)}],
74
+ private: [${fmtNameList(privateOutputs)}],
75
+ });`;
76
+ const fmtFile = (imports, exports) => `${BANNER}\n${imports}\n\n${exports}\n`;
77
+ const render = (computers) => {
78
+ const valueImports = {};
79
+ const typeImports = {};
80
+ const srcsById = {};
81
+ const track = (bucket, src, id) => {
82
+ var _a, _b;
83
+ ((_a = bucket[src]) !== null && _a !== void 0 ? _a : (bucket[src] = new Set())).add(id);
84
+ ((_b = srcsById[id]) !== null && _b !== void 0 ? _b : (srcsById[id] = new Set())).add(src);
85
+ };
86
+ for (const c of computers) {
87
+ track(typeImports, c.recordSrc, c.name);
88
+ for (const f of c.sorted) {
89
+ const { src, id } = refOf(f);
90
+ track(valueImports, src, id);
91
+ }
92
+ }
93
+ const importAlias = (src, id) => {
94
+ var _a;
95
+ if (srcsById[id].size === 1)
96
+ return id;
97
+ return `${id}_${(_a = src.split("/").pop()) === null || _a === void 0 ? void 0 : _a.replace(/[.-]/g, "_")}`;
98
+ };
99
+ const importLinesFor = (bucket, prefix) => Object.entries(bucket).map(([src, ids]) => {
100
+ const specs = [...ids].map((id) => fmtImportSpec(id, importAlias(src, id)));
101
+ return fmtImportLine(prefix, src, specs);
102
+ });
103
+ const imports = [RUNTIME_IMPORT, ...importLinesFor(valueImports, "import"), ...importLinesFor(typeImports, "import type")].join("\n");
104
+ const refExpr = (f) => {
105
+ const { src, id, path } = refOf(f);
106
+ return path.reduce((acc, key) => `${acc}.parents.${key}`, importAlias(src, id));
107
+ };
108
+ const exports = computers.map((c) => fmtComputerExport(c.name, importAlias(c.recordSrc, c.name), c.sorted.map(refExpr), c.features, c.private)).join("\n\n");
109
+ return fmtFile(imports, exports);
110
+ };
111
+ const writeOut = (path, content) => {
112
+ mkdirSync(dirname(path), { recursive: true });
113
+ writeFileSync(path, content);
114
+ };
115
+ const [, , formsOut, fieldsOut] = process.argv;
116
+ if (!formsOut || !fieldsOut)
117
+ throw new Error("usage: gen-sorted-features <forms-out.ts> <fields-out.ts>");
118
+ const formComputers = [buildComputer("formFeatures", "./abstract.form", abstractForm.formFeatures)];
119
+ const fieldComputers = [
120
+ buildComputer("fieldFeatures", "./abstract.field", abstractField.fieldFeatures),
121
+ buildComputer("emailFeatures", "./field.email", fieldEmail.emailFeatures),
122
+ buildComputer("otpFeatures", "./field.otp", fieldOtp.otpFeatures),
123
+ buildComputer("passwordFeatures", "./field.password", fieldPassword.passwordFeatures),
124
+ buildComputer("usernameFeatures", "./field.username", fieldUsername.usernameFeatures),
125
+ buildComputer("usernameHiddenFeatures", "./field.username-hidden", fieldUsernameHidden.usernameHiddenFeatures),
126
+ ];
127
+ writeOut(formsOut, render(formComputers));
128
+ writeOut(fieldsOut, render(fieldComputers));
package/types/index.d.ts CHANGED
@@ -71,13 +71,14 @@ export type Feature<N extends string, R, P extends AbstractFeatures> = {
71
71
  name: N;
72
72
  parents: P;
73
73
  compute(parents: InferParentComputeType<P>, fnode: Fnode): R;
74
+ private?: true;
74
75
  };
75
76
  export type ComputedFeatures<F extends AbstractFeatures> = {
76
77
  [K in keyof F as F[K]["name"]]: ReturnType<F[K]["compute"]>;
77
78
  };
78
79
  export interface FeatureComputer<F extends AbstractFeatures = AbstractFeatures> {
79
80
  compute(fnode: Fnode): ComputedFeatures<F>;
80
- features: AbstractFeature[];
81
+ features: string[];
81
82
  }
82
83
  export type ModelProviderRegistry = Record<ModelName, ModelProvider>;
83
84
  export type ModelName = string;
package/utils/fathom.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import type { Fnode } from "@protontech/fathom";
2
- import type { AbstractFeature } from "@protontech/autofill/types";
3
2
  export declare const TOLERANCE_LEVEL = 0.5;
4
3
  export declare const boolInt: (val: boolean) => number;
5
4
  export declare const safeInt: (val: number, fallback?: number) => number;
@@ -7,7 +6,7 @@ export declare const typeEffect: (type: string) => (fnode: Fnode) => Fnode;
7
6
  export declare const processFormEffect: (fnode: Fnode) => Fnode;
8
7
  export declare const processFieldEffect: (fnode: Fnode) => Fnode;
9
8
  type ClassNote = "form" | "new-password-field" | "password-field" | "username-field" | "username-hidden-field" | "email-field" | "otp-field";
10
- export declare const featureScore: <F extends AbstractFeature>(noteFor: ClassNote, feat: F) => import("@protontech/fathom").Side;
9
+ export declare const featureScore: (noteFor: ClassNote, featName: string) => import("@protontech/fathom").Side;
11
10
  export declare const getParentFormFnode: (fieldFnode: Fnode) => Fnode | null;
12
11
  export declare const typeScoreToleranceTest: (type: string) => (fnode: Fnode) => boolean;
13
12
  export declare const getTypeScore: (node: Fnode | null, type: string) => number;
package/utils/fathom.js CHANGED
@@ -20,9 +20,9 @@ export const processFieldEffect = throughEffect((fnode) => {
20
20
  if (visible || type === "hidden")
21
21
  flagAsProcessed(fnode.element);
22
22
  });
23
- export const featureScore = (noteFor, feat) => score((fnode) => {
23
+ export const featureScore = (noteFor, featName) => score((fnode) => {
24
24
  const note = fnode.noteFor(noteFor);
25
- return Number(note[feat.name]);
25
+ return Number(note[featName]);
26
26
  });
27
27
  export const getParentFormFnode = (fieldFnode) => {
28
28
  const field = fieldFnode.element;