@efffrida/frida-tools 0.0.14 → 0.0.16

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 (92) hide show
  1. package/README.md +6 -10
  2. package/dist/{dts/FridaDevice.d.ts → FridaDevice.d.ts} +48 -4
  3. package/dist/FridaDevice.d.ts.map +1 -0
  4. package/dist/{esm/FridaDevice.js → FridaDevice.js} +22 -2
  5. package/dist/FridaDevice.js.map +1 -0
  6. package/dist/{dts/FridaDeviceAcquisitionError.d.ts → FridaDeviceAcquisitionError.d.ts} +2 -1
  7. package/dist/FridaDeviceAcquisitionError.d.ts.map +1 -0
  8. package/dist/{esm/FridaDeviceAcquisitionError.js → FridaDeviceAcquisitionError.js} +5 -1
  9. package/dist/FridaDeviceAcquisitionError.js.map +1 -0
  10. package/dist/FridaScript.d.ts +104 -0
  11. package/dist/FridaScript.d.ts.map +1 -0
  12. package/dist/{esm/FridaScript.js → FridaScript.js} +5 -0
  13. package/dist/FridaScript.js.map +1 -0
  14. package/dist/FridaSession.d.ts +72 -0
  15. package/dist/FridaSession.d.ts.map +1 -0
  16. package/dist/{esm/FridaSession.js → FridaSession.js} +10 -0
  17. package/dist/FridaSession.js.map +1 -0
  18. package/dist/FridaSessionError.d.ts.map +1 -0
  19. package/dist/FridaSessionError.js.map +1 -0
  20. package/dist/{dts/index.d.ts → index.d.ts} +8 -5
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/{esm/index.js → index.js} +3 -0
  23. package/dist/index.js.map +1 -0
  24. package/dist/{dts/internal → internal}/device.d.ts.map +1 -1
  25. package/dist/internal/device.js +189 -0
  26. package/dist/internal/device.js.map +1 -0
  27. package/dist/{dts/internal → internal}/script.d.ts.map +1 -1
  28. package/dist/internal/script.js +229 -0
  29. package/dist/internal/script.js.map +1 -0
  30. package/dist/{dts/internal → internal}/session.d.ts.map +1 -1
  31. package/dist/internal/session.js +124 -0
  32. package/dist/internal/session.js.map +1 -0
  33. package/package.json +54 -68
  34. package/src/FridaDevice.ts +92 -8
  35. package/src/FridaDeviceAcquisitionError.ts +6 -2
  36. package/src/FridaScript.ts +67 -31
  37. package/src/FridaSession.ts +31 -5
  38. package/src/FridaSessionError.ts +1 -1
  39. package/src/index.ts +9 -5
  40. package/src/internal/device.ts +311 -32
  41. package/src/internal/script.ts +286 -118
  42. package/src/internal/session.ts +136 -27
  43. package/FridaDevice/package.json +0 -6
  44. package/FridaDeviceAcquisitionError/package.json +0 -6
  45. package/FridaScript/package.json +0 -6
  46. package/FridaSession/package.json +0 -6
  47. package/FridaSessionError/package.json +0 -6
  48. package/dist/cjs/FridaDevice.js +0 -60
  49. package/dist/cjs/FridaDevice.js.map +0 -1
  50. package/dist/cjs/FridaDeviceAcquisitionError.js +0 -33
  51. package/dist/cjs/FridaDeviceAcquisitionError.js.map +0 -1
  52. package/dist/cjs/FridaScript.js +0 -40
  53. package/dist/cjs/FridaScript.js.map +0 -1
  54. package/dist/cjs/FridaSession.js +0 -45
  55. package/dist/cjs/FridaSession.js.map +0 -1
  56. package/dist/cjs/FridaSessionError.js +0 -37
  57. package/dist/cjs/FridaSessionError.js.map +0 -1
  58. package/dist/cjs/index.js +0 -18
  59. package/dist/cjs/index.js.map +0 -1
  60. package/dist/cjs/internal/device.js +0 -68
  61. package/dist/cjs/internal/device.js.map +0 -1
  62. package/dist/cjs/internal/script.js +0 -163
  63. package/dist/cjs/internal/script.js.map +0 -1
  64. package/dist/cjs/internal/session.js +0 -55
  65. package/dist/cjs/internal/session.js.map +0 -1
  66. package/dist/dts/FridaDevice.d.ts.map +0 -1
  67. package/dist/dts/FridaDeviceAcquisitionError.d.ts.map +0 -1
  68. package/dist/dts/FridaScript.d.ts +0 -80
  69. package/dist/dts/FridaScript.d.ts.map +0 -1
  70. package/dist/dts/FridaSession.d.ts +0 -56
  71. package/dist/dts/FridaSession.d.ts.map +0 -1
  72. package/dist/dts/FridaSessionError.d.ts.map +0 -1
  73. package/dist/dts/index.d.ts.map +0 -1
  74. package/dist/esm/FridaDevice.js.map +0 -1
  75. package/dist/esm/FridaDeviceAcquisitionError.js.map +0 -1
  76. package/dist/esm/FridaScript.js.map +0 -1
  77. package/dist/esm/FridaSession.js.map +0 -1
  78. package/dist/esm/FridaSessionError.js.map +0 -1
  79. package/dist/esm/index.js.map +0 -1
  80. package/dist/esm/internal/device.js +0 -55
  81. package/dist/esm/internal/device.js.map +0 -1
  82. package/dist/esm/internal/script.js +0 -155
  83. package/dist/esm/internal/script.js.map +0 -1
  84. package/dist/esm/internal/session.js +0 -44
  85. package/dist/esm/internal/session.js.map +0 -1
  86. package/dist/esm/package.json +0 -4
  87. package/index/package.json +0 -6
  88. /package/dist/{dts/FridaSessionError.d.ts → FridaSessionError.d.ts} +0 -0
  89. /package/dist/{esm/FridaSessionError.js → FridaSessionError.js} +0 -0
  90. /package/dist/{dts/internal → internal}/device.d.ts +0 -0
  91. /package/dist/{dts/internal → internal}/script.d.ts +0 -0
  92. /package/dist/{dts/internal → internal}/session.d.ts +0 -0
