@unbound-app/api 3.0.0 → 3.1.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.0.0",
3
+ "version": "3.1.0",
4
4
  "author": {
5
5
  "name": "Mario P.",
6
6
  "email": "contact@marioparaschiv.com",
@@ -180,6 +180,7 @@ export declare const NATIVE_BRIDGE_METHOD_CAPABILITIES: {
180
180
  readonly 'hooks.removeReturnValue': 'native.java.hooks';
181
181
  readonly 'hooks.clearReturnValues': 'native.java.hooks';
182
182
  readonly 'hooks.remove': 'native.java.hooks';
183
+ readonly 'hooks.proxy': 'native.java.hooks';
183
184
  };
184
185
  /** The host platforms a native bridge runs on. */
185
186
  export declare const NATIVE_BRIDGE_PLATFORMS: readonly ['ios', 'android'];
@@ -4301,9 +4302,16 @@ export type NativeJavaHookOptions<Receiver extends boolean = boolean> = {
4301
4302
  replace?: boolean;
4302
4303
  /** Whether the listener hears calls: before the method by default, `after` once it has run, `false` never. */
4303
4304
  notify?: boolean | 'after';
4305
+ /** Lets a `before` listener hooked from a UI scope return `{ arguments }` to run the method with them instead. */
4306
+ rewriteArguments?: boolean;
4304
4307
  /** Trims the receiver, arguments and phase each event sends, to cut crossing cost on hot methods. */
4305
4308
  payload?: NativeHookPayload<Receiver>;
4306
4309
  };
4310
+ /** What a `rewriteArguments` listener returns to run the hooked method with other arguments, one per parameter. */
4311
+ export type NativeJavaHookRewrite = {
4312
+ /** The arguments to run the method with, in parameter order. */
4313
+ arguments: NativeJavaArgument[];
4314
+ };
4307
4315
  /** An installed Java hook; the plugin scope removes it on dispose. */
4308
4316
  export type NativeJavaHookToken = {
4309
4317
  /** The id the loader issued, such as `hook-1`. */
@@ -4317,7 +4325,7 @@ export type NativeJavaHooksBridge = {
4317
4325
  methodName: string,
4318
4326
  parameterTypes: string[],
4319
4327
  options?: NativeJavaHookOptions<Receiver>,
4320
- listener?: (event: NativeJavaHookEvent<Receiver>) => void,
4328
+ listener?: (event: NativeJavaHookEvent<Receiver>) => NativeJavaHookRewrite | void,
4321
4329
  ): NativeJavaHookToken;
4322
4330
  /** Sets the result a `replace` hook returns for calls with this receiver and these arguments. */
4323
4331
  setReturnValue(
@@ -4334,8 +4342,16 @@ export type NativeJavaHooksBridge = {
4334
4342
  ): void;
4335
4343
  /** Removes every result set on a hook. */
4336
4344
  clearReturnValues(token: NativeJavaHookToken): void;
4337
- /** Removes a hook. */
4345
+ /** Removes a hook or a proxy. */
4338
4346
  remove(token: NativeJavaHookToken): void;
4347
+ /**
4348
+ * Creates a Java object implementing `interfaces`, from a UI scope only. Calls on the main thread run `handler`
4349
+ * inline and return its value; calls on other threads reach it later and return the type's default.
4350
+ */
4351
+ proxy(
4352
+ interfaces: string[],
4353
+ handler: (call: NativeJavaProxyCall) => NativeJavaArgument | void,
4354
+ ): NativeJavaProxy;
4339
4355
  };
4340
4356
  /** One method a Java class declares, from `java.describe`. */
4341
4357
  export type NativeJavaMethodDescription = {
@@ -4348,6 +4364,20 @@ export type NativeJavaMethodDescription = {
4348
4364
  /** Whether the method is static. */
4349
4365
  static: boolean;
4350
4366
  };
4367
+ /** A Java object implementing interfaces through a handler; remove its token to stop it answering. */
4368
+ export type NativeJavaProxy = {
4369
+ /** Removes the proxy with `hooks.remove`; the UI scope removes it on dispose. */
4370
+ token: NativeJavaHookToken;
4371
+ /** The object to pass wherever Java expects one of the interfaces. */
4372
+ object: NativeJavaHandle;
4373
+ };
4374
+ /** What a proxy handler receives for one call of an interface method. */
4375
+ export type NativeJavaProxyCall = {
4376
+ /** The interface method's name, such as `onPreDraw`. */
4377
+ method: string;
4378
+ /** The call's arguments. */
4379
+ args: NativeJavaValue[];
4380
+ };
4351
4381
  /** A Java object, as a handle or as a tagged handle value from a result. */
4352
4382
  export type NativeJavaReference = NativeJavaHandle | NativeJavaHandleValue;
4353
4383
  /** A Java value tagged with its type, as the Java bridge returns and accepts it. */
@@ -4577,6 +4607,8 @@ export type NativePlatformAndroidInstaller = {
4577
4607
  export type NativePlatformApp = {
4578
4608
  /** Where Discord was installed from, such as `App Store` or `Google Play`. */
4579
4609
  getAppSource(): string;
4610
+ /** How an iOS install was signed: certificate kind, team, profile expiry, sideload tool marker and entitlement source. */
4611
+ getInstallDetails?(): string;
4580
4612
  /** The framework that injected the loader, such as Vector or LSPosed on Android and ElleKit on iOS, or an empty string. */
4581
4613
  getFramework(): string;
4582
4614
  /** Whether the loader's embedded attestation verified against Unbound's pinned key. False for development builds. */
@@ -6516,6 +6548,21 @@ export type UnboundAsset = DiscordAsset & {
6516
6548
  /** The URI of a registered plugin asset at each scale; set while it is registered. */
6517
6549
  unboundSources?: Record<number, string>;
6518
6550
  };
6551
+ /** One design axis of a variable font, such as `wght` from 100 to 900. */
6552
+ export type UnboundFontAxis = {
6553
+ /** The four-letter tag, such as `wght`, `wdth` or `slnt`. */
6554
+ tag: string;
6555
+ /** The name the font gives it, such as `Weight`. */
6556
+ name: string;
6557
+ /** The lowest value the axis accepts. */
6558
+ min: number;
6559
+ /** The value a face draws at when the axis is not set. */
6560
+ default: number;
6561
+ /** The highest value the axis accepts. */
6562
+ max: number;
6563
+ /** The font asks apps not to offer it. */
6564
+ hidden: boolean;
6565
+ };
6519
6566
  /**
6520
6567
  * One installed face in the loader's font store.
6521
6568
  * @internal
@@ -6533,6 +6580,10 @@ type UnboundInstalledFont = {
6533
6580
  /** The file's absolute path; `list()` adds it. */
6534
6581
  path?: string;
6535
6582
  source: UnboundFontSource;
6583
+ /** A variable font's design axes; absent for a static face. */
6584
+ axes?: UnboundFontAxis[];
6585
+ /** The coordinate on each axis this face draws at, such as `{ wght: 650 }`; absent for a static face. */
6586
+ variations?: Record<string, number>;
6536
6587
  };
6537
6588
  /** A value the generator could not type with confidence, so a loose prop accepts anything for it. */
6538
6589
  export type UncertainValue = any;
package/src/global.d.ts CHANGED
@@ -292,9 +292,12 @@ export type {
292
292
  NativeJavaHandleValue,
293
293
  NativeJavaHookEvent,
294
294
  NativeJavaHookOptions,
295
+ NativeJavaHookRewrite,
295
296
  NativeJavaHookToken,
296
297
  NativeJavaHooksBridge,
297
298
  NativeJavaMethodDescription,
299
+ NativeJavaProxy,
300
+ NativeJavaProxyCall,
298
301
  NativeJavaReference,
299
302
  NativeJavaValue,
300
303
  NativeMainWaitCounts,
@@ -513,6 +516,7 @@ export type {
513
516
  TransitionState,
514
517
  UnboundAppIcon,
515
518
  UnboundAsset,
519
+ UnboundFontAxis,
516
520
  UncertainValue,
517
521
  VisualEffectViewProps,
518
522
  VoidIconProps,
package/src/native.d.ts CHANGED
@@ -43,9 +43,12 @@ export type {
43
43
  NativeJavaHandleValue,
44
44
  NativeJavaHookEvent,
45
45
  NativeJavaHookOptions,
46
+ NativeJavaHookRewrite,
46
47
  NativeJavaHookToken,
47
48
  NativeJavaHooksBridge,
48
49
  NativeJavaMethodDescription,
50
+ NativeJavaProxy,
51
+ NativeJavaProxyCall,
49
52
  NativeJavaReference,
50
53
  NativeJavaValue,
51
54
  NativeObjCBridge,
@@ -8,6 +8,7 @@ import type {
8
8
  NativeJavaHookEvent,
9
9
  NativeJavaHookOptions,
10
10
  NativeJavaHooksBridge,
11
+ NativeJavaProxyCall,
11
12
  NativeJavaReference,
12
13
  NativeJavaValue,
13
14
  } from '../src/native';
@@ -72,7 +73,9 @@ export type FakeJava = {
72
73
  registerClass: (name: string, spec?: JavaClassSpec) => void;
73
74
  /** Makes an object of a registered class, with its fields, as the plugin sees it: a tagged `handle` value. */
74
75
  create: (className: string, fields?: Record<string, JavaPlain>) => NativeJavaValue;
75
- /** Forgets every class, object and hook. */
76
+ /** 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;
78
+ /** Forgets every class, object, hook and proxy. */
76
79
  reset: () => void;
77
80
  };
78
81
 
@@ -139,6 +142,8 @@ export function createFakeJava(log: NativeCallLog = createCallLog()): FakeJava {
139
142
  const classes = new Map<string, JavaClassSpec>();
140
143
  const objects = new Map<string, JavaObject>();
141
144
  const hookEntries = new Map<string, HookEntry>();
145
+ const proxyHandlers = new Map<string, (call: NativeJavaProxyCall) => unknown>();
146
+ const proxyTokens = new Map<string, string>();
142
147
  let next = 0;
143
148
 
144
149
  function chain(className: string): string[] {
@@ -496,18 +501,52 @@ export function createFakeJava(log: NativeCallLog = createCallLog()): FakeJava {
496
501
  removeReturnValue: (token, self) =>
497
502
  void hookEntries.get(token.id)?.results.delete(tagKey(self)),
498
503
  clearReturnValues: (token) => hookEntries.get(token.id)?.results.clear(),
499
- remove: (token) => void hookEntries.delete(token.id),
504
+ remove(token) {
505
+ hookEntries.delete(token.id);
506
+
507
+ const object = proxyTokens.get(token.id);
508
+
509
+ if (object) {
510
+ proxyHandlers.delete(object);
511
+ proxyTokens.delete(token.id);
512
+ }
513
+ },
514
+ proxy(interfaces, handler) {
515
+ const object = spawn(interfaces[0] ?? 'java.lang.Object', false);
516
+ const id = `proxy-${++next}`;
517
+
518
+ log.record({
519
+ bridge: 'hooks',
520
+ method: 'proxy',
521
+ target: interfaces.join(','),
522
+ name: 'proxy',
523
+ args: [],
524
+ });
525
+ proxyHandlers.set(object.id, handler);
526
+ proxyTokens.set(id, object.id);
527
+
528
+ return { token: { id }, object: brand<NativeJavaHandle>(object) };
529
+ },
500
530
  });
501
531
 
532
+ function callProxy(proxy: NativeJavaArgument, method: string, args: JavaPlain[] = []) {
533
+ const object = resolve(proxy as NativeJavaReference, 'callProxy');
534
+
535
+ return proxyHandlers.get(object.id)?.({ method, args: args.map(tagged) });
536
+ }
537
+
502
538
  return {
503
539
  bridge,
504
540
  hooks,
505
541
  registerClass: (name, spec = {}) => void classes.set(name, spec),
506
542
  create: (className, fields) => tagged(brand<NativeJavaHandle>(instance(className, fields))),
543
+ callProxy,
507
544
  reset() {
508
545
  classes.clear();
509
546
  objects.clear();
510
547
  hookEntries.clear();
548
+ proxyHandlers.clear();
549
+ proxyTokens.clear();
511
550
  },
512
551
  };
513
552
  }