@archildata/client 0.1.13 → 0.8.2

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.
@@ -73,13 +73,49 @@ export interface DirectoryEntry {
73
73
  /** Type of the entry (File, Directory, etc.) */
74
74
  inodeType: string
75
75
  }
76
+ /** Parameters for creating a new inode */
77
+ export interface CreateInodeParams {
78
+ /** Type of inode to create (File, Directory, Symlink, etc.) */
79
+ inodeType: string
80
+ /** Owner user ID */
81
+ uid: number
82
+ /** Owner group ID */
83
+ gid: number
84
+ /** Unix permission mode */
85
+ mode: number
86
+ /** Device ID for block/char devices */
87
+ rdev?: number
88
+ /** Symlink target if creating a symlink */
89
+ symlinkTarget?: string
90
+ }
91
+ /** Result of creating a new inode */
92
+ export interface CreateResult {
93
+ /** Inode ID of the created entry */
94
+ inodeId: number
95
+ /** Final attributes of the created inode (includes SGID inheritance, etc.) */
96
+ attributes: InodeAttributes
97
+ }
98
+ /** A page of directory entries for paginated reading */
99
+ export interface DirectoryPage {
100
+ /** Entries in this page */
101
+ entries: Array<DirectoryEntry>
102
+ /** Opaque cursor for the next page, or undefined if this is the last page */
103
+ nextCursor?: string
104
+ }
76
105
  /** Lookup response containing inode info */
77
106
  export interface LookupResponse {
78
- /** Inode ID of the found entry (-1 if not found) */
107
+ /** Inode ID of the found entry */
79
108
  inodeId: number
80
109
  /** Attributes of the found inode */
81
110
  attributes: InodeAttributes
82
111
  }
112
+ /** Result of opening a file */
113
+ export interface OpenFileResult {
114
+ /** File handle to use for subsequent operations */
115
+ fileHandle: number
116
+ /** Whether auto-checkout occurred (delegation will be checked in on release) */
117
+ needsCheckin: boolean
118
+ }
83
119
  /** Connection configuration for direct server connections */
