@tsukilabs/nil-ffi 0.7.5 → 0.7.6

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/dist/index.d.ts CHANGED
@@ -6,21 +6,20 @@ import * as ffi from "node:ffi";
6
6
  export * from './def';
7
7
  export * from './error';
8
8
  export type Handle = ffi.DynamicLibraryResult<typeof definitions>;
9
- export type { ErrorHandler } from './queue';
9
+ export type { ErrorHandler, QueueOptions } from './queue';
10
10
  export declare const VERSION: string;
11
11
  export declare const USER_AGENT: string;
12
- export declare class Nil implements Disposable {
12
+ export declare class Nil implements AsyncDisposable {
13
+ #private;
13
14
  readonly path: string;
14
15
  private readonly handle;
15
- readonly functions: Handle["functions"];
16
+ private readonly functions;
16
17
  private readonly queue;
17
- private disposed;
18
+ private closed;
19
+ private closePromise;
18
20
  private constructor();
19
- static init(dll: string, options?: NilOptions): Promise<Nil>;
20
- static initLatest(outDir?: Option<string>, options?: NilOptions): Promise<Nil>;
21
- static downloadLatest(outDir?: Option<string>): Promise<string>;
22
- [Symbol.dispose](): void;
23
- close(): void;
21
+ [Symbol.asyncDispose](): Promise<void>;
22
+ close(): Promise<void>;
24
23
  isClosed(): boolean;
25
24
  authorize(req: AuthorizeRequest): Promise<string>;
26
25
  getClientVersion(): Promise<string>;
@@ -46,12 +45,19 @@ export declare class Nil implements Disposable {
46
45
  setUserAgent(userAgent: string): Promise<import('@tb-dev/utils').nil>;
47
46
  spawnPlayer(req: SpawnPlayerRequest): Promise<import('@tb-dev/utils').nil>;
48
47
  startServer(options: WorldOptions): Promise<LocalServer>;
49
- startServerWithSavedata(path: string): Promise<LocalServer>;
48
+ startServerWithSavedata(savedataPath: string): Promise<LocalServer>;
50
49
  stopClient(): Promise<import('@tb-dev/utils').nil>;
51
50
  stopServer(): Promise<import('@tb-dev/utils').nil>;
52
51
  updateClient(options: ClientOptions): Promise<import('@tb-dev/utils').nil>;
53
52
  validateToken(req: ValidateTokenRequest): Promise<ValidateTokenResponse>;
53
+ static init(dll: string, options?: NilOptions): Promise<Nil>;
54
+ static initLatest(options?: InitLatestOptions): Promise<Nil>;
55
+ static downloadLatest(options?: DownloadLatestOptions): Promise<string>;
56
+ }
57
+ export interface NilOptions extends QueueOptions {
54
58
  }
55
- export interface NilOptions {
56
- onError?: QueueOptions["onError"];
59
+ export interface DownloadLatestOptions {
60
+ outDir?: Option<string>;
61
+ overwrite?: boolean;
57
62
  }
63
+ export type InitLatestOptions = DownloadLatestOptions & NilOptions;
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import * as ffi from "node:ffi";
2
+ import * as path from "node:path";
2
3
  import * as process from "node:process";
3
4
  import { cwd } from "node:process";
5
+ import { existsSync } from "node:fs";
6
+ import * as fs from "node:fs/promises";
4
7
  import { ffi_Status } from "@tsukilabs/nil-bindings";
5
- import { writeFile } from "node:fs/promises";
8
+ import { attemptAsync } from "es-toolkit/util";
6
9
  import { EventEmitter } from "node:events";
7
10
  import { isNil } from "es-toolkit/predicate";
8
- import { join, resolve } from "node:path";
9
11
  //#region src/def.ts
10
12
  //! Copyright (C) Call of Nil contributors
11
13
  //! SPDX-License-Identifier: AGPL-3.0-only
@@ -752,7 +754,7 @@ var Queue = class Queue {
752
754
  };
753
755
  //#endregion
754
756
  //#region package.json
755
- var version = "0.7.5";
757
+ var version = "0.7.6";
756
758
  //#endregion
757
759
  //#region \0@oxc-project+runtime@0.139.0/helpers/esm/decorate.js
758
760
  function __decorate(decorators, target, key, desc) {
@@ -769,43 +771,31 @@ var VERSION = version;
769
771
  var USER_AGENT = `nil-ffi-node/${VERSION}`;
770
772
  var Nil = class Nil {
771
773
  constructor(dll, options) {
772
- this.disposed = false;
774
+ this.closed = false;
773
775
  if (!dll.endsWith(ffi.suffix)) dll = `${dll}.${ffi.suffix}`;
774
- this.path = resolve(dll);
776
+ this.path = path.resolve(dll);
775
777
  this.handle = ffi.dlopen(dll, definitions);
776
778
  this.functions = this.handle.functions;
777
779
  this.queue = new Queue(this.handle, options);
778
780
  }
779
- static async init(dll, options) {
780
- const nil = new Nil(dll, options);
781
- await nil.setUserAgent(USER_AGENT);
782
- return nil;
783
- }
784
- static async initLatest(outDir, options) {
785
- const dll = await this.downloadLatest(outDir);
786
- return this.init(dll, options);
787
- }
788
- static async downloadLatest(outDir) {
789
- const file = `libnil.${ffi.suffix}`;
790
- const response = await fetch(`https://tsukilabs.dev.br/${file}`);
791
- if (!response.ok) throw new Error(`failed to download ${file}: ${response.status} ${response.statusText}`);
792
- const bytes = await response.bytes();
793
- const path = join(outDir ?? cwd(), file);
794
- await writeFile(path, bytes);
795
- return resolve(path);
781
+ async [Symbol.asyncDispose]() {
782
+ await this.close();
796
783
  }
797
- [Symbol.dispose]() {
798
- this.close();
799
- }
800
- close() {
801
- if (this.disposed) return;
802
- this.disposed = true;
784
+ async #close() {
785
+ if (this.closed) return;
786
+ this.closed = true;
787
+ await attemptAsync(this.stopClient.bind(this));
788
+ await attemptAsync(this.stopServer.bind(this));
803
789
  this.queue[Symbol.dispose]();
804
790
  this.functions.nil_ffi_shutdown();
805
791
  this.handle[Symbol.dispose]();
806
792
  }
793
+ async close() {
794
+ this.closePromise ??= this.#close();
795
+ return this.closePromise;
796
+ }
807
797
  isClosed() {
808
- return this.disposed;
798
+ return this.closed;
809
799
  }
810
800
  async authorize(req) {
811
801
  return this.queue.request((requestId) => {
@@ -927,9 +917,9 @@ var Nil = class Nil {
927
917
  this.functions.nil_start_server(requestId, JSON.stringify(options));
928
918
  });
929
919
  }
930
- async startServerWithSavedata(path) {
920
+ async startServerWithSavedata(savedataPath) {
931
921
  return this.queue.request((requestId) => {
932
- this.functions.nil_start_server_with_savedata(requestId, JSON.stringify(path));
922
+ this.functions.nil_start_server_with_savedata(requestId, JSON.stringify(savedataPath));
933
923
  });
934
924
  }
935
925
  async stopClient() {
@@ -952,6 +942,25 @@ var Nil = class Nil {
952
942
  this.functions.nil_validate_token(requestId, JSON.stringify(req));
953
943
  });
954
944
  }
945
+ static async init(dll, options) {
946
+ const nil = new Nil(dll, options);
947
+ await nil.setUserAgent(USER_AGENT);
948
+ return nil;
949
+ }
950
+ static async initLatest(options) {
951
+ const dll = await this.downloadLatest(options);
952
+ return this.init(dll, options);
953
+ }
954
+ static async downloadLatest(options) {
955
+ const file = `libnil.${ffi.suffix}`;
956
+ const filePath = path.resolve(options?.outDir ?? cwd(), file);
957
+ if (!(options?.overwrite ?? true) && existsSync(filePath)) return filePath;
958
+ const response = await fetch(`https://tsukilabs.dev.br/download/nil/${file}`, { headers: { "User-Agent": USER_AGENT } });
959
+ if (!response.ok) throw new Error(`failed to download ${file}: ${response.status} ${response.statusText}`);
960
+ const bytes = await response.bytes();
961
+ await fs.writeFile(filePath, bytes);
962
+ return filePath;
963
+ }
955
964
  };
956
965
  __decorate([ThrowIfClosed], Nil.prototype, "authorize", null);
957
966
  __decorate([ThrowIfClosed], Nil.prototype, "getClientVersion", null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tsukilabs/nil-ffi",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "description": "FFI bindings for Call of Nil",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.18.0",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@tb-dev/utils": "^8.1.1",
34
- "@tsukilabs/nil-bindings": "^0.7.4",
34
+ "@tsukilabs/nil-bindings": "^0.7.5",
35
35
  "es-toolkit": "^1.50.0"
36
36
  },
37
37
  "files": ["dist"],