@unbound-app/api 3.1.0 → 3.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unbound-app/api",
3
- "version": "3.1.0",
3
+ "version": "3.3.0",
4
4
  "author": {
5
5
  "name": "Mario P.",
6
6
  "email": "contact@marioparaschiv.com",
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type { LiteralUnion } from './_types';
4
4
  import * as React$1 from 'react';
5
- import { ComponentType, FunctionComponent, ReactElement, ReactNode } from 'react';
5
+ import { ComponentType, Context, FunctionComponent, ReactElement, ReactNode } from 'react';
6
6
  import * as RN from 'react-native';
7
7
  import { ImageSourcePropType, ImageStyle, TextStyle, ViewStyle } from 'react-native';
8
8
 
@@ -87,12 +87,20 @@ export declare const NATIVE_BRIDGE_CAPABILITIES: readonly [
87
87
  'native.objc.ivars',
88
88
  'native.objc.associations',
89
89
  'native.objc.hooks',
90
+ 'native.objc.blocks',
91
+ 'native.objc.classDefinition',
92
+ 'native.objc.classSearch',
93
+ 'native.objc.inspect',
90
94
  'native.ffi.symbols',
91
95
  'native.ffi.call',
96
+ 'native.ffi.memory',
97
+ 'native.ffi.callbacks',
98
+ 'native.ffi.rebind',
92
99
  'native.fabric.mount',
93
100
  'native.fabric.async',
94
101
  'native.runtime.events',
95
102
  'native.java.classes',
103
+ 'native.java.classSearch',
96
104
  'native.java.construct',
97
105
  'native.java.fields',
98
106
  'native.java.invoke',
@@ -135,8 +143,25 @@ export declare const NATIVE_BRIDGE_METHOD_CAPABILITIES: {
135
143
  readonly 'objc.array': 'native.objc.classes';
136
144
  readonly 'objc.data': 'native.objc.classes';
137
145
  readonly 'objc.hook': 'native.objc.hooks';
146
+ readonly 'objc.block': 'native.objc.blocks';
147
+ readonly 'objc.callBlock': 'native.objc.blocks';
148
+ readonly 'objc.defineClass': 'native.objc.classDefinition';
149
+ readonly 'objc.findClasses': 'native.objc.classSearch';
150
+ readonly 'objc.inspectClass': 'native.objc.inspect';
151
+ readonly 'objc.inspectMembers': 'native.objc.inspect';
152
+ readonly 'objc.inspectValues': 'native.objc.inspect';
153
+ readonly 'objc.inspectImages': 'native.objc.inspect';
154
+ readonly 'objc.inspectClasses': 'native.objc.inspect';
138
155
  readonly 'ffi.symbol': 'native.ffi.symbols';
139
156
  readonly 'ffi.call': 'native.ffi.call';
157
+ readonly 'ffi.alloc': 'native.ffi.memory';
158
+ readonly 'ffi.free': 'native.ffi.memory';
159
+ readonly 'ffi.read': 'native.ffi.memory';
160
+ readonly 'ffi.write': 'native.ffi.memory';
161
+ readonly 'ffi.callback': 'native.ffi.callbacks';
162
+ readonly 'ffi.releaseCallback': 'native.ffi.callbacks';
163
+ readonly 'ffi.rebind': 'native.ffi.rebind';
164
+ readonly 'ffi.restore': 'native.ffi.rebind';
140
165
  readonly 'fabric.mount': 'native.fabric.mount';
141
166
  readonly 'fabric.update': 'native.fabric.mount';
142
167
  readonly 'fabric.setSize': 'native.fabric.mount';
@@ -156,6 +181,7 @@ export declare const NATIVE_BRIDGE_METHOD_CAPABILITIES: {
156
181
  readonly 'java.getClass': 'native.java.classes';
157
182
  readonly 'java.className': 'native.java.classes';
158
183
  readonly 'java.describe': 'native.java.classes';
184
+ readonly 'java.findClasses': 'native.java.classSearch';
159
185
  readonly 'java.construct': 'native.java.construct';
160
186
  readonly 'java.respondsTo': 'native.java.classes';
161
187
  readonly 'java.invoke': 'native.java.invoke';
@@ -195,8 +221,15 @@ export declare const NATIVE_BRIDGE_PLATFORM_CAPABILITIES: {
195
221
  'native.objc.ivars',
196
222
  'native.objc.associations',
197
223
  'native.objc.hooks',
224
+ 'native.objc.blocks',
225
+ 'native.objc.classDefinition',
226
+ 'native.objc.classSearch',
227
+ 'native.objc.inspect',
198
228
  'native.ffi.symbols',
199
229
  'native.ffi.call',
230
+ 'native.ffi.memory',
231
+ 'native.ffi.callbacks',
232
+ 'native.ffi.rebind',
200
233
  'native.fabric.mount',
201
234
  'native.fabric.async',
202
235
  'native.runtime.events',
@@ -206,9 +239,13 @@ export declare const NATIVE_BRIDGE_PLATFORM_CAPABILITIES: {
206
239
  readonly android: readonly [
207
240
  'native.ffi.symbols',
208
241
  'native.ffi.call',
242
+ 'native.ffi.memory',
243
+ 'native.ffi.callbacks',
244
+ 'native.ffi.rebind',
209
245
  'native.fabric.async',
210
246
  'native.runtime.events',
211
247
  'native.java.classes',
248
+ 'native.java.classSearch',
212
249
  'native.java.construct',
213
250
  'native.java.fields',
214
251
  'native.java.invoke',
@@ -1354,6 +1391,8 @@ export type DesignHelpers = {
1354
1391
  TextStyleSheet: Record<TextVariant, TextStyle>;
1355
1392
  /** Hook that resolves a semantic colour token, such as `Theme.colors.TEXT_DEFAULT`, to a colour for the current theme. */
1356
1393
  useToken: (token: SemanticColorToken) => string;
1394
+ /** Whether a row sits in a `TableRowGroup`, which then rounds the group's card itself; rows outside one round their own. */
1395
+ TableRowGroupContext: React$1.Context<boolean>;
1357
1396
  /** Hook that builds the state a `SegmentedControl` and its `SegmentedControlPages` share. */
1358
1397
  useSegmentedControlState: (options: SegmentedControlStateOptions) => SegmentedControlState;
1359
1398
  /** Opens an alert as `openAlert(key, element)`; pass the same key to `dismissAlert` to close it. */
@@ -3416,7 +3455,9 @@ export type LoaderNativeBridge = Pick<
3416
3455
  readonly java?: NativeJavaBridge & NativeUIScopeFactory;
3417
3456
  };
3418
3457
  /** The `objc` namespace the loader publishes, before the client adds `create` and scopes it to a plugin. */
3419
- export type LoaderObjCBridge = Omit<NativeObjCBridge, 'create'> & NativeUIScopeFactory;
3458
+ export type LoaderObjCBridge = Omit<NativeObjCBridge, 'create'> &
3459
+ Partial<NativeObjCInspector> &
3460
+ NativeUIScopeFactory;
3420
3461
  /**
3421
3462
  * Props of `LoadingButtonPill` (function). Exports: LoadingButtonPill.
3422
3463
  * @see design/components/Button/native/ButtonPill.native.tsx
@@ -3836,6 +3877,9 @@ export type NativeBridgeError = {
3836
3877
  };
3837
3878
  /** The stable `code` on an error the native bridge or its plugin scope throws. */
3838
3879
  export type NativeBridgeErrorCode =
3880
+ | 'INSPECTOR_DISABLED'
3881
+ | 'INSPECTOR_UNAVAILABLE'
3882
+ | 'INSPECTOR_UNKNOWN_CLASS'
3839
3883
  | 'NATIVE_BRIDGE_ERROR'
3840
3884
  | 'NATIVE_PLUGIN_API_VERSION_UNSUPPORTED'
3841
3885
  | 'NATIVE_PLUGIN_CALL_CANCELLED'
@@ -3843,10 +3887,12 @@ export type NativeBridgeErrorCode =
3843
3887
  | 'NATIVE_PLUGIN_CAPABILITY_DENIED'
3844
3888
  | 'NATIVE_PLUGIN_SCOPE_DISPOSED'
3845
3889
  | 'NATIVE_PLUGIN_UNAVAILABLE';
3846
- /** A native bridge method by the path a plugin calls it through, such as `objc.invoke`. */
3847
- export type NativeBridgeMethod = {
3848
- [N in NativeBridgeNamespace]: `${N}.${keyof NativeBridge[N] & string}`;
3849
- }[NativeBridgeNamespace];
3890
+ /** A native bridge method by the path a plugin calls it through, such as `objc.invoke`, or the debugger's `objc.inspect*`. */
3891
+ export type NativeBridgeMethod =
3892
+ | {
3893
+ [N in NativeBridgeNamespace]: `${N}.${keyof NativeBridge[N] & string}`;
3894
+ }[NativeBridgeNamespace]
3895
+ | `objc.${keyof NativeObjCInspector}`;
3850
3896
  /** A {@link NativeBridge} namespace whose methods a plugin calls, such as `objc` or `java`. */
3851
3897
  export type NativeBridgeNamespace = Exclude<
3852
3898
  keyof NativeBridge,
@@ -3932,12 +3978,89 @@ export type NativeDebugEvaluationLog = {
3932
3978
  /** The printed text. */
3933
3979
  message: string;
3934
3980
  };
3981
+ /** Memory and thermal pressure, as each platform reports it. */
3982
+ export type NativeDeviceState = {
3983
+ /** Memory available to apps, in megabytes. */
3984
+ availableMB?: number;
3985
+ /** Android: the system considers itself low on memory. */
3986
+ lowMemory?: boolean;
3987
+ /** iOS: memory warnings Discord received this session. */
3988
+ memoryWarnings?: number;
3989
+ /** How hot the device runs, as the system rates it. */
3990
+ thermal?: 'nominal' | 'fair' | 'serious' | 'critical';
3991
+ /** Free space on the volume holding Discord's documents, and the size of Unbound's folder there. */
3992
+ freeMB?: number;
3993
+ /** The size of Unbound's folder, in megabytes. */
3994
+ unboundMB?: number;
3995
+ /** The active connection, and whether a VPN, a proxy, a metered plan or Low Data Mode (Data Saver) applies. */
3996
+ network?: NativeNetworkState;
3997
+ /** Other tweaks or modules loaded into Discord: iOS dylib names, Android packages or Magisk modules; older loaders omit it. */
3998
+ injected?: string[];
3999
+ };
4000
+ /**
4001
+ * The install, binary, device and network facts `/debug` shows, each already a display string.
4002
+ * @internal
4003
+ */
4004
+ type NativeEnvironmentReport = {
4005
+ /** iOS: the signing certificate's SHA-256 prefix and issuer. */
4006
+ signer?: string;
4007
+ /** iOS: encryption, UUID, minimum OS, SDK and dylib count of Discord's executable. */
4008
+ binary?: string;
4009
+ /** Android: the APK signer, patch mode, splits and profile. */
4010
+ install?: string;
4011
+ markers?: string[];
4012
+ /** iOS: the OS build number when it is a beta. */
4013
+ osBeta?: string;
4014
+ /** Whether Discord's HTTPS traffic reaches a certificate from a known public CA. */
4015
+ https?: {
4016
+ intercepted: boolean;
4017
+ issuer?: string;
4018
+ failure?: string;
4019
+ };
4020
+ };
3935
4021
  /** Calls C functions in images Discord already loaded. An unsigned plugin needs the user's consent to use it. */
3936
4022
  export type NativeFFIBridge = {
3937
4023
  /** Resolves a symbol in a loaded image, or in every loaded image when `image` is omitted; `null` when not found. */
3938
4024
  symbol(name: string, image?: string): NativePointer | null;
3939
4025
  /** Calls a symbol from `symbol` with an explicit signature. */
3940
4026
  call(pointer: NativePointer, signature: NativeFFISignature, ...args: unknown[]): unknown;
4027
+ /** Allocates zeroed memory for out-parameters and buffers; free it with `free`. Needs `native.ffi.memory`. */
4028
+ alloc(size: number): NativePointer;
4029
+ /** Frees memory from `alloc`; `false` for any other pointer. Needs `native.ffi.memory`. */
4030
+ free(pointer: NativePointer): boolean;
4031
+ /** Reads a value of a type at a pointer, `offset` bytes in, failing safely on an unreadable address. Needs `native.ffi.memory`. */
4032
+ read(pointer: NativePointer, type: NativeFFIType, offset?: number): NativeFFIValue;
4033
+ /** Writes a value of a type into memory from `alloc`, `offset` bytes in. Needs `native.ffi.memory`. */
4034
+ write(
4035
+ pointer: NativePointer,
4036
+ type: NativeFFIType,
4037
+ value: NativeFFIValue,
4038
+ offset?: number,
4039
+ ): void;
4040
+ /**
4041
+ * Makes a C function pointer that runs `implementation` on the JavaScript thread; 32 per return kind live at
4042
+ * once, so release each with `releaseCallback`. Needs `native.ffi.callbacks`.
4043
+ */
4044
+ callback(
4045
+ signature: NativeFFISignature,
4046
+ implementation: (...args: never[]) => NativeFFIValue | void,
4047
+ ): NativePointer;
4048
+ /** Frees a pointer from `callback`. Needs `native.ffi.callbacks`. */
4049
+ releaseCallback(pointer: NativePointer): boolean;
4050
+ /**
4051
+ * Points every image's imports of a C function at `replacement`, such as a pointer from `callback`, and returns
4052
+ * the original to call through; the loader's own calls keep the original. Needs `native.ffi.rebind`.
4053
+ */
4054
+ rebind(name: string, replacement: NativePointer): NativeFFIRebinding;
4055
+ /** Puts back every import `rebind` changed for a symbol. Needs `native.ffi.rebind`. */
4056
+ restore(name: string): boolean;
4057
+ };
4058
+ /** What `rebind` changed: the original function and how many import slots now point at the replacement. */
4059
+ export type NativeFFIRebinding = {
4060
+ /** The function the import slots pointed at before. */
4061
+ original: NativePointer;
4062
+ /** How many import slots now point at the replacement. */
4063
+ slots: number;
3941
4064
  };
3942
4065
  /** A non-variadic C function signature for `ffi.call`. */
3943
4066
  export type NativeFFISignature = {
@@ -3971,6 +4094,15 @@ export type NativeFFITypeName =
3971
4094
  | 'object'
3972
4095
  | 'class'
3973
4096
  | 'selector';
4097
+ /** A value an FFI type reads or writes: a number, `BigInt` for 64-bit integers, a boolean, a string or a pointer. */
4098
+ export type NativeFFIValue =
4099
+ | number
4100
+ | bigint
4101
+ | boolean
4102
+ | string
4103
+ | NativePointer
4104
+ | NativeStruct
4105
+ | null;
3974
4106
  /** One surface's changes in a `batchAsync` call, applied as properties, then size, then frame. */
3975
4107
  export type NativeFabricBatchMutation = {
3976
4108
  /** The surface these changes apply to. */
@@ -4132,6 +4264,10 @@ export type NativeHookOptions<Receiver extends boolean = boolean> = {
4132
4264
  /** Removes the hook after its first call. */
4133
4265
  once?: boolean;
4134
4266
  payload?: NativeHookPayload<Receiver>;
4267
+ /** Also hooks every loaded subclass that implements the selector itself. */
4268
+ subclasses?: boolean;
4269
+ /** Waits for a class that is not loaded yet, retrying with backoff for up to ten minutes. */
4270
+ waitForClass?: boolean;
4135
4271
  } & NativeCallOptions;
4136
4272
  /** Trims what a hook sends to JavaScript per call, to cut crossing cost on hot methods. */
4137
4273
  export type NativeHookPayload<Receiver extends boolean = boolean> = {
@@ -4155,6 +4291,123 @@ export type NativeHookToken = {
4155
4291
  /** Removes the hook; calling it again does nothing. */
4156
4292
  remove(): void;
4157
4293
  };
4294
+ /** A kind of a class's own members `objc.inspectMembers` lists. */
4295
+ export type NativeInspectKind = 'properties' | 'ivars' | 'methods' | 'classMethods' | 'protocols';
4296
+ /** Narrows a page of inspected members, images or classes. */
4297
+ export type NativeInspectPage = {
4298
+ /** How many matches to skip. */
4299
+ offset?: number;
4300
+ /** At most 200. */
4301
+ limit?: number;
4302
+ /** A case-insensitive substring of the name. */
4303
+ filter?: string;
4304
+ };
4305
+ /** Options for `objc.inspectValues`. */
4306
+ export type NativeInspectValuesOptions = {
4307
+ /** Runs the getters of computed properties, which automatic reads skip. */
4308
+ invokeGetters?: boolean;
4309
+ };
4310
+ /** One class of an inspected class chain, from the class itself to its root. */
4311
+ export type NativeInspectedClass = {
4312
+ /** The class's name. */
4313
+ name: string;
4314
+ /** The superclass's name, or `null` at the root. */
4315
+ superclass: string | null;
4316
+ /** The path of the image that defines the class, or `null` when unknown. */
4317
+ image: string | null;
4318
+ /** The size of an instance, in bytes. */
4319
+ instanceSize: number;
4320
+ /** How many of each kind of member the class itself declares. */
4321
+ counts: Record<NativeInspectKind, number>;
4322
+ };
4323
+ /** One page of an image's class names, and how many match in all. */
4324
+ export type NativeInspectedClasses = {
4325
+ /** How many classes match in all. */
4326
+ total: number;
4327
+ /** This page's class names. */
4328
+ classes: string[];
4329
+ };
4330
+ /** One loaded image that defines Objective-C classes. */
4331
+ export type NativeInspectedImage = {
4332
+ /** The image's path on the device. */
4333
+ path: string;
4334
+ /** The image's file name. */
4335
+ name: string;
4336
+ /** How many classes the image defines. */
4337
+ classCount: number;
4338
+ };
4339
+ /** One page of loaded images, and how many match in all. */
4340
+ export type NativeInspectedImages = {
4341
+ /** How many images match in all. */
4342
+ total: number;
4343
+ /** This page's images. */
4344
+ images: NativeInspectedImage[];
4345
+ };
4346
+ /** One member of a class; fields that do not apply to its kind are omitted. */
4347
+ export type NativeInspectedMember = {
4348
+ /** The member's name, or a method's selector. */
4349
+ name: string;
4350
+ /** The kind of member. */
4351
+ kind: NativeInspectKind;
4352
+ /** The decoded type, such as `NSString *` or `CGRect`. */
4353
+ type?: string;
4354
+ /** The declaration, such as `- (void)setFoo:(id)foo`. */
4355
+ signature?: string;
4356
+ /** A method's decoded return type. */
4357
+ returnType?: string;
4358
+ /** A method's decoded parameter types, in order. */
4359
+ parameters?: string[];
4360
+ /** The raw Objective-C type encoding. */
4361
+ encoding?: string;
4362
+ /** Property attributes, such as `nonatomic`, `strong`, `readonly`, `weak`, `copy` or `class`. */
4363
+ attributes?: string[];
4364
+ /** A property's getter selector. */
4365
+ getter?: string;
4366
+ /** A property's setter selector, absent when it is read-only. */
4367
+ setter?: string;
4368
+ /** The instance variable backing a property. */
4369
+ ivar?: string;
4370
+ /** An instance variable's offset in the object, in bytes. */
4371
+ offset?: number;
4372
+ /** An instance variable's size, in bytes. */
4373
+ size?: number;
4374
+ /** The path of the image that defines a method. */
4375
+ image?: string;
4376
+ /** Whether reading the value runs no code (`auto`), runs a getter (`manual`), or is unsafe (`never`). */
4377
+ read: 'auto' | 'manual' | 'never';
4378
+ };
4379
+ /** One page of a class's members of one kind, and how many match in all. */
4380
+ export type NativeInspectedMembers = {
4381
+ /** How many members match in all. */
4382
+ total: number;
4383
+ /** This page's members. */
4384
+ members: NativeInspectedMember[];
4385
+ };
4386
+ /** One value read by `objc.inspectValues`; `text` describes it for display. */
4387
+ export type NativeInspectedValue = {
4388
+ /** The member the value was read from. */
4389
+ name: string;
4390
+ /** What the value is; `skipped` was not read and `error` failed to read. */
4391
+ kind:
4392
+ | 'nil'
4393
+ | 'number'
4394
+ | 'bool'
4395
+ | 'string'
4396
+ | 'object'
4397
+ | 'class'
4398
+ | 'struct'
4399
+ | 'pointer'
4400
+ | 'selector'
4401
+ | 'other'
4402
+ | 'skipped'
4403
+ | 'error';
4404
+ /** The value as text, strings cut to 500 characters. */
4405
+ text: string;
4406
+ /** A handle to the value, for `kind: 'object'`. */
4407
+ object?: NativeObjectHandle;
4408
+ /** The class of an object or class value. */
4409
+ className?: string;
4410
+ };
4158
4411
  /** An argument to a Java call: a tagged value or a handle. */
4159
4412
  export type NativeJavaArgument = NativeJavaValue | NativeJavaHandle;
4160
4413
  /** A key from `java.createAssociationKey` that names one associated value. */
@@ -4178,6 +4431,11 @@ export type NativeJavaBridge = {
4178
4431
  getClass(name: string): NativeJavaHandle;
4179
4432
  /** Lists a class's constructors, methods and fields. */
4180
4433
  describe(name: string): NativeJavaClassDescription;
4434
+ /**
4435
+ * Finds Discord's classes by shape, so a lookup survives the obfuscated names changing between builds; results
4436
+ * are cached per Discord build. Needs `native.java.classSearch`.
4437
+ */
4438
+ findClasses(query: NativeJavaClassQuery): NativeCancelablePromise<string[]>;
4181
4439
  /** Runs independent operations in one call on the JavaScript thread and returns every result in order. */
4182
4440
  batch(operations: NativeJavaBatchOperation[]): NativeJavaValue[];
4183
4441
  /** Runs the operations like `batch`, on the main thread, so views can be read safely. */
@@ -4265,6 +4523,21 @@ export type NativeJavaClassDescription = {
4265
4523
  /** The fields the class declares. */
4266
4524
  fields: NativeJavaFieldDescription[];
4267
4525
  };
4526
+ /** What `java.findClasses` matches; library packages are skipped unless `package` names one. */
4527
+ export type NativeJavaClassQuery = {
4528
+ /** The class name starts with it, such as `com.discord.`. */
4529
+ package?: string;
4530
+ /** The class inherits from it, directly or further up. */
4531
+ extends?: string;
4532
+ /** The class implements every one, directly or through a superclass. */
4533
+ implements?: string[];
4534
+ /** Methods the class must have, every one matching. */
4535
+ methods?: NativeJavaMethodShape[];
4536
+ /** Fields the class must declare, every one matching. */
4537
+ fields?: NativeJavaFieldShape[];
4538
+ /** At most this many names, 50 by default and 1000 at most. */
4539
+ limit?: number;
4540
+ };
4268
4541
  /** One field a Java class declares, from `java.describe`. */
4269
4542
  export type NativeJavaFieldDescription = {
4270
4543
  /** The field name. */
@@ -4274,6 +4547,15 @@ export type NativeJavaFieldDescription = {
4274
4547
  /** Whether the field is static. */
4275
4548
  static: boolean;
4276
4549
  };
4550
+ /** A field a class from `java.findClasses` must declare. */
4551
+ export type NativeJavaFieldShape = {
4552
+ /** The field's name. */
4553
+ name?: string;
4554
+ /** The field type's fully qualified name. */
4555
+ type?: string;
4556
+ /** Whether the field is static. */
4557
+ static?: boolean;
4558
+ };
4277
4559
  /** A handle to a Java object or class; the plugin scope releases it on dispose. */
4278
4560
  export type NativeJavaHandle = NativeHandle;
4279
4561
  /** A Java object reference the bridge returns inside a result. */
@@ -4306,6 +4588,10 @@ export type NativeJavaHookOptions<Receiver extends boolean = boolean> = {
4306
4588
  rewriteArguments?: boolean;
4307
4589
  /** Trims the receiver, arguments and phase each event sends, to cut crossing cost on hot methods. */
4308
4590
  payload?: NativeHookPayload<Receiver>;
4591
+ /** Also hooks every subclass that declares the method itself, found by `java.findClasses` once it answers. */
4592
+ subclasses?: boolean;
4593
+ /** Waits for a class that is not loaded yet, retrying with backoff for up to ten minutes. */
4594
+ waitForClass?: boolean;
4309
4595
  };
4310
4596
  /** What a `rewriteArguments` listener returns to run the hooked method with other arguments, one per parameter. */
4311
4597
  export type NativeJavaHookRewrite = {
@@ -4364,6 +4650,19 @@ export type NativeJavaMethodDescription = {
4364
4650
  /** Whether the method is static. */
4365
4651
  static: boolean;
4366
4652
  };
4653
+ /** A method a class from `java.findClasses` must have; every given part must match. */
4654
+ export type NativeJavaMethodShape = {
4655
+ /** The method's name. */
4656
+ name?: string;
4657
+ /** The parameter types' fully qualified names, in order. */
4658
+ parameters?: string[];
4659
+ /** The return type's fully qualified name. */
4660
+ returns?: string;
4661
+ /** Whether the method is static. */
4662
+ static?: boolean;
4663
+ /** Whether the class itself declares it rather than inheriting it; `true` by default. */
4664
+ declared?: boolean;
4665
+ };
4367
4666
  /** A Java object implementing interfaces through a handler; remove its token to stop it answering. */
4368
4667
  export type NativeJavaProxy = {
4369
4668
  /** Removes the proxy with `hooks.remove`; the UI scope removes it on dispose. */
@@ -4450,6 +4749,19 @@ export type NativeMainWorkCounts = {
4450
4749
  /** The most items one drain ran. */
4451
4750
  maxDrainItems: number;
4452
4751
  };
4752
+ /** The device's active connection. */
4753
+ export type NativeNetworkState = {
4754
+ /** The kind of connection, or `offline` with none. */
4755
+ type: 'wifi' | 'cellular' | 'ethernet' | 'other' | 'offline';
4756
+ /** The connection bills by data. */
4757
+ metered?: boolean;
4758
+ /** Low Data Mode (iOS) or Data Saver (Android) is on. */
4759
+ lowData?: boolean;
4760
+ /** Traffic goes through a VPN. */
4761
+ vpn?: boolean;
4762
+ /** A system HTTP proxy is set. */
4763
+ proxy?: boolean;
4764
+ };
4453
4765
  /** The iOS bridge to the Objective-C runtime, scoped to the plugin's capabilities. */
4454
4766
  export type NativeObjCBridge = {
4455
4767
  /** Looks up a class by name, or returns `null` when none is registered. */
@@ -4565,11 +4877,89 @@ export type NativeObjCBridge = {
4565
4877
  handlers: NativeHookHandlers<Receiver>,
4566
4878
  options?: NativeHookOptions<Receiver>,
4567
4879
  ): NativeHookToken;
4880
+ /**
4881
+ * Makes an Objective-C block that calls `implementation` on the JavaScript thread, for completion handlers,
4882
+ * notification observers and enumeration blocks. Needs `native.objc.blocks`.
4883
+ */
4884
+ block(
4885
+ signature: NativeFFISignature,
4886
+ implementation: (...args: never[]) => NativeObjCResult | void,
4887
+ ): NativeObjectHandle;
4888
+ /** Calls a block, such as a completion handler a hook received, with an explicit signature. Needs `native.objc.blocks`. */
4889
+ callBlock(
4890
+ block: NativeObjectHandle,
4891
+ signature: NativeFFISignature,
4892
+ ...args: NativeObjCResult[]
4893
+ ): NativeObjCResult;
4894
+ /** Finds loaded classes by shape, so a lookup survives renamed classes. Needs `native.objc.classSearch`. */
4895
+ findClasses(query: NativeObjCClassQuery): string[];
4896
+ /**
4897
+ * Defines an Objective-C class at runtime whose methods run JavaScript, for delegates, data sources and
4898
+ * target-action receivers; defining it again replaces its methods. Needs `native.objc.classDefinition`.
4899
+ */
4900
+ defineClass(
4901
+ name: string,
4902
+ superclass: string,
4903
+ methods: Record<string, NativeObjCMethodDefinition>,
4904
+ protocols?: string[],
4905
+ ): NativeClassHandle;
4568
4906
  };
4569
4907
  /** A selector and method signature resolved once by `objc.prepare`, for calling many times without the lookup. */
4570
4908
  export type NativeObjCCallPlan = NativeHandle & {
4571
4909
  readonly [nativeObjCCallPlan]: true;
4572
4910
  };
4911
+ /** What `objc.findClasses` matches; every given part must match, and names come back sorted. */
4912
+ export type NativeObjCClassQuery = {
4913
+ /** The class name starts with it. */
4914
+ prefix?: string;
4915
+ /** The path of the image the class is in contains it, such as `Discord.app/Discord`. */
4916
+ image?: string;
4917
+ /** The class inherits from it, directly or further up. */
4918
+ superclass?: string;
4919
+ /** The class conforms to every one. */
4920
+ protocols?: string[];
4921
+ /** The class responds to every instance selector, its own or inherited. */
4922
+ methods?: string[];
4923
+ /** The class itself implements every instance selector. */
4924
+ ownMethods?: string[];
4925
+ /** The class responds to every class selector. */
4926
+ classMethods?: string[];
4927
+ /** At most this many names, 50 by default and 1000 at most. */
4928
+ limit?: number;
4929
+ };
4930
+ /**
4931
+ * The debugger's Objective-C reflection, iOS only and never in a plugin's scope. Needs `native.objc.inspect`.
4932
+ * Throws `INSPECTOR_DISABLED` without developer mode or the debugger, `INSPECTOR_UNAVAILABLE` when the library cannot load.
4933
+ */
4934
+ export type NativeObjCInspector = {
4935
+ /** Describes a class, or an object's class, and its superclasses; throws `INSPECTOR_UNKNOWN_CLASS` for an unknown name. */
4936
+ inspectClass(target: NativeObjectHandle | string): NativeInspectedClass[];
4937
+ /** Lists one page of one kind of a class's own members. */
4938
+ inspectMembers(
4939
+ className: string,
4940
+ kind: NativeInspectKind,
4941
+ page?: NativeInspectPage,
4942
+ ): NativeInspectedMembers;
4943
+ /** Reads up to 50 properties or ivars of an object on the main thread; getters run only with `invokeGetters`. */
4944
+ inspectValues(
4945
+ object: NativeObjectHandle,
4946
+ className: string,
4947
+ kind: 'properties' | 'ivars',
4948
+ names: string[],
4949
+ options?: NativeInspectValuesOptions,
4950
+ ): NativeCancelablePromise<NativeInspectedValue[]>;
4951
+ /** Lists one page of the loaded images that define Objective-C classes. */
4952
+ inspectImages(page?: NativeInspectPage): NativeInspectedImages;
4953
+ /** Lists one page of the class names an image defines, sorted. */
4954
+ inspectClasses(imagePath: string, page?: NativeInspectPage): NativeInspectedClasses;
4955
+ };
4956
+ /** One method of a class `objc.defineClass` makes: its signature without `self` and `_cmd`, and what runs. */
4957
+ export type NativeObjCMethodDefinition = {
4958
+ /** The method's argument and return types, without `self` and `_cmd`. */
4959
+ signature: NativeFFISignature;
4960
+ /** Runs on the JavaScript thread with the receiver and the method's arguments. */
4961
+ implementation: (self: NativeObjectHandle, ...args: never[]) => NativeObjCResult | void;
4962
+ };
4573
4963
  /** What an Objective-C call returns: a plain value, a handle to an object, a 64-bit integer, or nothing for `void`. */
4574
4964
  export type NativeObjCResult = NativeSerializable | NativeHandle | bigint | undefined;
4575
4965
  /** A retained handle to an Objective-C object. */
@@ -4609,6 +4999,8 @@ export type NativePlatformApp = {
4609
4999
  getAppSource(): string;
4610
5000
  /** How an iOS install was signed: certificate kind, team, profile expiry, sideload tool marker and entitlement source. */
4611
5001
  getInstallDetails?(): string;
5002
+ /** What the loader read about the install, the binary and the device for `/debug`; missing on older loaders. */
5003
+ getEnvironment?(): NativeEnvironmentReport;
4612
5004
  /** The framework that injected the loader, such as Vector or LSPosed on Android and ElleKit on iOS, or an empty string. */
4613
5005
  getFramework(): string;
4614
5006
  /** Whether the loader's embedded attestation verified against Unbound's pinned key. False for development builds. */
@@ -4672,6 +5064,8 @@ export type NativePlatformDevice = {
4672
5064
  isSystemApp(): boolean;
4673
5065
  /** Whether Discord runs in a simulator, emulator or virtual machine. */
4674
5066
  isVirtualDevice(): boolean;
5067
+ /** Memory and thermal pressure right now; empty on loaders older than 1.4.0. */
5068
+ getState?(): NativeDeviceState;
4675
5069
  };
4676
5070
  /** File operations inside the Unbound folder in Discord's documents directory. */
4677
5071
  export type NativePlatformFiles = {
package/src/flux.d.ts CHANGED
@@ -73,6 +73,10 @@ export declare function useStore<const S extends FluxStore | readonly FluxStore[
73
73
  * `declare module '@unbound-app/api/flux' { interface FluxActions { MY_ACTION: { id: string } } }`.
74
74
  */
75
75
  export interface FluxActions {
76
+ /** Discord moved to the front, the background, or in between, as React Native's `AppState` reports it. */
77
+ APP_STATE_UPDATE: {
78
+ state: 'active' | 'background' | 'inactive';
79
+ };
76
80
  /** A message arrived or was sent; `optimistic` is `true` for the local copy before Discord confirms it. */
77
81
  MESSAGE_CREATE: {
78
82
  channelId: string;
package/src/global.d.ts CHANGED
@@ -262,10 +262,13 @@ export type {
262
262
  NativeDebugEnvironmentOptions,
263
263
  NativeDebugEvaluation,
264
264
  NativeDebugEvaluationLog,
265
+ NativeDeviceState,
265
266
  NativeFFIBridge,
267
+ NativeFFIRebinding,
266
268
  NativeFFISignature,
267
269
  NativeFFIType,
268
270
  NativeFFITypeName,
271
+ NativeFFIValue,
269
272
  NativeFabricBatchMutation,
270
273
  NativeFabricBridge,
271
274
  NativeFabricFrame,
@@ -281,13 +284,25 @@ export type {
281
284
  NativeHookOptions,
282
285
  NativeHookPayload,
283
286
  NativeHookToken,
287
+ NativeInspectKind,
288
+ NativeInspectPage,
289
+ NativeInspectValuesOptions,
290
+ NativeInspectedClass,
291
+ NativeInspectedClasses,
292
+ NativeInspectedImage,
293
+ NativeInspectedImages,
294
+ NativeInspectedMember,
295
+ NativeInspectedMembers,
296
+ NativeInspectedValue,
284
297
  NativeJavaArgument,
285
298
  NativeJavaAssociationKey,
286
299
  NativeJavaBatchOperation,
287
300
  NativeJavaBridge,
288
301
  NativeJavaCallPlan,
289
302
  NativeJavaClassDescription,
303
+ NativeJavaClassQuery,
290
304
  NativeJavaFieldDescription,
305
+ NativeJavaFieldShape,
291
306
  NativeJavaHandle,
292
307
  NativeJavaHandleValue,
293
308
  NativeJavaHookEvent,
@@ -296,14 +311,19 @@ export type {
296
311
  NativeJavaHookToken,
297
312
  NativeJavaHooksBridge,
298
313
  NativeJavaMethodDescription,
314
+ NativeJavaMethodShape,
299
315
  NativeJavaProxy,
300
316
  NativeJavaProxyCall,
301
317
  NativeJavaReference,
302
318
  NativeJavaValue,
303
319
  NativeMainWaitCounts,
304
320
  NativeMainWorkCounts,
321
+ NativeNetworkState,
305
322
  NativeObjCBridge,
306
323
  NativeObjCCallPlan,
324
+ NativeObjCClassQuery,
325
+ NativeObjCInspector,
326
+ NativeObjCMethodDefinition,
307
327
  NativeObjCResult,
308
328
  NativeObjectHandle,
309
329
  NativePlatformAddons,
@@ -28,10 +28,10 @@ export type CatalogQuery = {
28
28
  sort?: CatalogSort;
29
29
  };
30
30
  /**
31
- * `name` sorts alphabetically, `popular` puts the most installed addons first, `updated` the most
32
- * recently published versions.
31
+ * `new` puts the most recently listed addons first, `name` sorts alphabetically, `popular` the most
32
+ * installed addons first, `updated` the most recently published versions.
33
33
  */
34
- export type CatalogSort = 'name' | 'popular' | 'updated';
34
+ export type CatalogSort = 'new' | 'name' | 'popular' | 'updated';
35
35
  /** One addon the marketplace lists, at its newest version. */
36
36
  export type MarketplaceListing = {
37
37
  /** The addon's id from its manifest, which installs and updates key on. */
@@ -4,7 +4,14 @@ export type { DesignComponentName, DesignModule } from '../_internal';
4
4
  export { DESIGN_COMPONENTS } from '../_internal';
5
5
  import type { DesignComponentName, DesignModule } from '../_internal';
6
6
  import * as React$1 from 'react';
7
- import { ComponentProps, ComponentType, ElementType, FunctionComponent, ReactNode } from 'react';
7
+ import {
8
+ ComponentProps,
9
+ ComponentType,
10
+ Context,
11
+ ElementType,
12
+ FunctionComponent,
13
+ ReactNode,
14
+ } from 'react';
8
15
  import * as RN from 'react-native';
9
16
  import { ColorValue, ImageStyle, TextStyle, ViewStyle } from 'react-native';
10
17
 
@@ -149,7 +149,14 @@ import type {
149
149
  } from '../_internal';
150
150
  import type { LiteralUnion, PredicateResult } from '../_types';
151
151
  import * as React$1 from 'react';
152
- import { ComponentProps, ComponentType, ElementType, FunctionComponent, ReactNode } from 'react';
152
+ import {
153
+ ComponentProps,
154
+ ComponentType,
155
+ Context,
156
+ ElementType,
157
+ FunctionComponent,
158
+ ReactNode,
159
+ } from 'react';
153
160
  import * as RN from 'react-native';
154
161
  import {
155
162
  ColorValue,
package/src/native.d.ts CHANGED
@@ -75,6 +75,11 @@ import type {
75
75
  NativeBridgeCapability,
76
76
  NativeBridgeMethod,
77
77
  NativeBridgePlatform,
78
+ NativeJavaBridge,
79
+ NativeJavaHandleValue,
80
+ NativeJavaReference,
81
+ NativeObjCBridge,
82
+ NativeObjectHandle,
78
83
  NativePlatformBridge,
79
84
  NativeResourceCounts,
80
85
  } from './_internal';
@@ -167,6 +172,28 @@ export declare function reload(): Promise<void>;
167
172
  * @returns Whether the loader implements it.
168
173
  */
169
174
  export declare function supports(method: NativeBridgeMethod): boolean;
175
+ /**
176
+ * @description Holds a Java object weakly, through a `java.lang.ref.WeakReference`, so caching a view does not keep
177
+ * it alive after Discord drops it.
178
+ * @param java The plugin's Java bridge.
179
+ * @param handle The object to hold.
180
+ * @returns A weak handle whose `deref` gives the object while it lives, then `null`.
181
+ */
182
+ export declare function weakJava(
183
+ java: Pick<NativeJavaBridge, 'construct' | 'invoke'>,
184
+ handle: NativeJavaReference,
185
+ ): NativeWeakHandle<NativeJavaHandleValue>;
186
+ /**
187
+ * @description Holds an Objective-C object weakly, through a `strongToWeakObjectsMapTable`, so caching a view or
188
+ * controller does not keep it alive after Discord releases it.
189
+ * @param objc The plugin's Objective-C bridge.
190
+ * @param handle The object to hold.
191
+ * @returns A weak handle whose `deref` gives the object while it lives, then `null`.
192
+ */
193
+ export declare function weakObjC(
194
+ objc: Pick<NativeObjCBridge, 'getClass' | 'call'>,
195
+ handle: NativeObjectHandle,
196
+ ): NativeWeakHandle<NativeObjectHandle>;
170
197
  /** Build and release metadata reported by the native client info module. */
171
198
  export type BundleInfoType = {
172
199
  /** Discord's app version, shown in Unbound's settings beside `Build`. */
@@ -268,6 +295,11 @@ export type DeviceInfoType = {
268
295
  };
269
296
  /** What `HermesInternal.getRuntimeProperties()` reports; empty when the engine is not Hermes. */
270
297
  export type HermesRuntimeProperties = ReturnType<HermesInternalObject['getRuntimeProperties']>;
298
+ /** A reference that does not keep its native object alive; `deref` reads `null` once the object is gone. */
299
+ export type NativeWeakHandle<T> = {
300
+ /** The object while it lives, else `null`. */
301
+ deref(): T | null;
302
+ };
271
303
  /** One Platform handler per platform an addon runs on. */
272
304
  export type PlatformHandlers<Handler> = Partial<Record<NativeBridgePlatform, Handler>>;
273
305
  /** A native method Discord exposes without documenting what its promise resolves to. */
package/src/ui.d.ts CHANGED
@@ -10,9 +10,17 @@ import type {
10
10
  } from './_internal';
11
11
  import type { Without } from './_types';
12
12
  import * as React$1 from 'react';
13
- import { ComponentProps, ComponentType, FunctionComponent, ReactElement, ReactNode } from 'react';
13
+ import {
14
+ ComponentProps,
15
+ ComponentType,
16
+ Context,
17
+ FunctionComponent,
18
+ ReactElement,
19
+ ReactNode,
20
+ Ref,
21
+ } from 'react';
14
22
  import * as RN from 'react-native';
15
- import { ImageStyle, TextStyle, ViewStyle } from 'react-native';
23
+ import { ImageStyle, ScrollView, ScrollViewProps, TextStyle, ViewStyle } from 'react-native';
16
24
  /**
17
25
  * @description A pressable `TableRow` in its settings group, as Discord draws actions such as Log Out; it asks first when
18
26
  * `confirmation` is set. `danger` draws the label red behind a red trash icon.
@@ -150,7 +158,7 @@ export declare function NumberRow({
150
158
  * inset and a 24px gap between form groups, matching how Discord lays out its own settings screens. Use
151
159
  * it as the root of every settings page.
152
160
  */
153
- export declare function Page({ children }: PageProps): React$1.ReactElement;
161
+ export declare function Page({ children, ...scroll }: PageProps): React$1.ReactElement;
154
162
  /**
155
163
  * @description A row showing the picked option that opens Discord's action sheet listing every option, for choices too many for a radio group.
156
164
  * @param props The row's label, picked value, options and change handler.
@@ -236,7 +244,7 @@ export declare function SegmentedRow({
236
244
  }: SegmentedRowProps): React$1.ReactElement;
237
245
  /**
238
246
  * @description Discord's `TableSliderRow`, as its own settings draw one: the label and live value over the slider
239
- * with its default mark. A sub-label, which that row cannot show, moves it to a `TableRow` holding the same slider.
247
+ * with its default mark. A sub-label, which that row cannot show, draws the same layout by hand with it under the label.
240
248
  * The value is saved when the drag ends; Android's slider and iOS's take differently named props, so it passes both.
241
249
  * @param props The row's label, value, default, range and change handler.
242
250
  * @returns The row, or `null` when Discord's slider is unavailable.
@@ -471,9 +479,14 @@ export type NumberRowProps = NumberConstraints & {
471
479
  onChange: (value: number) => void;
472
480
  };
473
481
  /** The props of {@link Page}. */
474
- export type PageProps = {
482
+ export type PageProps = Pick<
483
+ ScrollViewProps,
484
+ 'onScrollEndDrag' | 'onMomentumScrollEnd' | 'onContentSizeChange'
485
+ > & {
475
486
  /** The page's form groups, laid out top to bottom with a 24px gap. */
476
487
  children: React$1.ReactNode;
488
+ /** The page's scroll view, for a page that restores its scroll offset. */
489
+ ref?: React$1.Ref<ScrollView>;
477
490
  };
478
491
  /** Props for `PickerRow`. */
479
492
  export type PickerRowProps = {
@@ -16,9 +16,12 @@ const BAGS = [
16
16
  'Discord',
17
17
  'FlashList',
18
18
  'Forms',
19
+ 'GorhomSheet',
19
20
  'Media',
20
21
  'Portal',
21
22
  'SafeArea',
23
+ 'SafeAreaContext',
24
+ 'TableRowDividers',
22
25
  'Video',
23
26
  ] as const;
24
27
 
@@ -8,7 +8,6 @@ import type {
8
8
  NativeJavaHookEvent,
9
9
  NativeJavaHookOptions,
10
10
  NativeJavaHooksBridge,
11
- NativeJavaProxyCall,
12
11
  NativeJavaReference,
13
12
  NativeJavaValue,
14
13
  } from '../src/native';
@@ -74,11 +73,17 @@ export type FakeJava = {
74
73
  /** Makes an object of a registered class, with its fields, as the plugin sees it: a tagged `handle` value. */
75
74
  create: (className: string, fields?: Record<string, JavaPlain>) => NativeJavaValue;
76
75
  /** Calls `method` on a proxy made with `hooks.proxy`, as Java would, and returns what its handler returned. */
77
- callProxy: (proxy: NativeJavaArgument, method: string, args?: JavaPlain[]) => unknown;
76
+ callProxy: (
77
+ proxy: NativeJavaArgument,
78
+ method: string,
79
+ args?: JavaPlain[],
80
+ ) => NativeJavaArgument | undefined;
78
81
  /** Forgets every class, object, hook and proxy. */
79
82
  reset: () => void;
80
83
  };
81
84
 
85
+ type ProxyHandler = Parameters<NativeJavaHooksBridge['proxy']>[1];
86
+
82
87
  type HookEntry = {
83
88
  className: string;
84
89
  methodName: string;
@@ -142,7 +147,7 @@ export function createFakeJava(log: NativeCallLog = createCallLog()): FakeJava {
142
147
  const classes = new Map<string, JavaClassSpec>();
143
148
  const objects = new Map<string, JavaObject>();
144
149
  const hookEntries = new Map<string, HookEntry>();
145
- const proxyHandlers = new Map<string, (call: NativeJavaProxyCall) => unknown>();
150
+ const proxyHandlers = new Map<string, ProxyHandler>();
146
151
  const proxyTokens = new Map<string, string>();
147
152
  let next = 0;
148
153
 
@@ -506,10 +511,12 @@ export function createFakeJava(log: NativeCallLog = createCallLog()): FakeJava {
506
511
 
507
512
  const object = proxyTokens.get(token.id);
508
513
 
509
- if (object) {
510
- proxyHandlers.delete(object);
511
- proxyTokens.delete(token.id);
514
+ if (!object) {
515
+ return;
512
516
  }
517
+
518
+ proxyHandlers.delete(object);
519
+ proxyTokens.delete(token.id);
513
520
  },
514
521
  proxy(interfaces, handler) {
515
522
  const object = spawn(interfaces[0] ?? 'java.lang.Object', false);
@@ -532,7 +539,7 @@ export function createFakeJava(log: NativeCallLog = createCallLog()): FakeJava {
532
539
  function callProxy(proxy: NativeJavaArgument, method: string, args: JavaPlain[] = []) {
533
540
  const object = resolve(proxy as NativeJavaReference, 'callProxy');
534
541
 
535
- return proxyHandlers.get(object.id)?.({ method, args: args.map(tagged) });
542
+ return proxyHandlers.get(object.id)?.({ method, args: args.map(tagged) }) ?? undefined;
536
543
  }
537
544
 
538
545
  return {