@@ -1,21 +1,24 @@
1
1
  import type * as Scope from "effect/Scope";
2
- import type * as FridaScript from "../FridaScript.js";
2
+ import type * as FridaScript from "../FridaScript.ts";
3
3
 
4
+ import * as Path from "@effect/platform/Path";
5
+ import * as Cause from "effect/Cause";
4
6
  import * as Context from "effect/Context";
5
7
  import * as Deferred from "effect/Deferred";
6
8
  import * as Effect from "effect/Effect";
9
+ import * as Exit from "effect/Exit";
7
10
  import * as Function from "effect/Function";
8
11
  import * as Layer from "effect/Layer";
12
+ import * as Mailbox from "effect/Mailbox";
9
13
  import * as Option from "effect/Option";
10
14
  import * as Predicate from "effect/Predicate";
11
- import * as Queue from "effect/Queue";
15
+ import * as Schema from "effect/Schema";
12
16
  import * as Sink from "effect/Sink";
13
17
  import * as Stream from "effect/Stream";
14
- import * as Take from "effect/Take";
15
18
  import * as Frida from "frida";
16
- import * as FridaDevice from "../FridaDevice.js";
17
- import * as FridaSession from "../FridaSession.js";
18
- import * as FridaSessionError from "../FridaSessionError.js";
19
+
20
+ import * as FridaSession from "../FridaSession.ts";
21
+ import * as FridaSessionError from "../FridaSessionError.ts";
19
22
 
20
23
  /** @internal */
