@vinikjkkj/wa-abprops 2.3000.1044071294-e8a5558

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 (4) hide show
  1. package/README.md +223 -0
  2. package/index.d.ts +4402 -0
  3. package/index.js +4372 -0
  4. package/package.json +52 -0
package/README.md ADDED
@@ -0,0 +1,223 @@
1
+ # @vinikjkkj/wa-abprops
2
+
3
+ WhatsApp Web AB props (server-driven experiment configs) — the numeric config
4
+ code each prop travels under, its wire value type, its client-side default and
5
+ its internal-build debug default. Everything is daily-extracted directly from
6
+ the minified `WAWebABPropsConfigs` / `WAWebGroupABPropsConfigs` tables in WA
7
+ Web bundles.
8
+
9
+ ```sh
10
+ npm i @vinikjkkj/wa-abprops
11
+ ```
12
+
13
+ ```ts
14
+ import {
15
+ WA_ABPROPS,
16
+ WA_GROUP_ABPROPS,
17
+ WA_ABPROPS_BY_CODE, // reverse map: 6939 → 'adv_accept_hosted_devices'
18
+ WA_GROUP_ABPROPS_BY_CODE,
19
+ WA_ABPROPS_USED_BEFORE_INIT, // readable before the config cache resolves
20
+ WA_ABPROPS_SPECIAL_EARLY // mirrored into localStorage for pre-DB startup code
21
+ } from '@vinikjkkj/wa-abprops'
22
+ import type {
23
+ WaAbPropName,
24
+ WaGroupAbPropName,
25
+ WaAbProp,
26
+ WaAbPropType,
27
+ WaAbPropValueByName
28
+ } from '@vinikjkkj/wa-abprops'
29
+
30
+ WA_ABPROPS.web_image_max_edge
31
+ // → { code: 3042, type: 'int', defaultValue: 1600, debugDefaultValue: 1600 }
32
+
33
+ WA_ABPROPS.adv_accept_hosted_devices
34
+ // → { code: 6939, type: 'bool', defaultValue: false, debugDefaultValue: true }
35
+ // defaultValue ≠ debugDefaultValue → shipped off, on for internal builds
36
+
37
+ WA_ABPROPS.a2ui_supported_elements
38
+ // → {
39
+ // code: 32276,
40
+ // type: 'string',
41
+ // defaultValue: 'info_card, list_card',
42
+ // debugDefaultValue: 'info_card, list_card'
43
+ // }
44
+
45
+ WA_GROUP_ABPROPS.group_history_messages_time_limit_secs_group_level
46
+ // → { code: 26270, type: 'int', defaultValue: 1209600, debugDefaultValue: 1209600 }
47
+
48
+ WA_ABPROPS_SPECIAL_EARLY
49
+ // → {
50
+ // localStorageKey: 'abprops_needed_early',
51
+ // props: ['wa_web_favicons_update_m1', 'web_ui_refresh_m1', …]
52
+ // }
53
+ ```
54
+
55
+ ## Decoding a server response
56
+
57
+ The `abt` IQ hands back rows of `{ configCode, configValue, configExpoKey }`
58
+ where `configValue` is *always* a string. This package gives you both halves
59
+ of the decode: the code → name mapping and the type to parse with.
60
+
61
+ ```ts
62
+ import { WA_ABPROPS, WA_ABPROPS_BY_CODE } from '@vinikjkkj/wa-abprops'
63
+
64
+ function parseConfigValue(raw: string, type: WaAbPropType, fallback: unknown) {
65
+ if (raw == null) return fallback
66
+ if (type === 'bool') return raw === '1' || raw === 'true' || raw === 'True'
67
+ if (type === 'int') return parseInt(raw, 10)
68
+ if (type === 'float') return parseFloat(raw)
69
+ return raw
70
+ }
71
+
72
+ function decode(rows: Array<{ configCode: string; configValue: string }>) {
73
+ const out: Record<string, unknown> = {}
74
+ for (const row of rows) {
75
+ const name = WA_ABPROPS_BY_CODE[Number(row.configCode) as keyof typeof WA_ABPROPS_BY_CODE]
76
+ if (name == null) continue // prop the client build doesn't know yet
77
+ const prop = WA_ABPROPS[name]
78
+ out[name] = parseConfigValue(row.configValue, prop.type, prop.defaultValue)
79
+ }
80
+ return out
81
+ }
82
+ ```
83
+
84
+ Props the server never sent keep their `defaultValue` — that is exactly what
85
+ `WAWebABProps.getABPropConfigValue` does when the cache misses.
86
+
87
+ ## Typed lookups
88
+
89
+ Every prop is emitted with literal types, so `WaAbPropValueByName<K>` resolves
90
+ a prop's decoded JS type from its declared wire type:
91
+
92
+ ```ts
93
+ import type { WaAbPropValueByName } from '@vinikjkkj/wa-abprops'
94
+
95
+ type MaxEdge = WaAbPropValueByName<'web_image_max_edge'> // → number
96
+ type Hosted = WaAbPropValueByName<'adv_accept_hosted_devices'> // → boolean
97
+ type Elements = WaAbPropValueByName<'a2ui_supported_elements'> // → string
98
+
99
+ function getAbProp<K extends WaAbPropName>(name: K): WaAbPropValueByName<K> {
100
+ // …your cache lookup, falling back to WA_ABPROPS[name].defaultValue
101
+ }
102
+
103
+ getAbProp('web_image_max_edge') // ✓ number
104
+ getAbProp('web_image_max_edg') // ✗ caught at compile time
105
+ ```
106
+
107
+ The `code` and both default values are literal types too, so
108
+ `WA_ABPROPS.adv_accept_hosted_devices.code` narrows to `6939` rather than
109
+ `number`.
110
+
111
+ ## What's in here
112
+
113
+ Nearly every feature in WA Web sits behind an AB prop. The client ships the
114
+ full catalogue as a flat data table and asks the server, at connect, for the
115
+ values it should use:
116
+
117
+ ```js
118
+ // from WAWebABPropsConfigs — <name>: [configCode, type, default, debugDefault]
119
+ var e = {
120
+ adv_accept_hosted_devices: [6939, 'bool', false, true],
121
+ web_image_max_edge: [3042, 'int', 1600, 1600],
122
+ a2ui_supported_elements: [32276, 'string', 'info_card, list_card', 'info_card, list_card'],
123
+ // …2000+ more
124
+ }
125
+ i.ABPropConfigs = e
126
+ ```
127
+
128
+ Each entry boils down to:
129
+
130
+ - a **config code** (`6939`) — the *only* identity that travels on the wire.
131
+ The IQ (`WASmaxAbPropsGetExperimentConfigRPC`) returns rows keyed by code,
132
+ and the local `abpropConfigs` table uses it as its primary key. Prop names
133
+ never leave the client, which is why the reverse map matters.
134
+ - a **name** (`adv_accept_hosted_devices`) — the handle every
135
+ `getABPropConfigValue('…')` call site uses
136
+ - a **type** — `bool` | `int` | `float` | `string`. The server's
137
+ `configValue` is always a string; this drives
138
+ `WAWebABPropsParseConfigValue.parseConfigValue`.
139
+ - a **default value** — used whenever the server hasn't pushed a value for
140
+ this code (cache miss, offline, brand-new prop)
141
+ - a **debug default value** — substituted for the default only on internal
142
+ builds (gkx 26259 on *and* the account joined the internal beta;
143
+ `WAWebABPropsUpdateFromStorage` logs *"intern beta joined, using DEBUG
144
+ defaults"*). It's identical to the default for most props — where the two
145
+ differ, the debug value is a decent signal of where the rollout is headed.
146
+
147
+ Group-scoped props live in a parallel table (`WAWebGroupABPropsConfigs`),
148
+ fetched per group jid via the group experiment config IQ and cached separately.
149
+
150
+ Two auxiliary lists ship alongside:
151
+
152
+ - **`WA_ABPROPS_USED_BEFORE_INIT`** — the allowlist of props the runtime
153
+ tolerates reading before the config cache resolves. Everything else logs
154
+ *"impl must be set before first access"* and silently yields the default.
155
+ - **`WA_ABPROPS_SPECIAL_EARLY`** — the handful of props mirrored into
156
+ `localStorage` (as a JSON object under `abprops_needed_early`) so startup
157
+ code can consult them before IndexedDB opens.
158
+
159
+ This package gives you the static metadata for all **2100+ user props** +
160
+ **14 group props**, so you can decode an `abt` response, mirror WA Web's
161
+ gating decisions, or diff a build's rollout state without transcribing the
162
+ client's table by hand.
163
+
164
+ ## What's published
165
+
166
+ | File | Format | Use case |
167
+ |---|---|---|
168
+ | `index.js` | CommonJS | Runtime `WA_ABPROPS` / `WA_GROUP_ABPROPS` / `WA_ABPROPS_BY_CODE` / `WA_GROUP_ABPROPS_BY_CODE` / `WA_ABPROPS_USED_BEFORE_INIT` / `WA_ABPROPS_SPECIAL_EARLY` frozen tables |
169
+ | `index.d.ts` | TS declarations | Per-prop literal-typed entries + the umbrella maps + the `WaAbPropValueByName<K>` helper |
170
+
171
+ A raw IR file (`index.json`) is also produced — see
172
+ [`packages/abprops/index.json`](https://github.com/vinikjkkj/wa-spec/blob/master/packages/abprops/index.json)
173
+ for non-TS consumers (diff tools, codegen, other languages).
174
+
175
+ `index.json` shape:
176
+
177
+ ```jsonc
178
+ {
179
+ "waVersion": "2.3000.xxxxx",
180
+ "propCount": 2117,
181
+ "groupPropCount": 14,
182
+ "usedBeforeInitialization": ["direct_connection_business_numbers", …],
183
+ "specialEarlyProps": {
184
+ "localStorageKey": "abprops_needed_early",
185
+ "props": ["wa_web_favicons_update_m1", "web_ui_refresh_m1", …]
186
+ },
187
+ "props": {
188
+ "adv_accept_hosted_devices": {
189
+ "code": 6939,
190
+ "type": "bool",
191
+ "defaultValue": false,
192
+ "debugDefaultValue": true
193
+ },
194
+ …
195
+ },
196
+ "groupProps": {
197
+ "group_history_messages_time_limit_secs_group_level": {
198
+ "code": 26270,
199
+ "type": "int",
200
+ "defaultValue": 1209600,
201
+ "debugDefaultValue": 1209600
202
+ },
203
+ …
204
+ }
205
+ }
206
+ ```
207
+
208
+ ## Gotchas
209
+
210
+ - **Names are client-only.** A code with no entry in `WA_ABPROPS_BY_CODE` is
211
+ a prop the server knows about but this build doesn't — skip it rather than
212
+ guessing. The runtime does the same (it warns and drops the row).
213
+ - **Defaults are not "off".** Plenty of props default to a non-trivial int or
214
+ string; treating a missing value as `false` will diverge from the client.
215
+ - **`debugDefaultValue` is not what you'll be served.** It only applies to
216
+ internal builds. Use `defaultValue` when modelling a normal client.
217
+ - **Codes are stable, values are not.** A prop's `code` persists across
218
+ builds; its defaults change freely, and props are added and removed every
219
+ release. Diff `index.json` between versions to see the movement.
220
+ - **Group props are a separate namespace.** `WA_GROUP_ABPROPS` codes come
221
+ from their own table and are not interchangeable with user-level codes.
222
+
223
+ Daily-extracted by [wa-spec](https://github.com/vinikjkkj/wa-spec).