84
120
  export interface DirectConnectionConfig {
85
121
  /** Server address (e.g., "localhost:8080") */
@@ -218,16 +254,14 @@ export declare class ArchilClient {
218
254
  close(): Promise<number>
219
255
  /** Get attributes for an inode (uses cache). */
220
256
  getAttributes(inodeId: number, options?: OperationOptions | undefined | null): Promise<InodeAttributes>
221
- /** Lookup an entry by name in a directory (uses cache). */
222
- lookupInode(parentInodeId: number, name: string, options?: OperationOptions | undefined | null): Promise<LookupResponse>
223
- /**
224
- * Read directory entries.
225
- *
226
- * Uses the cache layer via snapshot_and_synchronize_directory to ensure
227
- * the dirent cache is properly populated. This ensures that subsequent
228
- * lookup_inode calls can find the entries returned here.
229
- */
230
- readDirectory(inodeId: number, options?: OperationOptions | undefined | null): Promise<Array<DirectoryEntry>>
257
+ /** Lookup an entry by name in a directory (uses cache). Returns null if not found. */
258
+ lookupInode(parentInodeId: number, name: string, options?: OperationOptions | undefined | null): Promise<LookupResponse | null>
259
+ /** Open a directory for paginated reading. Returns a file handle. */
260
+ openDirectory(inodeId: number, options?: OperationOptions | undefined | null): Promise<number>
261
+ /** Read a page of directory entries using a handle from openDirectory. */
262
+ readDirectory(inodeId: number, fileHandle: number, limit: number, cursor?: string | undefined | null, options?: OperationOptions | undefined | null): Promise<DirectoryPage>
263
+ /** Close a directory handle opened with openDirectory. */
264
+ closeDirectory(inodeId: number, fileHandle: number): void
231
265
  /** Get an extended attribute value. */
232
266
  getExtendedAttribute(inodeId: number, name: string, options?: OperationOptions | undefined | null): Promise<Buffer | null>
233
267
  /** List all extended attribute names. */
@@ -336,10 +370,20 @@ export declare class ArchilClient {
336
370
  *
337
371
  * Automatically chooses between unconditional create (if we have a delegation
338
372
  * on the parent) and conditional create (if we need the server to issue a delegation).
373
+ */
374
+ create(parentInodeId: number, name: string, params: CreateInodeParams, options?: OperationOptions | undefined | null): Promise<CreateResult>
375
+ /**
376
+ * Open a file for reading or writing.
339
377
  *
340
- * Returns the inode ID of the created file.
378
+ * @param accessType - 0 for read, 1 for write, 2 for read-write
341
379
  */
342
- create(parentInodeId: number, name: string, attributes: InodeAttributes, options?: OperationOptions | undefined | null): Promise<number>
380
+ openFile(inodeId: number, accessType: number, options?: OperationOptions | undefined | null): Promise<OpenFileResult>
381
+ /** Release (close) a file handle. */
382
+ releaseFile(inodeId: number, fileHandle: number, options?: OperationOptions | undefined | null): Promise<void>
383
+ /** Read the target of a symlink. */
384
+ readlink(inodeId: number, options?: OperationOptions | undefined | null): Promise<string>
385
+ /** Check access permissions for an inode. */
386
+ checkAccess(inodeId: number, mask: number, options?: OperationOptions | undefined | null): Promise<void>
343
387
  /** Mark an inode subtree as immutable. */
344
388
  setImmutable(inodeId: number): Promise<void>
345
389
  /** Mark an inode subtree as mutable (reverse of set_immutable). */
package/native.js ADDED
@@ -0,0 +1,99 @@
1
+ /* eslint-disable */
2
+
3
+ const { existsSync } = require('fs')
4
+ const { join } = require('path')
5
+
6
+ const { platform, arch } = process
7
+
8
+ // Bundlers (tsup, webpack, esbuild, etc.) cannot handle native .node addons.
9
+ // They either silently drop the binary or replace require() with their own
10
+ // resolution, which breaks at runtime. Detect this early with a clear message.
11
+ if (typeof __dirname === 'undefined' || !existsSync(__dirname)) {
12
+ throw new Error(
13
+ '@archildata/client contains a native Node.js addon (.node binary) that cannot be loaded ' +
14
+ 'through a bundler (tsup, webpack, esbuild, etc.). Import @archildata/client from ' +
15
+ 'unbundled code only — for example, mark it as external in your bundler config.'
16
+ )
17
+ }
18
+
19
+ const SUPPORTED_PLATFORMS = {
20
+ 'linux-x64-gnu': {
21
+ localFile: 'archildata-client.linux-x64-gnu.node',
22
+ package: '@archildata/client-linux-x64-gnu',
23
+ },
24
+ 'linux-arm64-gnu': {
25
+ localFile: 'archildata-client.linux-arm64-gnu.node',
26
+ package: '@archildata/client-linux-arm64-gnu',
27
+ },
28
+ 'darwin-arm64': {
29
+ localFile: 'archildata-client.darwin-arm64.node',
30
+ package: '@archildata/client-darwin-arm64',
31
+ },
32
+ }
33
+
34
+ function isMusl() {
35
+ const report = process.report && process.report.getReport && process.report.getReport()
36
+ if (report) {
37
+ return !report.header.glibcVersionRuntime
38
+ }
39
+ try {
40
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
41
+ return require('fs').readFileSync(lddPath, 'utf8').includes('musl')
42
+ } catch {
43
+ return true
44
+ }
45
+ }
46
+
47
+ let platformKey
48
+ if (platform === 'darwin') {
49
+ platformKey = `darwin-${arch}`
50
+ } else if (platform === 'linux') {
51
+ if (isMusl()) {
52
+ throw new Error(
53
+ `@archildata/client does not support musl-based Linux distros (e.g. Alpine). ` +
54
+ `Current platform: ${platform}/${arch}/musl.`
55
+ )
56
+ }
57
+ platformKey = `linux-${arch}-gnu`
58
+ } else {
59
+ throw new Error(
60
+ `@archildata/client only supports Linux (x64, arm64) and macOS (arm64). ` +
61
+ `Current platform: ${platform}/${arch}.`
62
+ )
63
+ }
64
+
65
+ const target = SUPPORTED_PLATFORMS[platformKey]
66
+
67
+ if (!target) {
68
+ throw new Error(
69
+ `@archildata/client does not support ${platform}/${arch}. ` +
70
+ `Supported platforms: Linux x64, Linux arm64, macOS arm64.`
71
+ )
72
+ }
73
+
74
+ let nativeBinding
75
+
76
+ // Local .node file takes precedence (development builds)
77
+ const localPath = join(__dirname, target.localFile)
78
+ if (existsSync(localPath)) {
79
+ nativeBinding = require(localPath)
80
+ } else {
81
+ try {
82
+ nativeBinding = require(target.package)
83
+ } catch (e) {
84
+ throw new Error(
85
+ `Failed to load native binding for ${platformKey}. ` +
86
+ `Tried platform package '${target.package}' but it was not installed.\n\n` +
87
+ `If you're using npm, reinstall with: npm install @archildata/client\n` +
88
+ `If you're using a bundler (tsup, webpack, esbuild), mark @archildata/client ` +
89
+ `as external — native .node addons cannot be bundled.\n\n` +
90
+ `Original error: ${e.message}`
91
+ )
92
+ }
93
+ }
94
+
95
+ const { initLogging, ArchilClient, JsInodeType } = nativeBinding
96
+
97
+ module.exports.initLogging = initLogging
98
+ module.exports.ArchilClient = ArchilClient
99
+ module.exports.JsInodeType = JsInodeType
package/package.json CHANGED
@@ -1,24 +1,46 @@
1
1
  {
2
2
  "name": "@archildata/client",
3
- "version": "0.1.13",
3
+ "version": "0.8.2",
4
4
  "description": "High-performance Node.js client for Archil distributed filesystem",
5
- "main": "index.js",
6
- "types": "index.d.ts",
5
+ "main": "main.js",
6
+ "types": "main.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./main.d.ts",
10
+ "import": "./main.mjs",
11
+ "require": "./main.js"
12
+ },
13
+ "./api": {
14
+ "types": "./dist/api/index.d.ts",
15
+ "import": "./dist/api/index.mjs",
16
+ "require": "./dist/api/index.js"
17
+ },
18
+ "./native": {
19
+ "types": "./native.d.ts",
20
+ "require": "./native.js"
21
+ }
22
+ },
7
23
  "napi": {
8
24
  "name": "archildata-client",
9
25
  "triples": {
10
- "defaults": true,
26
+ "defaults": false,
11
27
  "additional": [
12
- "aarch64-apple-darwin",
13
28
  "aarch64-unknown-linux-gnu",
14
- "x86_64-apple-darwin",
15
- "x86_64-unknown-linux-gnu"
29
+ "x86_64-unknown-linux-gnu",
30
+ "aarch64-apple-darwin"
16
31
  ]
17
32
  }
18
33
  },
19
34
  "license": "UNLICENSED",
35
+ "dependencies": {
36
+ "openapi-fetch": "^0.13.5"
37
+ },
20
38
  "devDependencies": {
21
- "@napi-rs/cli": "^2.18.0"
39
+ "@napi-rs/cli": "^2.18.0",
40
+ "@types/node": "^20.19.33",
41
+ "openapi-typescript": "^7.6.1",
42
+ "tsup": "^8.4.0",
43
+ "typescript": "^5.9.3"
22
44
  },
23
45
  "engines": {
24
46
  "node": ">= 18"
@@ -27,21 +49,17 @@
27
49
  "artifacts": "napi artifacts",
28
50
  "build": "napi build --platform --release",
29
51
  "build:debug": "napi build --platform",
30
- "test": "node --test test/*.js",
31
- "universal": "napi universal",
32
- "version": "napi version"
52
+ "build:api": "npm run generate && tsup src/api/index.ts --format cjs,esm --dts --outDir dist/api",
53
+ "generate": "openapi-typescript ../../api/controlplane/openapi.yaml -o src/api/generated/openapi.d.ts"
33
54
  },
34
55
  "files": [
35
- "index.js",
36
- "index.d.ts",
56
+ "native.js",
57
+ "native.d.ts",
58
+ "main.js",
59
+ "main.mjs",
60
+ "main.d.ts",
61
+ "dist/",
37
62
  "*.node",
38
63
  "README.md"
39
- ],
40
- "keywords": [
41
- "archil",
42
- "filesystem",
43
- "distributed",
44
- "napi",
45
- "native"
46
64
  ]
47
- }
65
+ }
Binary file
package/index.js DELETED
@@ -1,317 +0,0 @@
1
- /* tslint:disable */
2
- /* eslint-disable */
3
- /* prettier-ignore */
4
-
5
- /* auto-generated by NAPI-RS */
6
-
7
- const { existsSync, readFileSync } = require('fs')
8
- const { join } = require('path')
9
-
10
- const { platform, arch } = process
11
-
12
- let nativeBinding = null
13
- let localFileExisted = false
14
- let loadError = null
15
-
16
- function isMusl() {
17
- // For Node 10
18
- if (!process.report || typeof process.report.getReport !== 'function') {
19
- try {
20
- const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
- return readFileSync(lddPath, 'utf8').includes('musl')
22
- } catch (e) {
23
- return true
24
- }
25
- } else {
26
- const { glibcVersionRuntime } = process.report.getReport().header
27
- return !glibcVersionRuntime
28
- }
29
- }
30
-
31
- switch (platform) {
32
- case 'android':
33
- switch (arch) {
34
- case 'arm64':
35
- localFileExisted = existsSync(join(__dirname, 'archildata-client.android-arm64.node'))
36
- try {
37
- if (localFileExisted) {
38
- nativeBinding = require('./archildata-client.android-arm64.node')
39
- } else {
40
- nativeBinding = require('@archildata/client-android-arm64')
41
- }
42
- } catch (e) {
43
- loadError = e
44
- }
45
- break
46
- case 'arm':
47
- localFileExisted = existsSync(join(__dirname, 'archildata-client.android-arm-eabi.node'))
48
- try {
49
- if (localFileExisted) {
50
- nativeBinding = require('./archildata-client.android-arm-eabi.node')
51
- } else {
52
- nativeBinding = require('@archildata/client-android-arm-eabi')
53
- }
54
- } catch (e) {
55
- loadError = e
56
- }
57
- break
58
- default:
59
- throw new Error(`Unsupported architecture on Android ${arch}`)
60
- }
61
- break
62
- case 'win32':
63
- switch (arch) {
64
- case 'x64':
65
- localFileExisted = existsSync(
66
- join(__dirname, 'archildata-client.win32-x64-msvc.node')
67
- )
68
- try {
69
- if (localFileExisted) {
70
- nativeBinding = require('./archildata-client.win32-x64-msvc.node')
71
- } else {
72
- nativeBinding = require('@archildata/client-win32-x64-msvc')
73
- }
74
- } catch (e) {
75
- loadError = e
76
- }
77
- break
78
- case 'ia32':
79
- localFileExisted = existsSync(
80
- join(__dirname, 'archildata-client.win32-ia32-msvc.node')
81
- )
82
- try {
83
- if (localFileExisted) {
84
- nativeBinding = require('./archildata-client.win32-ia32-msvc.node')
85
- } else {
86
- nativeBinding = require('@archildata/client-win32-ia32-msvc')
87
- }
88
- } catch (e) {
89
- loadError = e
90
- }
91
- break
92
- case 'arm64':
93
- localFileExisted = existsSync(
94
- join(__dirname, 'archildata-client.win32-arm64-msvc.node')
95
- )
96
- try {
97
- if (localFileExisted) {
98
- nativeBinding = require('./archildata-client.win32-arm64-msvc.node')
99
- } else {
100
- nativeBinding = require('@archildata/client-win32-arm64-msvc')
101
- }
102
- } catch (e) {
103
- loadError = e
104
- }
105
- break
106
- default:
107
- throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
- }
109
- break
110
- case 'darwin':
111
- localFileExisted = existsSync(join(__dirname, 'archildata-client.darwin-universal.node'))
112
- try {
113
- if (localFileExisted) {
114
- nativeBinding = require('./archildata-client.darwin-universal.node')
115
- } else {
116
- nativeBinding = require('@archildata/client-darwin-universal')
117
- }
118
- break
119
- } catch {}
120
- switch (arch) {
121
- case 'x64':
122
- localFileExisted = existsSync(join(__dirname, 'archildata-client.darwin-x64.node'))
123
- try {
124
- if (localFileExisted) {
125
- nativeBinding = require('./archildata-client.darwin-x64.node')
126
- } else {
127
- nativeBinding = require('@archildata/client-darwin-x64')
128
- }
129
- } catch (e) {
130
- loadError = e
131
- }
132
- break
133
- case 'arm64':
134
- localFileExisted = existsSync(
135
- join(__dirname, 'archildata-client.darwin-arm64.node')
136
- )
137
- try {
138
- if (localFileExisted) {
139
- nativeBinding = require('./archildata-client.darwin-arm64.node')
140
- } else {
141
- nativeBinding = require('@archildata/client-darwin-arm64')
142
- }
143
- } catch (e) {
144
- loadError = e
145
- }
146
- break
147
- default:
148
- throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
- }
150
- break
151
- case 'freebsd':
152
- if (arch !== 'x64') {
153
- throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
- }
155
- localFileExisted = existsSync(join(__dirname, 'archildata-client.freebsd-x64.node'))
156
- try {
157
- if (localFileExisted) {
158
- nativeBinding = require('./archildata-client.freebsd-x64.node')
159
- } else {
160
- nativeBinding = require('@archildata/client-freebsd-x64')
161
- }
162
- } catch (e) {
163
- loadError = e
164
- }
165
- break
166
- case 'linux':
167
- switch (arch) {
168
- case 'x64':
169
- if (isMusl()) {
170
- localFileExisted = existsSync(
171
- join(__dirname, 'archildata-client.linux-x64-musl.node')
172
- )
173
- try {
174
- if (localFileExisted) {
175
- nativeBinding = require('./archildata-client.linux-x64-musl.node')
176
- } else {
177
- nativeBinding = require('@archildata/client-linux-x64-musl')
178
- }
179
- } catch (e) {
180
- loadError = e
181
- }
182
- } else {
183
- localFileExisted = existsSync(
184
- join(__dirname, 'archildata-client.linux-x64-gnu.node')
185
- )
186
- try {
187
- if (localFileExisted) {
188
- nativeBinding = require('./archildata-client.linux-x64-gnu.node')
189
- } else {
190
- nativeBinding = require('@archildata/client-linux-x64-gnu')
191
- }
192
- } catch (e) {
193
- loadError = e
194
- }
195
- }
196
- break
197
- case 'arm64':
198
- if (isMusl()) {
199
- localFileExisted = existsSync(
200
- join(__dirname, 'archildata-client.linux-arm64-musl.node')
201
- )
202
- try {
203
- if (localFileExisted) {
204
- nativeBinding = require('./archildata-client.linux-arm64-musl.node')
205
- } else {
206
- nativeBinding = require('@archildata/client-linux-arm64-musl')
207
- }
208
- } catch (e) {
209
- loadError = e
210
- }
211
- } else {
212
- localFileExisted = existsSync(
213
- join(__dirname, 'archildata-client.linux-arm64-gnu.node')
214
- )
215
- try {
216
- if (localFileExisted) {
217
- nativeBinding = require('./archildata-client.linux-arm64-gnu.node')
218
- } else {
219
- nativeBinding = require('@archildata/client-linux-arm64-gnu')
220
- }
221
- } catch (e) {
222
- loadError = e
223
- }
224
- }
225
- break
226
- case 'arm':
227
- if (isMusl()) {
228
- localFileExisted = existsSync(
229
- join(__dirname, 'archildata-client.linux-arm-musleabihf.node')
230
- )
231
- try {
232
- if (localFileExisted) {
233
- nativeBinding = require('./archildata-client.linux-arm-musleabihf.node')
234
- } else {
235
- nativeBinding = require('@archildata/client-linux-arm-musleabihf')
236
- }
237
- } catch (e) {
238
- loadError = e
239
- }
240
- } else {
241
- localFileExisted = existsSync(
242
- join(__dirname, 'archildata-client.linux-arm-gnueabihf.node')
243
- )
244
- try {
245
- if (localFileExisted) {
246
- nativeBinding = require('./archildata-client.linux-arm-gnueabihf.node')
247
- } else {
248
- nativeBinding = require('@archildata/client-linux-arm-gnueabihf')
249
- }
250
- } catch (e) {
251
- loadError = e
252
- }
253
- }
254
- break
255
- case 'riscv64':
256
- if (isMusl()) {
257
- localFileExisted = existsSync(
258
- join(__dirname, 'archildata-client.linux-riscv64-musl.node')
259
- )
260
- try {
261
- if (localFileExisted) {
262
- nativeBinding = require('./archildata-client.linux-riscv64-musl.node')
263
- } else {
264
- nativeBinding = require('@archildata/client-linux-riscv64-musl')
265
- }
266
- } catch (e) {
267
- loadError = e
268
- }
269
- } else {
270
- localFileExisted = existsSync(
271
- join(__dirname, 'archildata-client.linux-riscv64-gnu.node')
272
- )
273
- try {
274
- if (localFileExisted) {
275
- nativeBinding = require('./archildata-client.linux-riscv64-gnu.node')
276
- } else {
277
- nativeBinding = require('@archildata/client-linux-riscv64-gnu')
278
- }
279
- } catch (e) {
280
- loadError = e
281
- }
282
- }
283
- break
284
- case 's390x':
285
- localFileExisted = existsSync(
286
- join(__dirname, 'archildata-client.linux-s390x-gnu.node')
287
- )
288
- try {
289
- if (localFileExisted) {
290
- nativeBinding = require('./archildata-client.linux-s390x-gnu.node')
291
- } else {
292
- nativeBinding = require('@archildata/client-linux-s390x-gnu')
293
- }
294
- } catch (e) {
295
- loadError = e
296
- }
297
- break
298
- default:
299
- throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
- }
301
- break
302
- default:
303
- throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
- }
305
-
306
- if (!nativeBinding) {
307
- if (loadError) {
308
- throw loadError
309
- }
310
- throw new Error(`Failed to load native binding`)
311
- }
312
-
313
- const { initLogging, ArchilClient, JsInodeType } = nativeBinding
314
-
315
- module.exports.initLogging = initLogging
316
- module.exports.ArchilClient = ArchilClient
317
- module.exports.JsInodeType = JsInodeType