21
24
  export const FridaScriptTypeId: FridaScript.FridaScriptTypeId = Symbol.for(
@@ -28,182 +31,347 @@ export const Tag = Context.GenericTag<FridaScript.FridaScript>("@efffrida/frida-
28
31
  /** @internal */
29
32
  export const isFridaScript = (u: unknown): u is FridaScript.FridaScript => Predicate.hasProperty(u, FridaScriptTypeId);
30
33
 
34
+ /** @internal */
35
+ export const compile = Function.dual<
36
+ (
37
+ options?: Frida.CompilerOptions | undefined
38
+ ) => (path: string) => Effect.Effect<string, FridaSessionError.FridaSessionError, Scope.Scope>,
39
+ (
40
+ path: string,
41
+ options?: Frida.CompilerOptions | undefined
42
+ ) => Effect.Effect<string, FridaSessionError.FridaSessionError, Scope.Scope>
43
+ >(
44
+ (arguments_) => Predicate.isString(arguments_[0]),
45
+ (path: string, options?: Frida.CompilerOptions | undefined) =>
46
+ Effect.asyncEffect<string, FridaSessionError.FridaSessionError, never, never, never, Scope.Scope>(
47
+ Effect.fnUntraced(function* (resume) {
48
+ // https://github.com/frida/frida-compile/blob/e81ae27369466c69868fc6ee36c0f227bbfe340c/src/cli.ts#L173-L182
49
+ interface Diagnostic {
50
+ category: string;
51
+ code: number;
52
+ text: string;
53
+ file?: {
54
+ path: string;
55
+ line: number;
56
+ character: number;
57
+ };
58
+ }
59
+
60
+ const formatDiagnostic = (diagnostic: Diagnostic): FridaSessionError.FridaSessionError => {
61
+ const location = diagnostic.file
62
+ ? `${diagnostic.file.path}:${diagnostic.file.line}:${diagnostic.file.character}`
63
+ : undefined;
64
+ const message = `TS${diagnostic.code}: ${diagnostic.text}`;
65
+ const cause = location ? `${location} - ${message}` : message;
66
+ return new FridaSessionError.FridaSessionError({ cause, when: "compile" });
67
+ };
68
+
69
+ const compileErrors: Array<Diagnostic> = [];
70
+ const compiler = new Frida.Compiler();
71
+
72
+ const onOutput = (bundle: string) => resume(Effect.succeed(bundle));
73
+ yield* Effect.addFinalizer(() => Effect.sync(() => compiler.output.disconnect(onOutput)));
74
+ compiler.output.connect(onOutput);
75
+
76
+ const onDiagnostic = (diagnostic: Array<Diagnostic>) => {
77
+ for (const diag of diagnostic) {
78
+ if (diag.category === "error") {
79
+ compileErrors.push(diag);
80
+ }
81
+ }
82
+ };
83
+ yield* Effect.addFinalizer(() => Effect.sync(() => compiler.diagnostics.disconnect(onDiagnostic)));
84
+ compiler.diagnostics.connect(onDiagnostic);
85
+
86
+ const onFinished = () => {
87
+ if (compileErrors.length > 0) {
88
+ resume(
89
+ Effect.failCauseSync(() => {
90
+ const [first, ...rest] = compileErrors;
91
+ let cause = Cause.fail(formatDiagnostic(first));
92
+ for (const diag of rest) {
93
+ cause = Cause.parallel(cause, Cause.fail(formatDiagnostic(diag)));
94
+ }
95
+ return cause;
96
+ })
97
+ );
98
+ }
99
+ };
100
+ yield* Effect.addFinalizer(() => Effect.sync(() => compiler.finished.disconnect(onFinished)));
101
+ compiler.finished.connect(onFinished);
102
+
103
+ const cancellable = new Frida.Cancellable();
104
+ compiler
105
+ .build(
106
+ path,
107
+ {
108
+ externals: options?.externals,
109
+ projectRoot: options?.projectRoot,
110
+ platform: options?.platform ?? Frida.JsPlatform.Gum,
111
+ typeCheck: options?.typeCheck ?? Frida.TypeCheckMode.Full,
112
+ sourceMaps: options?.sourceMaps ?? Frida.SourceMaps.Included,
113
+ compression: options?.compression ?? Frida.JsCompression.None,
114
+ bundleFormat: options?.bundleFormat ?? Frida.BundleFormat.Esm,
115
+ outputFormat: options?.outputFormat ?? Frida.OutputFormat.Unescaped,
116
+ },
117
+ cancellable
118
+ )
119
+ .catch((error) =>
120
+ resume(
121
+ Effect.fail(
122
+ new FridaSessionError.FridaSessionError({
123
+ cause: error,
124
+ when: "compile",
125
+ })
126
+ )
127
+ )
128
+ );
129
+
130
+ return Effect.sync(() => cancellable.cancel());
131
+ })
132
+ )
133
+ );
134
+
31
135
  /** @internal */
32
136
  export const load = Function.dual<
33
137
  (
34
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
138
+ options?: FridaScript.LoadOptions | undefined
35
139
  ) => (
36
- source: string | Buffer
140
+ entrypoint: URL
37
141
  ) => Effect.Effect<
38
142
  FridaScript.FridaScript,
39
143
  FridaSessionError.FridaSessionError,
40
- FridaSession.FridaSession | FridaDevice.FridaDevice | Scope.Scope
144
+ Path.Path | FridaSession.FridaSession | Scope.Scope
41
145
  >,
42
146
  (
43
- source: string | Buffer,
44
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
147
+ entrypoint: URL,
148
+ options?: FridaScript.LoadOptions | undefined
45
149
  ) => Effect.Effect<
46
150
  FridaScript.FridaScript,
47
151
  FridaSessionError.FridaSessionError,
48
- FridaSession.FridaSession | FridaDevice.FridaDevice | Scope.Scope
152
+ Path.Path | FridaSession.FridaSession | Scope.Scope
49
153
  >
50
154
  >(
51
- (arguments_) => Predicate.isString(arguments_[0]) || Buffer.isBuffer(arguments_[0]),
155
+ (arguments_) => Predicate.hasProperty(arguments_[0], "href"),
52
156
  Effect.fnUntraced(
53
- function* (
54
- source: string | Buffer,
55
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
56
- ) {
57
- const { device } = yield* FridaDevice.FridaDevice;
157
+ function* (entrypoint: URL, options?: FridaScript.LoadOptions | undefined) {
158
+ const path = yield* Path.Path;
58
159
  const { session } = yield* FridaSession.FridaSession;
59
160
 
60
- const script = Predicate.isString(source)
61
- ? yield* Effect.tryPromise({
62
- try: () => session.createScript(source, { runtime: Frida.ScriptRuntime.V8, ...options }),
63
- catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "compile" }),
64
- })
65
- : yield* Effect.tryPromise({
66
- try: () => session.createScriptFromBytes(source, { runtime: Frida.ScriptRuntime.V8, ...options }),
67
- catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "compile" }),
68
- });
69
-
70
- const messageQueue =
71
- yield* Queue.unbounded<
72
- Take.Take<{ message: any; data: Option.Option<Buffer> }, FridaSessionError.FridaSessionError>
73
- >();
74
-
75
- let scriptDefectCause: unknown = undefined;
161
+ const projectRoot = yield* path
162
+ .fromFileUrl(entrypoint)
163
+ .pipe(
164
+ Effect.mapError(
165
+ (cause) =>
166
+ new FridaSessionError.FridaSessionError({
167
+ when: "compile",
168
+ cause,
169
+ })
170
+ )
171
+ )
172
+ .pipe(Effect.map((p) => path.dirname(p)));
173
+
174
+ const source = yield* path
175
+ .fromFileUrl(entrypoint)
176
+ .pipe(
177
+ Effect.flatMap(
178
+ compile({
179
+ ...options,
180
+ projectRoot: options?.projectRoot ?? projectRoot,
181
+ })
182
+ )
183
+ )
184
+ .pipe(Effect.scoped)
185
+ .pipe(
186
+ Effect.timeoutFail({
187
+ duration: "1 minute",
188
+ onTimeout: () =>
189
+ new FridaSessionError.FridaSessionError({
190
+ when: "compile",
191
+ cause: "TypeScript compilation timed out",
192
+ }),
193
+ })
194
+ )
195
+ .pipe(
196
+ Effect.catchTag(
197
+ "BadArgument",
198
+ (platformCause) =>
199
+ new FridaSessionError.FridaSessionError({
200
+ when: "compile",
201
+ cause: platformCause,
202
+ })
203
+ )
204
+ );
205
+
206
+ const script = yield* Effect.tryPromise({
207
+ try: (signal) => {
208
+ const cancellable = new Frida.Cancellable();
209
+ signal.onabort = () => cancellable.cancel();
210
+ return session.createScript(
211
+ source,
212
+ {
213
+ runtime: Frida.ScriptRuntime.V8,
214
+ ...options,
215
+ },
216
+ cancellable
217
+ );
218
+ },
219
+ catch: (cause) =>
220
+ new FridaSessionError.FridaSessionError({
221
+ cause,
222
+ when: "compile",
223
+ }),
224
+ });
225
+
226
+ const destroyed = yield* Deferred.make<void, never>();
227
+ const scriptError = yield* Deferred.make<unknown, never>();
228
+ const mailbox = yield* Mailbox.make<
229
+ { message: unknown; data: Option.Option<Buffer> },
230
+ FridaSessionError.FridaSessionError
231
+ >(options?.messageMailboxCapacity);
232
+ yield* Effect.addFinalizer(() => mailbox.shutdown); // TODO: is this needed?
233
+
234
+ const destroyedHandler: Frida.ScriptDestroyedHandler = () => {
235
+ Deferred.unsafeDone(destroyed, Effect.void);
236
+ mailbox.unsafeDone(
237
+ Exit.fail(
238
+ new FridaSessionError.FridaSessionError({
239
+ when: "message",
240
+ cause: "Script destroyed",
241
+ })
242
+ )
243
+ );
244
+ };
245
+ yield* Effect.addFinalizer(() => Effect.sync(() => script.destroyed.disconnect(destroyedHandler)));
246
+ script.destroyed.connect(destroyedHandler);
247
+
76
248
  const messageHandler: Frida.ScriptMessageHandler = (message: Frida.Message, data: Buffer | null): void => {
77
249
  switch (message.type) {
78
250
  case Frida.MessageType.Error: {
79
- const error = new Error();
80
- error.name = "FridaScriptDefect";
81
- error.stack = message.stack ?? "";
82
- error.message = message.description.replace(/Error: /, "") ?? "";
83
- scriptDefectCause = error;
84
- const sessionError = new FridaSessionError.FridaSessionError({
85
- when: "message",
86
- cause: error.cause,
87
- });
88
- const asTake = Take.fail(sessionError);
89
- Queue.unsafeOffer(messageQueue, asTake);
251
+ const cause = new Error();
252
+ cause.name = "FridaScriptDefect";
253
+ cause.stack = message.stack ?? "";
254
+ cause.message = message.description.replace(/^\w{0,}: /, "") ?? "";
255
+ Deferred.unsafeDone(scriptError, Exit.succeed(cause));
256
+ mailbox.unsafeDone(
257
+ Exit.fail(
258
+ new FridaSessionError.FridaSessionError({
259
+ when: "message",
260
+ cause,
261
+ })
262
+ )
263
+ );
90
264
  break;
91
265
  }
92
266
 
93
267
  case Frida.MessageType.Send: {
94
- const asTake = Take.of({ message: message.payload, data: Option.fromNullable(data) });
95
- Queue.unsafeOffer(messageQueue, asTake);
268
+ mailbox.unsafeOffer({
269
+ message: message.payload,
270
+ data: Option.fromNullable(data),
271
+ });
96
272
  break;
97
273
  }
98
274
 
99
- default:
100
- Function.absurd(message);
275
+ default: {
276
+ return Function.absurd(message);
277
+ }
101
278
  }
102
279
  };
103
-
104
- const disconnectMessageHandler = Effect.sync(() => script.message.disconnect(messageHandler));
105
- yield* Effect.addFinalizer(() => Effect.flatMap(messageQueue.shutdown, () => disconnectMessageHandler));
280
+ yield* Effect.addFinalizer(() => Effect.sync(() => script.message.disconnect(messageHandler)));
106
281
  script.message.connect(messageHandler);
107
282
 
108
- const stream = Stream.fromQueue(messageQueue).pipe(Stream.flattenTake);
283
+ const failIfScriptError = (when: FridaSessionError.FridaSessionError["when"]) =>
284
+ Effect.if(Deferred.isDone(scriptError), {
285
+ onFalse: () => Effect.void,
286
+ onTrue: () =>
287
+ Effect.flatMap(
288
+ Deferred.await(scriptError),
289
+ (cause) => new FridaSessionError.FridaSessionError({ cause, when })
290
+ ),
291
+ });
292
+
293
+ const failIfDestroyed = (when: FridaSessionError.FridaSessionError["when"]) =>
294
+ Effect.if(Deferred.isDone(destroyed), {
295
+ onFalse: () => Effect.void,
296
+ onTrue: () => new FridaSessionError.FridaSessionError({ cause: "Script is destroyed", when }),
297
+ });
298
+
299
+ const stream = yield* Stream.share(
300
+ Mailbox.toStream(mailbox),
301
+ options?.streamShareOptions ?? {
302
+ replay: 100,
303
+ capacity: "unbounded",
304
+ }
305
+ );
306
+
109
307
  const sink = Sink.forEach<
110
- { message: any; data: Option.Option<Buffer> },
308
+ { message: unknown; data: Option.Option<Buffer> },
111
309
  void,
112
310
  FridaSessionError.FridaSessionError,
113
311
  never
114
- >(({ data, message }) => {
115
- if (Predicate.isNotUndefined(scriptDefectCause)) {
116
- return Effect.fail(
117
- new FridaSessionError.FridaSessionError({
118
- when: "rpcCall",
119
- cause: scriptDefectCause,
120
- })
121
- );
122
- } else {
123
- return Effect.sync(() => script.post(message, Option.getOrNull(data)));
124
- }
125
- });
312
+ >(
313
+ Effect.fnUntraced(function* ({ data, message }) {
314
+ yield* failIfDestroyed("message");
315
+ yield* failIfScriptError("message");
316
+ script.post(message, Option.getOrNull(data));
317
+ })
318
+ );
126
319
 
127
- const destroyed = yield* Deferred.make<void, never>();
128
- const destroyedHandler = () => Deferred.unsafeDone(destroyed, Effect.void);
129
- script.destroyed.connect(destroyedHandler);
130
-
131
- const callExport = (exportName: string) =>
320
+ const callExport = <A, I, R>(exportName: string, schema: Schema.Schema<A, I, R>) =>
132
321
  Effect.fn(`call frida export ${exportName}`)(function* (...args: Array<any>) {
133
322
  yield* Effect.annotateCurrentSpan("args", args);
134
-
135
- const isDestroyed = yield* Deferred.isDone(destroyed);
136
- if (isDestroyed) {
137
- return yield* new FridaSessionError.FridaSessionError({
138
- when: "rpcCall",
139
- cause: "Script is destroyed",
140
- });
141
- }
142
-
143
- if (Predicate.isNotUndefined(scriptDefectCause)) {
144
- return yield* new FridaSessionError.FridaSessionError({
145
- when: "rpcCall",
146
- cause: scriptDefectCause,
147
- });
148
- }
149
-
323
+ yield* failIfDestroyed("rpcCall");
324
+ yield* failIfScriptError("rpcCall");
150
325
  const result = yield* Effect.tryPromise({
151
326
  try: () => script.exports[exportName](...args) as Promise<unknown>,
152
327
  catch: (cause) => new FridaSessionError.FridaSessionError({ when: "rpcCall", cause }),
153
328
  });
154
-
155
329
  yield* Effect.annotateCurrentSpan("result", result);
156
- return result;
330
+ return yield* Schema.decodeUnknown(schema)(result);
157
331
  });
158
332
 
159
333
  yield* Effect.tryPromise({
160
- try: () => script.load(),
334
+ try: (signal) => {
335
+ const cancellable = new Frida.Cancellable();
336
+ signal.onabort = () => cancellable.cancel();
337
+ return script.load(cancellable);
338
+ },
161
339
  catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "load" }),
162
340
  });
