diff --git a/__test__/index.spec.js b/__test__/index.spec.js index 6ac9d28..355b071 100644 --- a/__test__/index.spec.js +++ b/__test__/index.spec.js @@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const ava_1 = __importDefault(require("ava")); const node_process_1 = __importDefault(require("node:process")); -const indax_1 = require("../indax"); +const index_1 = require("../index"); const smbURL = node_process_1.default.env.SMB_URL || 'smb://127.0.0.1/Users/Shared/smb/'; //const smbPath = process.env.SMB_PATH; let cachedRoot; @@ -30,7 +30,7 @@ let testPermissions = false; let testResolve = false; async function getRootHandle() { if (!cachedRoot) { - cachedRoot = new indax_1.SmbDirectoryHandle(smbURL); + cachedRoot = new index_1.SmbDirectoryHandle(smbURL); } //let cachedRoot = new SmbDirectoryHandle(smbURL); let subRoot = cachedRoot; diff --git a/__test__/index.spec.ts b/__test__/index.spec.ts index 92131e1..0ea8be2 100644 --- a/__test__/index.spec.ts +++ b/__test__/index.spec.ts @@ -19,7 +19,7 @@ import test from 'ava' import process from 'node:process'; -import { SmbDirectoryHandle, SmbFileHandle } from '../indax'; +import { SmbDirectoryHandle, SmbFileHandle } from '../index'; const smbURL = process.env.SMB_URL || 'smb://127.0.0.1/Users/Shared/smb/'; //const smbPath = process.env.SMB_PATH; diff --git a/binding.cjs b/binding.cjs new file mode 100644 index 0000000..e1c454b --- /dev/null +++ b/binding.cjs @@ -0,0 +1,310 @@ +/* tslint:disable */ +/* eslint-disable */ +/* prettier-ignore */ + +/* auto-generated by NAPI-RS */ + +const { existsSync, readFileSync } = require('fs') +const { join } = require('path') + +const { platform, arch } = process + +let nativeBinding = null +let localFileExisted = false +let loadError = null + +function isMusl() { + // For Node 10 + if (!process.report || typeof process.report.getReport !== 'function') { + try { + const lddPath = require('child_process').execSync('which ldd').toString().trim() + return readFileSync(lddPath, 'utf8').includes('musl') + } catch (e) { + return true + } + } else { + const { glibcVersionRuntime } = process.report.getReport().header + return !glibcVersionRuntime + } +} + +switch (platform) { + case 'android': + switch (arch) { + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'smb-js.android-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.android-arm64.node') + } else { + nativeBinding = require('@netapplabs/smb-js-android-arm64') + } + } catch (e) { + loadError = e + } + break + case 'arm': + localFileExisted = existsSync(join(__dirname, 'smb-js.android-arm-eabi.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.android-arm-eabi.node') + } else { + nativeBinding = require('@netapplabs/smb-js-android-arm-eabi') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Android ${arch}`) + } + break + case 'win32': + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'smb-js.win32-x64-msvc.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.win32-x64-msvc.node') + } else { + nativeBinding = require('@netapplabs/smb-js-win32-x64-msvc') + } + } catch (e) { + loadError = e + } + break + case 'ia32': + localFileExisted = existsSync(join(__dirname, 'smb-js.win32-ia32-msvc.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.win32-ia32-msvc.node') + } else { + nativeBinding = require('@netapplabs/smb-js-win32-ia32-msvc') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'smb-js.win32-arm64-msvc.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.win32-arm64-msvc.node') + } else { + nativeBinding = require('@netapplabs/smb-js-win32-arm64-msvc') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Windows: ${arch}`) + } + break + case 'darwin': + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.darwin-universal.node') + } else { + nativeBinding = require('@netapplabs/smb-js-darwin-universal') + } + break + } catch {} + switch (arch) { + case 'x64': + localFileExisted = existsSync(join(__dirname, 'smb-js.darwin-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.darwin-x64.node') + } else { + nativeBinding = require('@netapplabs/smb-js-darwin-x64') + } + } catch (e) { + loadError = e + } + break + case 'arm64': + localFileExisted = existsSync(join(__dirname, 'smb-js.darwin-arm64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.darwin-arm64.node') + } else { + nativeBinding = require('@netapplabs/smb-js-darwin-arm64') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on macOS: ${arch}`) + } + break + case 'freebsd': + if (arch !== 'x64') { + throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + } + localFileExisted = existsSync(join(__dirname, 'smb-js.freebsd-x64.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.freebsd-x64.node') + } else { + nativeBinding = require('@netapplabs/smb-js-freebsd-x64') + } + } catch (e) { + loadError = e + } + break + case 'linux': + switch (arch) { + case 'x64': + if (isMusl()) { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-x64-musl.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-x64-musl.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-x64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-x64-gnu.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-x64-gnu.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-x64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm64': + if (isMusl()) { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-arm64-musl.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-arm64-musl.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-arm64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-arm64-gnu.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-arm64-gnu.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-arm64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 'arm': + if (isMusl()) { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-arm-musleabihf.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-arm-musleabihf.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-arm-musleabihf') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-arm-gnueabihf.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-arm-gnueabihf.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-arm-gnueabihf') + } + } catch (e) { + loadError = e + } + } + break + case 'riscv64': + if (isMusl()) { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-riscv64-musl.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-riscv64-musl.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-riscv64-musl') + } + } catch (e) { + loadError = e + } + } else { + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-riscv64-gnu.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-riscv64-gnu.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-riscv64-gnu') + } + } catch (e) { + loadError = e + } + } + break + case 's390x': + localFileExisted = existsSync(join(__dirname, 'smb-js.linux-s390x-gnu.node')) + try { + if (localFileExisted) { + nativeBinding = require('./smb-js.linux-s390x-gnu.node') + } else { + nativeBinding = require('@netapplabs/smb-js-linux-s390x-gnu') + } + } catch (e) { + loadError = e + } + break + default: + throw new Error(`Unsupported architecture on Linux: ${arch}`) + } + break + default: + throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) +} + +if (!nativeBinding) { + if (loadError) { + throw loadError + } + throw new Error(`Failed to load native binding`) +} + +const { + JsSmbDirectoryHandleEntries, + JsSmbDirectoryHandleKeys, + JsSmbDirectoryHandleValues, + JsSmbHandle, + JsSmbDirectoryHandle, + Cancellable, + JsSmbFileHandle, + JsSmbFile, + JsSmbReadableStreamSource, + JsSmbWritableFileStream, + JsSmbWritableStreamSink, +} = nativeBinding + +module.exports.JsSmbDirectoryHandleEntries = JsSmbDirectoryHandleEntries +module.exports.JsSmbDirectoryHandleKeys = JsSmbDirectoryHandleKeys +module.exports.JsSmbDirectoryHandleValues = JsSmbDirectoryHandleValues +module.exports.JsSmbHandle = JsSmbHandle +module.exports.JsSmbDirectoryHandle = JsSmbDirectoryHandle +module.exports.Cancellable = Cancellable +module.exports.JsSmbFileHandle = JsSmbFileHandle +module.exports.JsSmbFile = JsSmbFile +module.exports.JsSmbReadableStreamSource = JsSmbReadableStreamSource +module.exports.JsSmbWritableFileStream = JsSmbWritableFileStream +module.exports.JsSmbWritableStreamSink = JsSmbWritableStreamSink diff --git a/binding.d.ts b/binding.d.ts new file mode 100644 index 0000000..63cbdf6 --- /dev/null +++ b/binding.d.ts @@ -0,0 +1,125 @@ +/* tslint:disable */ +/* eslint-disable */ + +/* auto-generated by NAPI-RS */ + +export interface JsSmbHandlePermissionDescriptor { + mode: 'read' | 'readwrite' +} +export interface JsSmbGetDirectoryOptions { + create: boolean +} +export interface JsSmbGetFileOptions { + create: boolean +} +export interface JsSmbRemoveOptions { + recursive: boolean +} +export interface JsSmbCreateWritableOptions { + keepExistingData: boolean +} +export interface JsSmbStat { + readonly inode?: bigint + readonly size: bigint + readonly creationTime: bigint + readonly modifiedTime: bigint + readonly accessedTime: bigint +} +export interface JsSmbNotifyChange { + path: string + action: string + fromPath?: string +} +export declare class JsSmbDirectoryHandleEntries { + [Symbol.asyncIterator]: AsyncIterableIterator<[string, JsSmbDirectoryHandle | JsSmbFileHandle]> +} +export declare class JsSmbDirectoryHandleKeys { + [Symbol.asyncIterator]: AsyncIterableIterator +} +export declare class JsSmbDirectoryHandleValues { + [Symbol.asyncIterator]: AsyncIterableIterator +} +export declare class JsSmbHandle { + readonly kind: 'directory' | 'file' + readonly name: string + isSameEntry(other: JsSmbHandle): boolean + queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise + requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise + stat(): Promise +} +export declare class JsSmbDirectoryHandle { + [Symbol.asyncIterator]: JsSmbDirectoryHandle['entries'] + readonly kind: 'directory' + readonly name: string + constructor(url: string) + toHandle(): JsSmbHandle + isSameEntry(other: JsSmbHandle): boolean + queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise + requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise + entries(): AsyncIterableIterator<[string, JsSmbDirectoryHandle | JsSmbFileHandle]> + keys(): AsyncIterableIterator + values(): AsyncIterableIterator + getDirectoryHandle(name: string, options?: JsSmbGetDirectoryOptions): Promise + getFileHandle(name: string, options?: JsSmbGetFileOptions): Promise + removeEntry(name: string, options?: JsSmbRemoveOptions): Promise + resolve(possibleDescendant: JsSmbHandle): Promise | null> + watch(callback: (...args: any[]) => any): Cancellable +} +export declare class Cancellable { + wait(): Promise + cancel(): void +} +export declare class JsSmbFileHandle { + readonly kind: 'file' + readonly name: string + toHandle(): JsSmbHandle + isSameEntry(other: JsSmbHandle): boolean + queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise + requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise + getFile(): Promise + createWritable(options?: JsSmbCreateWritableOptions): Promise +} +export declare class JsSmbFile { + readonly size: number + readonly type: string + readonly lastModified: number + readonly name: string + arrayBuffer(): Promise + slice(start?: number, end?: number, contentType?: string): Blob + stream(): ReadableStream + text(): Promise +} +export declare class JsSmbReadableStreamSource { + readonly type: 'bytes' + pull(controller: ReadableByteStreamController): void +} +export declare class JsSmbWritableFileStream { + readonly locked: boolean + write( + data: + | ArrayBuffer + | ArrayBufferView + | DataView + | Blob + | String + | string + | { + type: 'write' | 'seek' | 'truncate' + data?: ArrayBuffer | ArrayBufferView | DataView | Blob | String | string + position?: number + size?: number + }, + ): Promise + seek(position: number): Promise + truncate(size: number): Promise + close(): Promise + abort(reason: string): Promise + releaseLock(): void + getWriter(): WritableStreamDefaultWriter +} +export declare class JsSmbWritableStreamSink { + start(controller?: WritableStreamDefaultController): Promise + abort(reason: string): Promise + close(controller?: WritableStreamDefaultController): Promise + write(chunk: any, controller?: WritableStreamDefaultController): Promise +} diff --git a/build.sh b/build.sh index 3719766..88b5f7f 100755 --- a/build.sh +++ b/build.sh @@ -80,35 +80,23 @@ export RUST_BACKTRACE=1 if [ "$ARG1" == "test" ]; then cargo test --release else - yarn build-tsc + # build binary first, so we have the bundle.cjs created yarn build-napi --target ${TARGET_TRIPLE} + yarn build-tsc - # amend napi generated index.js a bit so that it plays nicer with esbuild - for x in `cat index.js | grep -o "smb-js\..*\.node" | sort | uniq`; do - cat index.js | sed "s/join(__dirname, '$x')/new URL('$x', import.meta.url)/g" > index.js~ - mv index.js{~,} - - cat index.js | sed "s/require('.\/$x')/require(new URL('$x', import.meta.url).pathname)/g" > index.js~ - mv index.js{~,} - done + # remove check for universal binary for darwin, as we know we won't have one + cat binding.cjs | grep -v "'smb-js.darwin-universal.node'" > binding.cjs~ + mv binding.cjs{~,} - # also remove check for universal binary for darwin, as we know we won't have one - cat index.js | grep -v "'smb-js.darwin-universal.node'" > index.js~ + # change ./index.js to require ./binding.cjs instead of just ./binding + cat index.js | sed "s/binding\"/binding.cjs\"/" > index.js~ mv index.js{~,} - # finally, change way in which things are exported from index.js - cat index.js | grep -v 'module.exports.' | sed "s/^const {$/export const {/" > index.js~ - mv index.js{~,} - - # change indax.js to require index.cjs instead of just index - cat indax.js | sed "s/index\"/index.cjs\"/" > indax.js~ - mv indax.js{~,} - + # rename index mv index.js index.cjs - mv indax.js indax.cjs fi if [ "${NODE_OS}" == "darwin" ]; then # rewrite dylib search path after build for macos install_name_tool -change ${LIBSMB_BASE_LIB_INSTALL_PATH}/libsmb2.${SMB_JS_LIB_VER}.dylib @loader_path/lib/${NODE_OS}/${NODE_ARCH}/libsmb2.${SMB_JS_LIB_VER}.dylib smb-js.${NODE_OS}-${NODE_ARCH}.node -fi \ No newline at end of file +fi diff --git a/indax.cjs b/indax.cjs deleted file mode 100644 index 7157414..0000000 --- a/indax.cjs +++ /dev/null @@ -1,244 +0,0 @@ -"use strict"; -/** - * Copyright 2025 NetApp Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.SmbWritableFileStream = exports.SmbFileHandle = exports.SmbDirectoryHandle = exports.SmbHandle = void 0; -const index_1 = require("./index.cjs"); -class SmbHandle { - _jsh; - kind; - name; - constructor(_jsh) { - this._jsh = _jsh; - this.kind = _jsh.kind; - this.name = _jsh.name; - } - isSameEntry(other) { - return new Promise(async (resolve, reject) => { - try { - resolve(this._jsh.isSameEntry(other._jsh || other)); - } - catch (reason) { - reject(reason); - } - }); - } - async queryPermission(perm) { - return this._jsh.queryPermission(perm); - } - async requestPermission(perm) { - return this._jsh.requestPermission(perm); - } - async stat() { - return this._jsh.stat(); - } -} -exports.SmbHandle = SmbHandle; -class SmbDirectoryHandle extends SmbHandle { - // @ts-ignore - [Symbol.asyncIterator] = this.entries; - _js; - constructor(param) { - const [url, toWrap] = typeof param === 'string' ? [param] : ['', param]; - const _js = toWrap || new index_1.JsSmbDirectoryHandle(url); - super(_js.toHandle()); - this[Symbol.asyncIterator] = this.entries; - this._js = _js; - this.getFile = this.getFileHandle; - this.getDirectory = this.getDirectoryHandle; - this.getEntries = this.values; - } - // @ts-ignore - async *entries() { - for await (const [key, value] of this._js.entries()) { - yield [key, value instanceof index_1.JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value)]; - } - } - // @ts-ignore - async *keys() { - for await (const key of this._js.keys()) { - yield key; - } - } - // @ts-ignore - async *values() { - for await (const value of this._js.values()) { - yield value instanceof index_1.JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value); - } - } - async getDirectoryHandle(name, options) { - //console.log("getDirectoryHandle: ", name); - return new Promise(async (resolve, reject) => { - await this._js.getDirectoryHandle(name, options) - .then((handle) => resolve(new SmbDirectoryHandle(handle))) - .catch((reason) => { - let errMsg = reason.message; - if (errMsg !== undefined) { - if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { - reason.name = 'TypeMismatchError'; - } - else if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { - reason.name = 'NotFoundError'; - } - } - reject(reason); - }); - }); - } - async getFileHandle(name, options) { - return new Promise(async (resolve, reject) => { - await this._js.getFileHandle(name, options) - .then((handle) => resolve(new SmbFileHandle(handle))) - .catch((reason) => { - let errMsg = reason.message; - if (errMsg !== undefined) { - if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { - reason.name = 'TypeMismatchError'; - } - else if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { - reason.name = 'NotFoundError'; - } - } - reject(reason); - }); - }); - } - async removeEntry(name, options) { - return this._js.removeEntry(name, options); - } - async resolve(possibleDescendant) { - return this._js.resolve(possibleDescendant._jsh || possibleDescendant); - } - /** - * @deprecated Old property just for Chromium <=85. Use `.getFileHandle()` in the new API. - */ - getFile; - /** - * @deprecated Old property just for Chromium <=85. Use `.getDirectoryHandle()` in the new API. - */ - getDirectory; - /** - * @deprecated Old property just for Chromium <=85. Use `.keys()`, `.values()`, `.entries()`, or the directory itself as an async iterable in the new API. - */ - getEntries; - watch(callback) { - return this._js.watch(callback); - } -} -exports.SmbDirectoryHandle = SmbDirectoryHandle; -class SmbFileHandle extends SmbHandle { - _js; - constructor(_js) { - super(_js.toHandle()); - this._js = _js; - } - // @ts-ignore - async createSyncAccessHandle() { - throw Error('createSyncAccessHandle not implemented'); - } - async getFile() { - return new Promise(async (resolve, reject) => { - await this._js.getFile() - .then((file) => resolve(file)) - .catch((reason) => { - let errMsg = reason.message; - if (errMsg !== undefined) { - if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { - reason.message = `File "${this.name}" not found`; - reason.name = 'NotFoundError'; - } - } - reject(reason); - }); - }); - } - async createWritable(options) { - return new Promise(async (resolve, reject) => { - await this._js.createWritable(options) - .then((stream) => resolve(new SmbWritableFileStream(stream))) - .catch((reason) => { - let errMsg = reason.message; - if (errMsg !== undefined) { - if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { - reason.message = `File "${this.name}" not found`; - reason.name = 'NotFoundError'; - } - } - reject(reason); - }); - }); - } -} -exports.SmbFileHandle = SmbFileHandle; -class SmbWritableFileStream { - _js; - locked; - constructor(_js) { - this._js = _js; - this.locked = _js.locked; - } - async write(data) { - return new Promise(async (resolve, reject) => { - if (data instanceof Blob) { - data = await data.arrayBuffer(); - } - else { - const dat = data; - if (dat.type === 'write' && dat.data instanceof Blob) { - dat.data = await dat.data.arrayBuffer(); - } - } - try { - await this._js.write(data) - .then(() => resolve()) - .catch((reason) => reject(reason)); - } - catch (reason) { - reject(reason); - } - }); - } - async seek(position) { - return this._js.seek(position); - } - async truncate(size) { - return this._js.truncate(size); - } - async close() { - return this._js.close(); - } - async abort(reason) { - return new Promise(async (resolve, reject) => { - await this._js.abort(reason) - .then((_reason) => resolve()) - .catch((reason) => reject(reason)); - }); - } - getWriter() { - const writer = this._js.getWriter(); - this.locked = true; - writer._releaseLock = writer.releaseLock; - writer.releaseLock = () => { - writer._releaseLock(); - this._js.releaseLock(); - this.locked = false; - }; - return writer; - } -} -exports.SmbWritableFileStream = SmbWritableFileStream; diff --git a/index.cjs b/index.cjs index b3fa5cb..b09ebbb 100644 --- a/index.cjs +++ b/index.cjs @@ -1,298 +1,238 @@ -/* tslint:disable */ -/* eslint-disable */ -/* prettier-ignore */ - -/* auto-generated by NAPI-RS */ - -const { existsSync, readFileSync } = require('fs') -const { join } = require('path') - -const { platform, arch } = process - -let nativeBinding = null -let localFileExisted = false -let loadError = null - -function isMusl() { - // For Node 10 - if (!process.report || typeof process.report.getReport !== 'function') { - try { - const lddPath = require('child_process').execSync('which ldd').toString().trim() - return readFileSync(lddPath, 'utf8').includes('musl') - } catch (e) { - return true +"use strict"; +/** + * Copyright 2025 NetApp Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SmbWritableFileStream = exports.SmbFileHandle = exports.SmbDirectoryHandle = exports.SmbHandle = void 0; +const binding_1 = require("./binding.cjs"); +class SmbHandle { + _jsh; + kind; + name; + constructor(_jsh) { + this._jsh = _jsh; + this.kind = _jsh.kind; + this.name = _jsh.name; + } + isSameEntry(other) { + return new Promise(async (resolve, reject) => { + try { + resolve(this._jsh.isSameEntry(other._jsh || other)); + } + catch (reason) { + reject(reason); + } + }); + } + async queryPermission(perm) { + return this._jsh.queryPermission(perm); + } + async requestPermission(perm) { + return this._jsh.requestPermission(perm); + } + async stat() { + return this._jsh.stat(); } - } else { - const { glibcVersionRuntime } = process.report.getReport().header - return !glibcVersionRuntime - } } - -switch (platform) { - case 'android': - switch (arch) { - case 'arm64': - localFileExisted = existsSync(new URL('smb-js.android-arm64.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.android-arm64.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-android-arm64') - } - } catch (e) { - loadError = e - } - break - case 'arm': - localFileExisted = existsSync(new URL('smb-js.android-arm-eabi.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.android-arm-eabi.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-android-arm-eabi') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Android ${arch}`) +exports.SmbHandle = SmbHandle; +class SmbDirectoryHandle extends SmbHandle { + [Symbol.asyncIterator] = this.entries; + _js; + constructor(param) { + const [url, toWrap] = typeof param === 'string' ? [param] : ['', param]; + const _js = toWrap || new binding_1.JsSmbDirectoryHandle(url); + super(_js.toHandle()); + this[Symbol.asyncIterator] = this.entries; + this._js = _js; + this.getFile = this.getFileHandle; + this.getDirectory = this.getDirectoryHandle; + this.getEntries = this.values; } - break - case 'win32': - switch (arch) { - case 'x64': - localFileExisted = existsSync(new URL('smb-js.win32-x64-msvc.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.win32-x64-msvc.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-win32-x64-msvc') - } - } catch (e) { - loadError = e - } - break - case 'ia32': - localFileExisted = existsSync(new URL('smb-js.win32-ia32-msvc.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.win32-ia32-msvc.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-win32-ia32-msvc') - } - } catch (e) { - loadError = e + async *entries() { + for await (const [key, value] of this._js.entries()) { + yield [key, value instanceof binding_1.JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value)]; } - break - case 'arm64': - localFileExisted = existsSync(new URL('smb-js.win32-arm64-msvc.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.win32-arm64-msvc.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-win32-arm64-msvc') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Windows: ${arch}`) } - break - case 'darwin': - try { - if (localFileExisted) { - } else { - nativeBinding = require('@netapplabs/smb-js-darwin-universal') - } - break - } catch {} - switch (arch) { - case 'x64': - localFileExisted = existsSync(new URL('smb-js.darwin-x64.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.darwin-x64.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-darwin-x64') - } - } catch (e) { - loadError = e + async *keys() { + for await (const key of this._js.keys()) { + yield key; } - break - case 'arm64': - localFileExisted = existsSync(new URL('smb-js.darwin-arm64.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.darwin-arm64.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-darwin-arm64') - } - } catch (e) { - loadError = e + } + async *values() { + for await (const value of this._js.values()) { + yield value instanceof binding_1.JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value); } - break - default: - throw new Error(`Unsupported architecture on macOS: ${arch}`) } - break - case 'freebsd': - if (arch !== 'x64') { - throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) + async getDirectoryHandle(name, options) { + return new Promise(async (resolve, reject) => { + await this._js.getDirectoryHandle(name, options) + .then((handle) => resolve(new SmbDirectoryHandle(handle))) + .catch((reason) => { + let errMsg = reason.message; + if (errMsg !== undefined) { + if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { + reason.name = 'TypeMismatchError'; + } + else if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { + reason.name = 'NotFoundError'; + } + } + reject(reason); + }); + }); } - localFileExisted = existsSync(new URL('smb-js.freebsd-x64.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.freebsd-x64.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-freebsd-x64') - } - } catch (e) { - loadError = e + async getFileHandle(name, options) { + return new Promise(async (resolve, reject) => { + await this._js.getFileHandle(name, options) + .then((handle) => resolve(new SmbFileHandle(handle))) + .catch((reason) => { + let errMsg = reason.message; + if (errMsg !== undefined) { + if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { + reason.name = 'TypeMismatchError'; + } + else if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { + reason.name = 'NotFoundError'; + } + } + reject(reason); + }); + }); } - break - case 'linux': - switch (arch) { - case 'x64': - if (isMusl()) { - localFileExisted = existsSync(new URL('smb-js.linux-x64-musl.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-x64-musl.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-x64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync(new URL('smb-js.linux-x64-gnu.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-x64-gnu.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-x64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm64': - if (isMusl()) { - localFileExisted = existsSync(new URL('smb-js.linux-arm64-musl.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-arm64-musl.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-arm64-musl') - } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync(new URL('smb-js.linux-arm64-gnu.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-arm64-gnu.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-arm64-gnu') - } - } catch (e) { - loadError = e - } - } - break - case 'arm': - if (isMusl()) { - localFileExisted = existsSync(new URL('smb-js.linux-arm-musleabihf.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-arm-musleabihf.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-arm-musleabihf') + async removeEntry(name, options) { + return this._js.removeEntry(name, options); + } + async resolve(possibleDescendant) { + return this._js.resolve(possibleDescendant._jsh || possibleDescendant); + } + /** + * @deprecated Old property just for Chromium <=85. Use `.getFileHandle()` in the new API. + */ + getFile; + /** + * @deprecated Old property just for Chromium <=85. Use `.getDirectoryHandle()` in the new API. + */ + getDirectory; + /** + * @deprecated Old property just for Chromium <=85. Use `.keys()`, `.values()`, `.entries()`, or the directory itself as an async iterable in the new API. + */ + getEntries; + watch(callback) { + return this._js.watch(callback); + } +} +exports.SmbDirectoryHandle = SmbDirectoryHandle; +class SmbFileHandle extends SmbHandle { + _js; + constructor(_js) { + super(_js.toHandle()); + this._js = _js; + } + async createSyncAccessHandle() { + throw Error('createSyncAccessHandle not implemented'); + } + async getFile() { + return new Promise(async (resolve, reject) => { + await this._js.getFile() + .then((file) => resolve(file)) + .catch((reason) => { + let errMsg = reason.message; + if (errMsg !== undefined) { + if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { + reason.message = `File "${this.name}" not found`; + reason.name = 'NotFoundError'; + } + } + reject(reason); + }); + }); + } + async createWritable(options) { + return new Promise(async (resolve, reject) => { + await this._js.createWritable(options) + .then((stream) => resolve(new SmbWritableFileStream(stream))) + .catch((reason) => { + let errMsg = reason.message; + if (errMsg !== undefined) { + if (errMsg.indexOf('not found') != -1 || errMsg.indexOf('ENOENT') != -1) { + reason.message = `File "${this.name}" not found`; + reason.name = 'NotFoundError'; + } + } + reject(reason); + }); + }); + } +} +exports.SmbFileHandle = SmbFileHandle; +class SmbWritableFileStream { + _js; + locked; + constructor(_js) { + this._js = _js; + this.locked = _js.locked; + } + async write(data) { + return new Promise(async (resolve, reject) => { + if (data instanceof Blob) { + data = await data.arrayBuffer(); } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync(new URL('smb-js.linux-arm-gnueabihf.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-arm-gnueabihf.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-arm-gnueabihf') + else { + const dat = data; + if (dat.type === 'write' && dat.data instanceof Blob) { + dat.data = await dat.data.arrayBuffer(); + } } - } catch (e) { - loadError = e - } - } - break - case 'riscv64': - if (isMusl()) { - localFileExisted = existsSync(new URL('smb-js.linux-riscv64-musl.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-riscv64-musl.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-riscv64-musl') + try { + await this._js.write(data) + .then(() => resolve()) + .catch((reason) => reject(reason)); } - } catch (e) { - loadError = e - } - } else { - localFileExisted = existsSync(new URL('smb-js.linux-riscv64-gnu.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-riscv64-gnu.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-riscv64-gnu') + catch (reason) { + reject(reason); } - } catch (e) { - loadError = e - } - } - break - case 's390x': - localFileExisted = existsSync(new URL('smb-js.linux-s390x-gnu.node', import.meta.url)) - try { - if (localFileExisted) { - nativeBinding = require(new URL('smb-js.linux-s390x-gnu.node', import.meta.url).pathname) - } else { - nativeBinding = require('@netapplabs/smb-js-linux-s390x-gnu') - } - } catch (e) { - loadError = e - } - break - default: - throw new Error(`Unsupported architecture on Linux: ${arch}`) + }); + } + async seek(position) { + return this._js.seek(position); + } + async truncate(size) { + return this._js.truncate(size); + } + async close() { + return this._js.close(); + } + async abort(reason) { + return new Promise(async (resolve, reject) => { + await this._js.abort(reason) + .then((_reason) => resolve()) + .catch((reason) => reject(reason)); + }); + } + getWriter() { + const writer = this._js.getWriter(); + this.locked = true; + writer._releaseLock = writer.releaseLock; + writer.releaseLock = () => { + writer._releaseLock(); + this._js.releaseLock(); + this.locked = false; + }; + return writer; } - break - default: - throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) -} - -if (!nativeBinding) { - if (loadError) { - throw loadError - } - throw new Error(`Failed to load native binding`) } - -export const { - JsSmbDirectoryHandleEntries, - JsSmbDirectoryHandleKeys, - JsSmbDirectoryHandleValues, - JsSmbHandle, - JsSmbDirectoryHandle, - Cancellable, - JsSmbFileHandle, - JsSmbFile, - JsSmbReadableStreamSource, - JsSmbWritableFileStream, - JsSmbWritableStreamSink, -} = nativeBinding - +exports.SmbWritableFileStream = SmbWritableFileStream; diff --git a/index.d.ts b/index.d.ts index 63cbdf6..f31ddf5 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,125 +1,84 @@ -/* tslint:disable */ -/* eslint-disable */ - -/* auto-generated by NAPI-RS */ - -export interface JsSmbHandlePermissionDescriptor { - mode: 'read' | 'readwrite' -} -export interface JsSmbGetDirectoryOptions { - create: boolean -} -export interface JsSmbGetFileOptions { - create: boolean -} -export interface JsSmbRemoveOptions { - recursive: boolean -} -export interface JsSmbCreateWritableOptions { - keepExistingData: boolean -} -export interface JsSmbStat { - readonly inode?: bigint - readonly size: bigint - readonly creationTime: bigint - readonly modifiedTime: bigint - readonly accessedTime: bigint -} -export interface JsSmbNotifyChange { - path: string - action: string - fromPath?: string -} -export declare class JsSmbDirectoryHandleEntries { - [Symbol.asyncIterator]: AsyncIterableIterator<[string, JsSmbDirectoryHandle | JsSmbFileHandle]> -} -export declare class JsSmbDirectoryHandleKeys { - [Symbol.asyncIterator]: AsyncIterableIterator -} -export declare class JsSmbDirectoryHandleValues { - [Symbol.asyncIterator]: AsyncIterableIterator -} -export declare class JsSmbHandle { - readonly kind: 'directory' | 'file' - readonly name: string - isSameEntry(other: JsSmbHandle): boolean - queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise - requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise - stat(): Promise -} -export declare class JsSmbDirectoryHandle { - [Symbol.asyncIterator]: JsSmbDirectoryHandle['entries'] - readonly kind: 'directory' - readonly name: string - constructor(url: string) - toHandle(): JsSmbHandle - isSameEntry(other: JsSmbHandle): boolean - queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise - requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise - entries(): AsyncIterableIterator<[string, JsSmbDirectoryHandle | JsSmbFileHandle]> - keys(): AsyncIterableIterator - values(): AsyncIterableIterator - getDirectoryHandle(name: string, options?: JsSmbGetDirectoryOptions): Promise - getFileHandle(name: string, options?: JsSmbGetFileOptions): Promise - removeEntry(name: string, options?: JsSmbRemoveOptions): Promise - resolve(possibleDescendant: JsSmbHandle): Promise | null> - watch(callback: (...args: any[]) => any): Cancellable -} -export declare class Cancellable { - wait(): Promise - cancel(): void -} -export declare class JsSmbFileHandle { - readonly kind: 'file' - readonly name: string - toHandle(): JsSmbHandle - isSameEntry(other: JsSmbHandle): boolean - queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise - requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise - getFile(): Promise - createWritable(options?: JsSmbCreateWritableOptions): Promise -} -export declare class JsSmbFile { - readonly size: number - readonly type: string - readonly lastModified: number - readonly name: string - arrayBuffer(): Promise - slice(start?: number, end?: number, contentType?: string): Blob - stream(): ReadableStream - text(): Promise -} -export declare class JsSmbReadableStreamSource { - readonly type: 'bytes' - pull(controller: ReadableByteStreamController): void -} -export declare class JsSmbWritableFileStream { - readonly locked: boolean - write( - data: - | ArrayBuffer - | ArrayBufferView - | DataView - | Blob - | String - | string - | { - type: 'write' | 'seek' | 'truncate' - data?: ArrayBuffer | ArrayBufferView | DataView | Blob | String | string - position?: number - size?: number - }, - ): Promise - seek(position: number): Promise - truncate(size: number): Promise - close(): Promise - abort(reason: string): Promise - releaseLock(): void - getWriter(): WritableStreamDefaultWriter -} -export declare class JsSmbWritableStreamSink { - start(controller?: WritableStreamDefaultController): Promise - abort(reason: string): Promise - close(controller?: WritableStreamDefaultController): Promise - write(chunk: any, controller?: WritableStreamDefaultController): Promise -} +/** + * Copyright 2025 NetApp Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import { JsSmbCreateWritableOptions, JsSmbDirectoryHandle, JsSmbFileHandle, JsSmbGetDirectoryOptions, JsSmbGetFileOptions, JsSmbHandle, JsSmbHandlePermissionDescriptor, JsSmbRemoveOptions, JsSmbStat, JsSmbWritableFileStream } from './binding'; +type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; +interface SmbWritableFileStreamLock { + locked: boolean; +} +export declare class SmbHandle implements FileSystemHandle { + private _jsh; + readonly kind: FileSystemHandleKind; + readonly name: string; + constructor(_jsh: JsSmbHandle); + isSameEntry(other: FileSystemHandle): Promise; + queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise; + requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise; + stat(): Promise; +} +export declare class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectoryHandle { + [Symbol.asyncIterator]: SmbDirectoryHandle['entries']; + readonly kind: 'directory'; + private _js; + constructor(url: string); + constructor(toWrap: JsSmbDirectoryHandle); + entries(): AsyncIterableIterator<[string, FileSystemDirectoryHandle | FileSystemFileHandle]>; + keys(): AsyncIterableIterator; + values(): AsyncIterableIterator; + getDirectoryHandle(name: string, options?: JsSmbGetDirectoryOptions): Promise; + getFileHandle(name: string, options?: JsSmbGetFileOptions): Promise; + removeEntry(name: string, options?: JsSmbRemoveOptions): Promise; + resolve(possibleDescendant: SmbHandle): Promise | null>; + /** + * @deprecated Old property just for Chromium <=85. Use `.getFileHandle()` in the new API. + */ + getFile: SmbDirectoryHandle['getFileHandle']; + /** + * @deprecated Old property just for Chromium <=85. Use `.getDirectoryHandle()` in the new API. + */ + getDirectory: SmbDirectoryHandle['getDirectoryHandle']; + /** + * @deprecated Old property just for Chromium <=85. Use `.keys()`, `.values()`, `.entries()`, or the directory itself as an async iterable in the new API. + */ + getEntries: SmbDirectoryHandle['values']; + watch(callback: (...args: any[]) => any): import("./binding").Cancellable; +} +export declare class SmbFileHandle extends SmbHandle implements FileSystemFileHandle { + readonly kind: "file"; + private _js; + constructor(_js: JsSmbFileHandle); + createSyncAccessHandle(): Promise; + getFile(): Promise; + createWritable(options?: JsSmbCreateWritableOptions): Promise; +} +export declare class SmbWritableFileStream implements SmbWritableFileStreamLock { + private _js; + readonly locked: boolean; + constructor(_js: JsSmbWritableFileStream); + write(data: ArrayBuffer | TypedArray | DataView | Blob | String | string | { + type: 'write' | 'seek' | 'truncate'; + data?: ArrayBuffer | TypedArray | DataView | Blob | String | string; + position?: number; + size?: number; + }): Promise; + seek(position: number): Promise; + truncate(size: number): Promise; + close(): Promise; + abort(reason: string): Promise; + getWriter(): WritableStreamDefaultWriter; +} +export {}; diff --git a/indax.ts b/index.ts similarity index 81% rename from indax.ts rename to index.ts index b72fb8f..9ad26e0 100644 --- a/indax.ts +++ b/index.ts @@ -17,36 +17,37 @@ */ import { - JsSmbHandlePermissionDescriptor, + JsSmbCreateWritableOptions, + JsSmbDirectoryHandle, + JsSmbFileHandle, JsSmbGetDirectoryOptions, JsSmbGetFileOptions, + JsSmbHandle, + JsSmbHandlePermissionDescriptor, JsSmbRemoveOptions, - JsSmbCreateWritableOptions, JsSmbStat, - JsSmbHandle, - JsSmbDirectoryHandle, - JsSmbFileHandle, JsSmbWritableFileStream, -} from './index'; - -type SmbStat = JsSmbStat; -type SmbHandlePermissionDescriptor = JsSmbHandlePermissionDescriptor; -// @ts-ignore -type SmbCreateWritableOptions = FileSystemCreateWritableOptions; -// @ts-ignore -type FileSystemWritableFileStream = FileSystemWritableFileStream; +} from './binding'; type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; +interface WritableStreamDefaultWriterEx extends WritableStreamDefaultWriter { + _releaseLock: () => void +} + +interface SmbWritableFileStreamLock { locked: boolean } + export class SmbHandle implements FileSystemHandle { private _jsh: JsSmbHandle readonly kind: FileSystemHandleKind readonly name: string + constructor(_jsh: JsSmbHandle) { this._jsh = _jsh; this.kind = _jsh.kind; this.name = _jsh.name; } + isSameEntry(other: FileSystemHandle): Promise { return new Promise(async (resolve, reject) => { try { @@ -56,22 +57,25 @@ export class SmbHandle implements FileSystemHandle { } }); } - async queryPermission(perm: SmbHandlePermissionDescriptor): Promise { + + async queryPermission(perm: JsSmbHandlePermissionDescriptor): Promise { return this._jsh.queryPermission(perm) as Promise; } - async requestPermission(perm: SmbHandlePermissionDescriptor): Promise { + + async requestPermission(perm: JsSmbHandlePermissionDescriptor): Promise { return this._jsh.requestPermission(perm) as Promise; } - async stat(): Promise { - return this._jsh.stat() as Promise; + + async stat(): Promise { + return this._jsh.stat(); } } export class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectoryHandle { - // @ts-ignore [Symbol.asyncIterator]: SmbDirectoryHandle['entries'] = this.entries declare readonly kind: 'directory' private _js: JsSmbDirectoryHandle + constructor(url: string); constructor(toWrap: JsSmbDirectoryHandle); constructor(param: string | JsSmbDirectoryHandle) { @@ -84,31 +88,32 @@ export class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectory this.getDirectory = this.getDirectoryHandle; this.getEntries = this.values; } - // @ts-ignore + async *entries(): AsyncIterableIterator<[string, FileSystemDirectoryHandle | FileSystemFileHandle]> { for await (const [key, value] of this._js.entries()) { - yield [key, value instanceof JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) as any as FileSystemDirectoryHandle : new SmbFileHandle(value) as FileSystemFileHandle]; + yield [key, value instanceof JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value)]; } } - // @ts-ignore + async *keys(): AsyncIterableIterator { for await (const key of this._js.keys()) { yield key; } } - // @ts-ignore + async *values(): AsyncIterableIterator { for await (const value of this._js.values()) { - yield value instanceof JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) as any as FileSystemDirectoryHandle : new SmbFileHandle(value) as FileSystemFileHandle; + yield value instanceof JsSmbDirectoryHandle ? new SmbDirectoryHandle(value) : new SmbFileHandle(value); } } - async getDirectoryHandle(name: string, options?: FileSystemGetDirectoryOptions): Promise { - //console.log("getDirectoryHandle: ", name); + + async getDirectoryHandle(name: string, options?: JsSmbGetDirectoryOptions): Promise { return new Promise(async (resolve, reject) => { - await this._js.getDirectoryHandle(name, options as JsSmbGetDirectoryOptions) - .then((handle) => resolve(new SmbDirectoryHandle(handle) as any as FileSystemDirectoryHandle)) + await this._js.getDirectoryHandle(name, options) + .then((handle) => resolve(new SmbDirectoryHandle(handle))) .catch((reason) => { let errMsg: string = reason.message; + if (errMsg !== undefined) { if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { reason.name = 'TypeMismatchError'; @@ -116,16 +121,19 @@ export class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectory reason.name = 'NotFoundError'; } } + reject(reason); }); }); } - async getFileHandle(name: string, options?: FileSystemGetFileOptions): Promise { + + async getFileHandle(name: string, options?: JsSmbGetFileOptions): Promise { return new Promise(async (resolve, reject) => { - await this._js.getFileHandle(name, options as JsSmbGetFileOptions) - .then((handle) => resolve(new SmbFileHandle(handle) as FileSystemFileHandle)) + await this._js.getFileHandle(name, options) + .then((handle) => resolve(new SmbFileHandle(handle))) .catch((reason) => { let errMsg: string = reason.message; + if (errMsg !== undefined) { if (errMsg == 'The path supplied exists, but was not an entry of requested type.') { reason.name = 'TypeMismatchError'; @@ -137,10 +145,12 @@ export class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectory }); }); } - async removeEntry(name: string, options?: FileSystemRemoveOptions): Promise { - return this._js.removeEntry(name, options as JsSmbRemoveOptions); + + async removeEntry(name: string, options?: JsSmbRemoveOptions): Promise { + return this._js.removeEntry(name, options); } - async resolve(possibleDescendant: FileSystemHandle): Promise | null> { + + async resolve(possibleDescendant: SmbHandle): Promise | null> { return this._js.resolve((possibleDescendant as any)._jsh || possibleDescendant); } @@ -161,17 +171,17 @@ export class SmbDirectoryHandle extends SmbHandle implements FileSystemDirectory watch(callback: (...args: any[]) => any) { return this._js.watch(callback) } - } +} export class SmbFileHandle extends SmbHandle implements FileSystemFileHandle { declare readonly kind: "file"; - private _js: JsSmbFileHandle + private _js: JsSmbFileHandle; + constructor(_js: JsSmbFileHandle) { super(_js.toHandle()); this._js = _js; } - // @ts-ignore async createSyncAccessHandle(): Promise { throw Error('createSyncAccessHandle not implemented'); } @@ -192,10 +202,11 @@ export class SmbFileHandle extends SmbHandle implements FileSystemFileHandle { }); }); } - async createWritable(options?: SmbCreateWritableOptions): Promise { + + async createWritable(options?: JsSmbCreateWritableOptions): Promise { return new Promise(async (resolve, reject) => { - await this._js.createWritable(options as JsSmbCreateWritableOptions) - .then((stream) => resolve(new SmbWritableFileStream(stream) as FileSystemWritableFileStream)) + await this._js.createWritable(options) + .then((stream) => resolve(new SmbWritableFileStream(stream))) .catch((reason) => { let errMsg: string = reason.message; if (errMsg !== undefined) { @@ -210,14 +221,15 @@ export class SmbFileHandle extends SmbHandle implements FileSystemFileHandle { } } -interface SmbWritableFileStreamLock { locked: boolean } export class SmbWritableFileStream implements SmbWritableFileStreamLock { private _js: JsSmbWritableFileStream readonly locked: boolean + constructor(_js: JsSmbWritableFileStream) { this._js = _js; this.locked = _js.locked; } + async write(data: ArrayBuffer | TypedArray | DataView | Blob | String | string | {type: 'write' | 'seek' | 'truncate', data?: ArrayBuffer | TypedArray | DataView | Blob | String | string, position?: number, size?: number}): Promise { return new Promise(async (resolve, reject) => { if (data instanceof Blob) { @@ -238,15 +250,19 @@ export class SmbWritableFileStream implements SmbWritableFileStreamLock { } }); } + async seek(position: number): Promise { return this._js.seek(position); } + async truncate(size: number): Promise { return this._js.truncate(size); } + async close(): Promise { return this._js.close(); } + async abort(reason: string): Promise { return new Promise(async (resolve, reject) => { await this._js.abort(reason) @@ -254,19 +270,19 @@ export class SmbWritableFileStream implements SmbWritableFileStreamLock { .catch((reason) => reject(reason)); }); } + getWriter(): WritableStreamDefaultWriter { const writer = this._js.getWriter(); + (this).locked = true; (writer)._releaseLock = writer.releaseLock; + writer.releaseLock = () => { (writer)._releaseLock(); this._js.releaseLock(); (this).locked = false; }; + return writer; } } - -interface WritableStreamDefaultWriterEx extends WritableStreamDefaultWriter { - _releaseLock: () => void -} diff --git a/package.json b/package.json index 48a056a..8344e50 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.9.6", "type": "commonjs", "description": "smb js", - "main": "indax.cjs", + "main": "index.cjs", + "types": "index.d.ts", "repository": "git@github.com:NetAppLabs/smb-js.git", "license": "Apache-2.0", "keywords": [ @@ -15,7 +16,8 @@ "node-addon-api" ], "files": [ - "indax.ts", + "binding.cjs", + "binding.d.ts", "index.d.ts", "index.cjs", "*.node", @@ -46,11 +48,11 @@ "build-all": "npm run build-sh && npm run build-tsc", "build": "./build.sh", "build-tsc": "npx tsc -p .", - "build-napi": "napi build --platform --release --pipe \"prettier -w\"", - "build:darwin:x64": "napi build --platform --release --target x86_64-apple-darwin --pipe \"prettier -w\"", - "build:darwin:arm64": "napi build --platform --release --target aarch64-apple-darwin --pipe \"prettier -w\"", - "build:linux:x64": "napi build --platform --release --target x86_64-unknown-linux-gnu --pipe \"prettier -w\"", - "build:linux:arm64": "napi build --platform --release --target aarch64-unknown-linux-gnu --pipe \"prettier -w\"", + "build-napi": "napi build --platform --release --js binding.cjs --dts binding.d.ts --pipe \"prettier -w\"", + "build:darwin:x64": "napi build --platform --release --js binding.cjs --dts binding.d.ts --target x86_64-apple-darwin --pipe \"prettier -w\"", + "build:darwin:arm64": "napi build --platform --release --js binding.cjs --dts binding.d.ts --target aarch64-apple-darwin --pipe \"prettier -w\"", + "build:linux:x64": "napi build --platform --release --js binding.cjs --dts binding.d.ts --target x86_64-unknown-linux-gnu --pipe \"prettier -w\"", + "build:linux:arm64": "napi build --platform --release --js binding.cjs --dts binding.d.ts --target aarch64-unknown-linux-gnu --pipe \"prettier -w\"", "build:debug": "napi build --platform --pipe \"prettier -w\"", "format": "run-p format:prettier format:rs", "format:prettier": "prettier . -w", diff --git a/tsconfig.json b/tsconfig.json index c975f01..d649c00 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,10 @@ "noUnusedLocals": true, "noUnusedParameters": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "declaration": true, + "lib": ["ESNext", "WebWorker"], }, - "include": ["."], + "include": ["./index.ts"], "exclude": ["node_modules"] }