163
341
 
164
- if (options?.resume === true) {
165
- yield* Effect.tryPromise({
166
- try: () => device.resume(session.pid),
167
- catch: (cause) => new FridaSessionError.FridaSessionError({ cause, when: "resume" }),
168
- });
169
- }
170
-
171
342
  return {
172
343
  sink,
173
- script,
174
344
  stream,
345
+ script,
175
346
  destroyed,
176
347
  callExport,
348
+ scriptError,
177
349
  [FridaScriptTypeId]: FridaScriptTypeId,
178
350
  } as const;
179
351
  },
180
- Effect.acquireRelease(({ script }: FridaScript.FridaScript) => Effect.promise(() => script.unload()))
352
+ Effect.acquireRelease(({ script }: FridaScript.FridaScript) =>
353
+ Effect.promise((signal) => {
354
+ const cancellable = new Frida.Cancellable();
355
+ signal.onabort = () => cancellable.cancel();
356
+ return script.unload(cancellable);
357
+ })
358
+ )
181
359
  )
182
360
  );
183
361
 
184
362
  /** @internal */
185
363
  export const layer = Function.dual<
186
364
  (
187
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
365
+ options?: FridaScript.LoadOptions | undefined
188
366
  ) => (
189
- source: string | Buffer
190
- ) => Layer.Layer<
191
- FridaScript.FridaScript,
192
- FridaSessionError.FridaSessionError,
193
- FridaSession.FridaSession | FridaDevice.FridaDevice
194
- >,
367
+ entrypoint: URL
368
+ ) => Layer.Layer<FridaScript.FridaScript, FridaSessionError.FridaSessionError, FridaSession.FridaSession>,
195
369
  (
196
- source: string | Buffer,
197
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
198
- ) => Layer.Layer<
199
- FridaScript.FridaScript,
200
- FridaSessionError.FridaSessionError,
201
- FridaSession.FridaSession | FridaDevice.FridaDevice
202
- >
370
+ entrypoint: URL,
371
+ options?: FridaScript.LoadOptions | undefined
372
+ ) => Layer.Layer<FridaScript.FridaScript, FridaSessionError.FridaSessionError, FridaSession.FridaSession>
203
373
  >(
204
- (arguments_) => Predicate.isString(arguments_[0]),
205
- (
206
- source: string | Buffer,
207
- options?: (Frida.ScriptOptions & { readonly resume?: boolean | undefined }) | undefined
208
- ) => Layer.scoped(Tag, load(source, options))
374
+ (arguments_) => Predicate.hasProperty(arguments_[0], "href"),
375
+ (entrypoint: URL, options?: FridaScript.LoadOptions | undefined) =>
376
+ Layer.scoped(Tag, load(entrypoint, options)).pipe(Layer.provide(Path.layer))
209
377
  );