@effect/platform-node-shared 0.0.0-snapshot-c0ae728e57df2c572ea803e1bb7121088cd67b49

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 (154) hide show
  1. package/Http/Etag/package.json +6 -0
  2. package/Http/Multipart/package.json +6 -0
  3. package/LICENSE +21 -0
  4. package/NodeCommandExecutor/package.json +6 -0
  5. package/NodeFileSystem/package.json +6 -0
  6. package/NodeKeyValueStore/package.json +6 -0
  7. package/NodePath/package.json +6 -0
  8. package/NodeRuntime/package.json +6 -0
  9. package/NodeSink/package.json +6 -0
  10. package/NodeStream/package.json +6 -0
  11. package/NodeTerminal/package.json +6 -0
  12. package/README.md +64 -0
  13. package/dist/cjs/Http/Etag.js +43 -0
  14. package/dist/cjs/Http/Etag.js.map +1 -0
  15. package/dist/cjs/Http/Multipart.js +48 -0
  16. package/dist/cjs/Http/Multipart.js.map +1 -0
  17. package/dist/cjs/NodeCommandExecutor.js +38 -0
  18. package/dist/cjs/NodeCommandExecutor.js.map +1 -0
  19. package/dist/cjs/NodeFileSystem.js +42 -0
  20. package/dist/cjs/NodeFileSystem.js.map +1 -0
  21. package/dist/cjs/NodeKeyValueStore.js +42 -0
  22. package/dist/cjs/NodeKeyValueStore.js.map +1 -0
  23. package/dist/cjs/NodePath.js +52 -0
  24. package/dist/cjs/NodePath.js.map +1 -0
  25. package/dist/cjs/NodeRuntime.js +38 -0
  26. package/dist/cjs/NodeRuntime.js.map +1 -0
  27. package/dist/cjs/NodeSink.js +43 -0
  28. package/dist/cjs/NodeSink.js.map +1 -0
  29. package/dist/cjs/NodeStream.js +68 -0
  30. package/dist/cjs/NodeStream.js.map +1 -0
  31. package/dist/cjs/NodeTerminal.js +43 -0
  32. package/dist/cjs/NodeTerminal.js.map +1 -0
  33. package/dist/cjs/internal/commandExecutor.js +151 -0
  34. package/dist/cjs/internal/commandExecutor.js.map +1 -0
  35. package/dist/cjs/internal/error.js +44 -0
  36. package/dist/cjs/internal/error.js.map +1 -0
  37. package/dist/cjs/internal/fileSystem.js +370 -0
  38. package/dist/cjs/internal/fileSystem.js.map +1 -0
  39. package/dist/cjs/internal/http/etag.js +74 -0
  40. package/dist/cjs/internal/http/etag.js.map +1 -0
  41. package/dist/cjs/internal/http/multipart.js +119 -0
  42. package/dist/cjs/internal/http/multipart.js.map +1 -0
  43. package/dist/cjs/internal/path.js +72 -0
  44. package/dist/cjs/internal/path.js.map +1 -0
  45. package/dist/cjs/internal/runtime.js +59 -0
  46. package/dist/cjs/internal/runtime.js.map +1 -0
  47. package/dist/cjs/internal/sink.js +52 -0
  48. package/dist/cjs/internal/sink.js.map +1 -0
  49. package/dist/cjs/internal/stream.js +208 -0
  50. package/dist/cjs/internal/stream.js.map +1 -0
  51. package/dist/cjs/internal/terminal.js +121 -0
  52. package/dist/cjs/internal/terminal.js.map +1 -0
  53. package/dist/dts/Http/Etag.d.ts +16 -0
  54. package/dist/dts/Http/Etag.d.ts.map +1 -0
  55. package/dist/dts/Http/Multipart.d.ts +29 -0
  56. package/dist/dts/Http/Multipart.d.ts.map +1 -0
  57. package/dist/dts/NodeCommandExecutor.d.ts +12 -0
  58. package/dist/dts/NodeCommandExecutor.d.ts.map +1 -0
  59. package/dist/dts/NodeFileSystem.d.ts +11 -0
  60. package/dist/dts/NodeFileSystem.d.ts.map +1 -0
  61. package/dist/dts/NodeKeyValueStore.d.ts +12 -0
  62. package/dist/dts/NodeKeyValueStore.d.ts.map +1 -0
  63. package/dist/dts/NodePath.d.ts +21 -0
  64. package/dist/dts/NodePath.d.ts.map +1 -0
  65. package/dist/dts/NodeRuntime.d.ts +10 -0
  66. package/dist/dts/NodeRuntime.d.ts.map +1 -0
  67. package/dist/dts/NodeSink.d.ts +22 -0
  68. package/dist/dts/NodeSink.d.ts.map +1 -0
  69. package/dist/dts/NodeStream.d.ts +79 -0
  70. package/dist/dts/NodeStream.d.ts.map +1 -0
  71. package/dist/dts/NodeTerminal.d.ts +18 -0
  72. package/dist/dts/NodeTerminal.d.ts.map +1 -0
  73. package/dist/dts/internal/commandExecutor.d.ts +2 -0
  74. package/dist/dts/internal/commandExecutor.d.ts.map +1 -0
  75. package/dist/dts/internal/error.d.ts +2 -0
  76. package/dist/dts/internal/error.d.ts.map +1 -0
  77. package/dist/dts/internal/fileSystem.d.ts +2 -0
  78. package/dist/dts/internal/fileSystem.d.ts.map +1 -0
  79. package/dist/dts/internal/http/etag.d.ts +2 -0
  80. package/dist/dts/internal/http/etag.d.ts.map +1 -0
  81. package/dist/dts/internal/http/multipart.d.ts +2 -0
  82. package/dist/dts/internal/http/multipart.d.ts.map +1 -0
  83. package/dist/dts/internal/path.d.ts +2 -0
  84. package/dist/dts/internal/path.d.ts.map +1 -0
  85. package/dist/dts/internal/runtime.d.ts +2 -0
  86. package/dist/dts/internal/runtime.d.ts.map +1 -0
  87. package/dist/dts/internal/sink.d.ts +2 -0
  88. package/dist/dts/internal/sink.d.ts.map +1 -0
  89. package/dist/dts/internal/stream.d.ts +2 -0
  90. package/dist/dts/internal/stream.d.ts.map +1 -0
  91. package/dist/dts/internal/terminal.d.ts +2 -0
  92. package/dist/dts/internal/terminal.d.ts.map +1 -0
  93. package/dist/esm/Http/Etag.js +12 -0
  94. package/dist/esm/Http/Etag.js.map +1 -0
  95. package/dist/esm/Http/Multipart.js +17 -0
  96. package/dist/esm/Http/Multipart.js.map +1 -0
  97. package/dist/esm/NodeCommandExecutor.js +7 -0
  98. package/dist/esm/NodeCommandExecutor.js.map +1 -0
  99. package/dist/esm/NodeFileSystem.js +10 -0
  100. package/dist/esm/NodeFileSystem.js.map +1 -0
  101. package/dist/esm/NodeKeyValueStore.js +10 -0
  102. package/dist/esm/NodeKeyValueStore.js.map +1 -0
  103. package/dist/esm/NodePath.js +20 -0
  104. package/dist/esm/NodePath.js.map +1 -0
  105. package/dist/esm/NodeRuntime.js +7 -0
  106. package/dist/esm/NodeRuntime.js.map +1 -0
  107. package/dist/esm/NodeSink.js +12 -0
  108. package/dist/esm/NodeSink.js.map +1 -0
  109. package/dist/esm/NodeStream.js +37 -0
  110. package/dist/esm/NodeStream.js.map +1 -0
  111. package/dist/esm/NodeTerminal.js +12 -0
  112. package/dist/esm/NodeTerminal.js.map +1 -0
  113. package/dist/esm/internal/commandExecutor.js +120 -0
  114. package/dist/esm/internal/commandExecutor.js.map +1 -0
  115. package/dist/esm/internal/error.js +37 -0
  116. package/dist/esm/internal/error.js.map +1 -0
  117. package/dist/esm/internal/fileSystem.js +339 -0
  118. package/dist/esm/internal/fileSystem.js.map +1 -0
  119. package/dist/esm/internal/http/etag.js +43 -0
  120. package/dist/esm/internal/http/etag.js.map +1 -0
  121. package/dist/esm/internal/http/multipart.js +85 -0
  122. package/dist/esm/internal/http/multipart.js.map +1 -0
  123. package/dist/esm/internal/path.js +41 -0
  124. package/dist/esm/internal/path.js.map +1 -0
  125. package/dist/esm/internal/runtime.js +27 -0
  126. package/dist/esm/internal/runtime.js.map +1 -0
  127. package/dist/esm/internal/sink.js +19 -0
  128. package/dist/esm/internal/sink.js.map +1 -0
  129. package/dist/esm/internal/stream.js +170 -0
  130. package/dist/esm/internal/stream.js.map +1 -0
  131. package/dist/esm/internal/terminal.js +89 -0
  132. package/dist/esm/internal/terminal.js.map +1 -0
  133. package/dist/esm/package.json +4 -0
  134. package/package.json +105 -0
  135. package/src/Http/Etag.ts +18 -0
  136. package/src/Http/Multipart.ts +40 -0
  137. package/src/NodeCommandExecutor.ts +13 -0
  138. package/src/NodeFileSystem.ts +13 -0
  139. package/src/NodeKeyValueStore.ts +20 -0
  140. package/src/NodePath.ts +25 -0
  141. package/src/NodeRuntime.ts +11 -0
  142. package/src/NodeSink.ts +30 -0
  143. package/src/NodeStream.ts +109 -0
  144. package/src/NodeTerminal.ts +20 -0
  145. package/src/internal/commandExecutor.ts +203 -0
  146. package/src/internal/error.ts +51 -0
  147. package/src/internal/fileSystem.ts +575 -0
  148. package/src/internal/http/etag.ts +44 -0
  149. package/src/internal/http/multipart.ts +107 -0
  150. package/src/internal/path.ts +58 -0
  151. package/src/internal/runtime.ts +36 -0
  152. package/src/internal/sink.ts +57 -0
  153. package/src/internal/stream.ts +325 -0
  154. package/src/internal/terminal.ts +123 -0
@@ -0,0 +1,575 @@
1
+ import { effectify } from "@effect/platform/Effectify"
2
+ import * as Error from "@effect/platform/Error"
3
+ import * as FileSystem from "@effect/platform/FileSystem"
4
+ import * as Effect from "effect/Effect"
5
+ import { pipe } from "effect/Function"
6
+ import * as Layer from "effect/Layer"
7
+ import * as Option from "effect/Option"
8
+ import * as Crypto from "node:crypto"
9
+ import * as NFS from "node:fs"
10
+ import * as OS from "node:os"
11
+ import * as Path from "node:path"
12
+ import { handleErrnoException } from "./error.js"
13
+
14
+ const handleBadArgument = (method: string) => (err: unknown) =>
15
+ Error.BadArgument({
16
+ module: "FileSystem",
17
+ method,
18
+ message: (err as Error).message ?? String(err)
19
+ })
20
+
21
+ // == access
22
+
23
+ const access = (() => {
24
+ const nodeAccess = effectify(
25
+ NFS.access,
26
+ handleErrnoException("FileSystem", "access"),
27
+ handleBadArgument("access")
28
+ )
29
+ return (path: string, options?: FileSystem.AccessFileOptions) => {
30
+ let mode = NFS.constants.F_OK
31
+ if (options?.readable) {
32
+ mode |= NFS.constants.R_OK
33
+ }
34
+ if (options?.writable) {
35
+ mode |= NFS.constants.W_OK
36
+ }
37
+ return nodeAccess(path, mode)
38
+ }
39
+ })()
40
+
41
+ // == copy
42
+
43
+ const copy = (() => {
44
+ const nodeCp = effectify(
45
+ NFS.cp,
46
+ handleErrnoException("FileSystem", "copy"),
47
+ handleBadArgument("copy")
48
+ )
49
+ return (fromPath: string, toPath: string, options?: FileSystem.CopyOptions) =>
50
+ nodeCp(fromPath, toPath, {
51
+ force: options?.overwrite ?? false,
52
+ preserveTimestamps: options?.preserveTimestamps ?? false,
53
+ recursive: true
54
+ })
55
+ })()
56
+
57
+ // == copyFile
58
+
59
+ const copyFile = (() => {
60
+ const nodeCopyFile = effectify(
61
+ NFS.copyFile,
62
+ handleErrnoException("FileSystem", "copyFile"),
63
+ handleBadArgument("copyFile")
64
+ )
65
+ return (fromPath: string, toPath: string) => nodeCopyFile(fromPath, toPath)
66
+ })()
67
+
68
+ // == chmod
69
+
70
+ const chmod = (() => {
71
+ const nodeChmod = effectify(
72
+ NFS.chmod,
73
+ handleErrnoException("FileSystem", "chmod"),
74
+ handleBadArgument("chmod")
75
+ )
76
+ return (path: string, mode: number) => nodeChmod(path, mode)
77
+ })()
78
+
79
+ // == chown
80
+
81
+ const chown = (() => {
82
+ const nodeChown = effectify(
83
+ NFS.chown,
84
+ handleErrnoException("FileSystem", "chown"),
85
+ handleBadArgument("chown")
86
+ )
87
+ return (path: string, uid: number, gid: number) => nodeChown(path, uid, gid)
88
+ })()
89
+
90
+ // == link
91
+
92
+ const link = (() => {
93
+ const nodeLink = effectify(
94
+ NFS.link,
95
+ handleErrnoException("FileSystem", "link"),
96
+ handleBadArgument("link")
97
+ )
98
+ return (existingPath: string, newPath: string) => nodeLink(existingPath, newPath)
99
+ })()
100
+
101
+ // == makeDirectory
102
+
103
+ const makeDirectory = (() => {
104
+ const nodeMkdir = effectify(
105
+ NFS.mkdir,
106
+ handleErrnoException("FileSystem", "makeDirectory"),
107
+ handleBadArgument("makeDirectory")
108
+ )
109
+ return (path: string, options?: FileSystem.MakeDirectoryOptions) =>
110
+ nodeMkdir(path, {
111
+ recursive: options?.recursive ?? false,
112
+ mode: options?.mode
113
+ })
114
+ })()
115
+
116
+ // == makeTempDirectory
117
+
118
+ const makeTempDirectoryFactory = (method: string) => {
119
+ const nodeMkdtemp = effectify(
120
+ NFS.mkdtemp,
121
+ handleErrnoException("FileSystem", method),
122
+ handleBadArgument(method)
123
+ )
124
+ return (options?: FileSystem.MakeTempDirectoryOptions) =>
125
+ Effect.suspend(() => {
126
+ const prefix = options?.prefix ?? ""
127
+ const directory = typeof options?.directory === "string"
128
+ ? Path.join(options.directory, ".")
129
+ : OS.tmpdir()
130
+
131
+ return nodeMkdtemp(prefix ? Path.join(directory, prefix) : directory + "/")
132
+ })
133
+ }
134
+ const makeTempDirectory = makeTempDirectoryFactory("makeTempDirectory")
135
+
136
+ // == remove
137
+
138
+ const removeFactory = (method: string) => {
139
+ const nodeRm = effectify(
140
+ NFS.rm,
141
+ handleErrnoException("FileSystem", method),
142
+ handleBadArgument(method)
143
+ )
144
+ return (path: string, options?: FileSystem.RemoveOptions) =>
145
+ nodeRm(
146
+ path,
147
+ { recursive: options?.recursive ?? false }
148
+ )
149
+ }
150
+ const remove = removeFactory("remove")
151
+
152
+ // == makeTempDirectoryScoped
153
+
154
+ const makeTempDirectoryScoped = (() => {
155
+ const makeDirectory = makeTempDirectoryFactory("makeTempDirectoryScoped")
156
+ const removeDirectory = removeFactory("makeTempDirectoryScoped")
157
+ return (
158
+ options?: FileSystem.MakeTempDirectoryOptions
159
+ ) =>
160
+ Effect.acquireRelease(
161
+ makeDirectory(options),
162
+ (directory) => Effect.orDie(removeDirectory(directory, { recursive: true }))
163
+ )
164
+ })()
165
+
166
+ // == open
167
+
168
+ const openFactory = (method: string) => {
169
+ const nodeOpen = effectify(
170
+ NFS.open,
171
+ handleErrnoException("FileSystem", method),
172
+ handleBadArgument(method)
173
+ )
174
+ const nodeClose = effectify(
175
+ NFS.close,
176
+ handleErrnoException("FileSystem", method),
177
+ handleBadArgument(method)
178
+ )
179
+
180
+ return (path: string, options?: FileSystem.OpenFileOptions) =>
181
+ pipe(
182
+ Effect.acquireRelease(
183
+ nodeOpen(path, options?.flag ?? "r", options?.mode),
184
+ (fd) => Effect.orDie(nodeClose(fd))
185
+ ),
186
+ Effect.map((fd) => makeFile(FileSystem.FileDescriptor(fd), options?.flag?.startsWith("a") ?? false))
187
+ )
188
+ }
189
+ const open = openFactory("open")
190
+
191
+ const makeFile = (() => {
192
+ const nodeReadFactory = (method: string) =>
193
+ effectify(
194
+ NFS.read,
195
+ handleErrnoException("FileSystem", method),
196
+ handleBadArgument(method)
197
+ )
198
+ const nodeRead = nodeReadFactory("read")
199
+ const nodeReadAlloc = nodeReadFactory("readAlloc")
200
+ const nodeStat = effectify(
201
+ NFS.fstat,
202
+ handleErrnoException("FileSystem", "stat"),
203
+ handleBadArgument("stat")
204
+ )
205
+ const nodeTruncate = effectify(
206
+ NFS.ftruncate,
207
+ handleErrnoException("FileSystem", "truncate"),
208
+ handleBadArgument("truncate")
209
+ )
210
+
211
+ const nodeWriteFactory = (method: string) =>
212
+ effectify(
213
+ NFS.write,
214
+ handleErrnoException("FileSystem", method),
215
+ handleBadArgument(method)
216
+ )
217
+ const nodeWrite = nodeWriteFactory("write")
218
+ const nodeWriteAll = nodeWriteFactory("writeAll")
219
+
220
+ class FileImpl implements FileSystem.File {
221
+ readonly [FileSystem.FileTypeId]: FileSystem.FileTypeId
222
+
223
+ private readonly semaphore = Effect.unsafeMakeSemaphore(1)
224
+ private position: bigint = 0n
225
+
226
+ constructor(
227
+ readonly fd: FileSystem.File.Descriptor,
228
+ private readonly append: boolean
229
+ ) {
230
+ this[FileSystem.FileTypeId] = FileSystem.FileTypeId
231
+ }
232
+
233
+ get stat() {
234
+ return Effect.map(nodeStat(this.fd), makeFileInfo)
235
+ }
236
+
237
+ seek(offset: FileSystem.SizeInput, from: FileSystem.SeekMode) {
238
+ const offsetSize = FileSystem.Size(offset)
239
+ return this.semaphore.withPermits(1)(
240
+ Effect.sync(() => {
241
+ if (from === "start") {
242
+ this.position = offsetSize
243
+ } else if (from === "current") {
244
+ this.position = this.position + offsetSize
245
+ }
246
+
247
+ return this.position
248
+ })
249
+ )
250
+ }
251
+
252
+ read(buffer: Uint8Array) {
253
+ return this.semaphore.withPermits(1)(
254
+ Effect.map(
255
+ Effect.suspend(() =>
256
+ nodeRead(this.fd, {
257
+ buffer,
258
+ position: this.position
259
+ })
260
+ ),
261
+ (bytesRead) => {
262
+ const sizeRead = FileSystem.Size(bytesRead)
263
+ this.position = this.position + sizeRead
264
+ return sizeRead
265
+ }
266
+ )
267
+ )
268
+ }
269
+
270
+ readAlloc(size: FileSystem.SizeInput) {
271
+ const sizeNumber = Number(size)
272
+ return this.semaphore.withPermits(1)(Effect.flatMap(
273
+ Effect.sync(() => Buffer.allocUnsafeSlow(sizeNumber)),
274
+ (buffer) =>
275
+ Effect.map(
276
+ nodeReadAlloc(this.fd, {
277
+ buffer,
278
+ position: this.position
279
+ }),
280
+ (bytesRead): Option.Option<Buffer> => {
281
+ if (bytesRead === 0) {
282
+ return Option.none()
283
+ }
284
+
285
+ this.position = this.position + BigInt(bytesRead)
286
+ if (bytesRead === sizeNumber) {
287
+ return Option.some(buffer)
288
+ }
289
+
290
+ const dst = Buffer.allocUnsafeSlow(bytesRead)
291
+ buffer.copy(dst, 0, 0, bytesRead)
292
+ return Option.some(dst)
293
+ }
294
+ )
295
+ ))
296
+ }
297
+
298
+ truncate(length?: FileSystem.SizeInput) {
299
+ return this.semaphore.withPermits(1)(
300
+ Effect.map(nodeTruncate(this.fd, length ? Number(length) : undefined), () => {
301
+ if (!this.append) {
302
+ const len = BigInt(length ?? 0)
303
+ if (this.position > len) {
304
+ this.position = len
305
+ }
306
+ }
307
+ })
308
+ )
309
+ }
310
+
311
+ write(buffer: Uint8Array) {
312
+ return this.semaphore.withPermits(1)(
313
+ Effect.map(
314
+ Effect.suspend(() =>
315
+ nodeWrite(this.fd, buffer, undefined, undefined, this.append ? undefined : Number(this.position))
316
+ ),
317
+ (bytesWritten) => {
318
+ const sizeWritten = FileSystem.Size(bytesWritten)
319
+ if (!this.append) {
320
+ this.position = this.position + sizeWritten
321
+ }
322
+
323
+ return sizeWritten
324
+ }
325
+ )
326
+ )
327
+ }
328
+
329
+ private writeAllChunk(buffer: Uint8Array): Effect.Effect<void, Error.PlatformError> {
330
+ return Effect.flatMap(
331
+ Effect.suspend(() =>
332
+ nodeWriteAll(this.fd, buffer, undefined, undefined, this.append ? undefined : Number(this.position))
333
+ ),
334
+ (bytesWritten) => {
335
+ if (bytesWritten === 0) {
336
+ return Effect.fail(Error.SystemError({
337
+ module: "FileSystem",
338
+ method: "writeAll",
339
+ reason: "WriteZero",
340
+ pathOrDescriptor: this.fd,
341
+ message: "write returned 0 bytes written"
342
+ }))
343
+ }
344
+
345
+ if (!this.append) {
346
+ this.position = this.position + BigInt(bytesWritten)
347
+ }
348
+
349
+ return bytesWritten < buffer.length ? this.writeAllChunk(buffer.subarray(bytesWritten)) : Effect.unit
350
+ }
351
+ )
352
+ }
353
+
354
+ writeAll(buffer: Uint8Array) {
355
+ return this.semaphore.withPermits(1)(this.writeAllChunk(buffer))
356
+ }
357
+ }
358
+
359
+ return (fd: FileSystem.File.Descriptor, append: boolean): FileSystem.File => new FileImpl(fd, append)
360
+ })()
361
+
362
+ // == makeTempFile
363
+
364
+ const makeTempFileFactory = (method: string) => {
365
+ const makeDirectory = makeTempDirectoryFactory(method)
366
+ const open = openFactory(method)
367
+ const randomHexString = (bytes: number) => Effect.sync(() => Crypto.randomBytes(bytes).toString("hex"))
368
+ return (options?: FileSystem.MakeTempFileOptions) =>
369
+ pipe(
370
+ Effect.zip(makeDirectory(options), randomHexString(6)),
371
+ Effect.map(([directory, random]) => Path.join(directory, random)),
372
+ Effect.tap((path) => Effect.scoped(open(path, { flag: "w+" })))
373
+ )
374
+ }
375
+ const makeTempFile = makeTempFileFactory("makeTempFile")
376
+
377
+ // == makeTempFileScoped
378
+
379
+ const makeTempFileScoped = (() => {
380
+ const makeFile = makeTempFileFactory("makeTempFileScoped")
381
+ const removeFile = removeFactory("makeTempFileScoped")
382
+ return (options?: FileSystem.MakeTempFileOptions) =>
383
+ Effect.acquireRelease(
384
+ makeFile(options),
385
+ (file) => Effect.orDie(removeFile(file))
386
+ )
387
+ })()
388
+
389
+ // == readDirectory
390
+
391
+ const readDirectory = (() => {
392
+ const nodeReadDirectory = effectify(
393
+ NFS.readdir,
394
+ handleErrnoException("FileSystem", "readDirectory"),
395
+ handleBadArgument("readDirectory")
396
+ )
397
+
398
+ return (path: string, options?: FileSystem.ReadDirectoryOptions) =>
399
+ nodeReadDirectory(path, options) as Effect.Effect<ReadonlyArray<string>, Error.PlatformError>
400
+ })()
401
+
402
+ // == readFile
403
+
404
+ const readFile = (path: string) =>
405
+ Effect.async<Uint8Array, Error.PlatformError, never>((resume, signal) => {
406
+ try {
407
+ NFS.readFile(path, { signal }, (err, data) => {
408
+ if (err) {
409
+ resume(Effect.fail(handleErrnoException("FileSystem", "readFile")(err, [path])))
410
+ } else {
411
+ resume(Effect.succeed(data))
412
+ }
413
+ })
414
+ } catch (err) {
415
+ resume(Effect.fail(handleBadArgument("readFile")(err)))
416
+ }
417
+ })
418
+
419
+ // == readLink
420
+
421
+ const readLink = (() => {
422
+ const nodeReadLink = effectify(
423
+ NFS.readlink,
424
+ handleErrnoException("FileSystem", "readLink"),
425
+ handleBadArgument("readLink")
426
+ )
427
+ return (path: string) => nodeReadLink(path)
428
+ })()
429
+
430
+ // == realPath
431
+
432
+ const realPath = (() => {
433
+ const nodeRealPath = effectify(
434
+ NFS.realpath,
435
+ handleErrnoException("FileSystem", "realPath"),
436
+ handleBadArgument("realPath")
437
+ )
438
+ return (path: string) => nodeRealPath(path)
439
+ })()
440
+
441
+ // == rename
442
+
443
+ const rename = (() => {
444
+ const nodeRename = effectify(
445
+ NFS.rename,
446
+ handleErrnoException("FileSystem", "rename"),
447
+ handleBadArgument("rename")
448
+ )
449
+ return (oldPath: string, newPath: string) => nodeRename(oldPath, newPath)
450
+ })()
451
+
452
+ // == stat
453
+
454
+ const makeFileInfo = (stat: NFS.Stats): FileSystem.File.Info => ({
455
+ type: stat.isFile() ?
456
+ "File" :
457
+ stat.isDirectory() ?
458
+ "Directory" :
459
+ stat.isSymbolicLink() ?
460
+ "SymbolicLink" :
461
+ stat.isBlockDevice() ?
462
+ "BlockDevice" :
463
+ stat.isCharacterDevice() ?
464
+ "CharacterDevice" :
465
+ stat.isFIFO() ?
466
+ "FIFO" :
467
+ stat.isSocket() ?
468
+ "Socket" :
469
+ "Unknown",
470
+ mtime: Option.fromNullable(stat.mtime),
471
+ atime: Option.fromNullable(stat.atime),
472
+ birthtime: Option.fromNullable(stat.birthtime),
473
+ dev: stat.dev,
474
+ rdev: Option.fromNullable(stat.rdev),
475
+ ino: Option.fromNullable(stat.ino),
476
+ mode: stat.mode,
477
+ nlink: Option.fromNullable(stat.nlink),
478
+ uid: Option.fromNullable(stat.uid),
479
+ gid: Option.fromNullable(stat.gid),
480
+ size: FileSystem.Size(stat.size),
481
+ blksize: Option.fromNullable(FileSystem.Size(stat.blksize)),
482
+ blocks: Option.fromNullable(stat.blocks)
483
+ })
484
+ const stat = (() => {
485
+ const nodeStat = effectify(
486
+ NFS.stat,
487
+ handleErrnoException("FileSystem", "stat"),
488
+ handleBadArgument("stat")
489
+ )
490
+ return (path: string) => Effect.map(nodeStat(path), makeFileInfo)
491
+ })()
492
+
493
+ // == symlink
494
+
495
+ const symlink = (() => {
496
+ const nodeSymlink = effectify(
497
+ NFS.symlink,
498
+ handleErrnoException("FileSystem", "symlink"),
499
+ handleBadArgument("symlink")
500
+ )
501
+ return (target: string, path: string) => nodeSymlink(target, path)
502
+ })()
503
+
504
+ // == truncate
505
+
506
+ const truncate = (() => {
507
+ const nodeTruncate = effectify(
508
+ NFS.truncate,
509
+ handleErrnoException("FileSystem", "truncate"),
510
+ handleBadArgument("truncate")
511
+ )
512
+ return (path: string, length?: FileSystem.SizeInput) =>
513
+ nodeTruncate(path, length !== undefined ? Number(length) : undefined)
514
+ })()
515
+
516
+ // == utimes
517
+
518
+ const utimes = (() => {
519
+ const nodeUtimes = effectify(
520
+ NFS.utimes,
521
+ handleErrnoException("FileSystem", "utime"),
522
+ handleBadArgument("utime")
523
+ )
524
+ return (path: string, atime: number | Date, mtime: number | Date) => nodeUtimes(path, atime, mtime)
525
+ })()
526
+
527
+ // == writeFile
528
+
529
+ const writeFile = (path: string, data: Uint8Array, options?: FileSystem.WriteFileOptions) =>
530
+ Effect.async<void, Error.PlatformError, never>((resume, signal) => {
531
+ try {
532
+ NFS.writeFile(path, data, {
533
+ signal,
534
+ flag: options?.flag,
535
+ mode: options?.mode
536
+ }, (err) => {
537
+ if (err) {
538
+ resume(Effect.fail(handleErrnoException("FileSystem", "writeFile")(err, [path])))
539
+ } else {
540
+ resume(Effect.unit)
541
+ }
542
+ })
543
+ } catch (err) {
544
+ resume(Effect.fail(handleBadArgument("writeFile")(err)))
545
+ }
546
+ })
547
+
548
+ const fileSystemImpl = FileSystem.make({
549
+ access,
550
+ chmod,
551
+ chown,
552
+ copy,
553
+ copyFile,
554
+ link,
555
+ makeDirectory,
556
+ makeTempDirectory,
557
+ makeTempDirectoryScoped,
558
+ makeTempFile,
559
+ makeTempFileScoped,
560
+ open,
561
+ readDirectory,
562
+ readFile,
563
+ readLink,
564
+ realPath,
565
+ remove,
566
+ rename,
567
+ stat,
568
+ symlink,
569
+ truncate,
570
+ utimes,
571
+ writeFile
572
+ })
573
+
574
+ /** @internal */
575
+ export const layer = Layer.succeed(FileSystem.FileSystem, fileSystemImpl)
@@ -0,0 +1,44 @@
1
+ import type * as FileSystem from "@effect/platform/FileSystem"
2
+ import type * as Body from "@effect/platform/Http/Body"
3
+ import * as Etag from "@effect/platform/Http/Etag"
4
+ import * as Effect from "effect/Effect"
5
+ import * as Layer from "effect/Layer"
6
+
7
+ const fromFileInfo = (info: FileSystem.File.Info) => {
8
+ const mtime = info.mtime._tag === "Some"
9
+ ? info.mtime.value.getTime().toString(16)
10
+ : "0"
11
+ return `${info.size.toString(16)}-${mtime}`
12
+ }
13
+
14
+ const fromFileWeb = (file: Body.Body.FileLike) => {
15
+ return `${file.size.toString(16)}-${file.lastModified.toString(16)}`
16
+ }
17
+
18
+ /** @internal */
19
+ export const layer = Layer.succeed(
20
+ Etag.Generator,
21
+ Etag.Generator.of({
22
+ [Etag.GeneratorTypeId]: Etag.GeneratorTypeId,
23
+ fromFileInfo(info) {
24
+ return Effect.sync(() => ({ _tag: "Strong", value: fromFileInfo(info) }))
25
+ },
26
+ fromFileWeb(file) {
27
+ return Effect.sync(() => ({ _tag: "Strong", value: fromFileWeb(file) }))
28
+ }
29
+ })
30
+ )
31
+
32
+ /** @internal */
33
+ export const layerWeak = Layer.succeed(
34
+ Etag.Generator,
35
+ Etag.Generator.of({
36
+ [Etag.GeneratorTypeId]: Etag.GeneratorTypeId,
37
+ fromFileInfo(info) {
38
+ return Effect.sync(() => ({ _tag: "Weak", value: fromFileInfo(info) }))
39
+ },
40
+ fromFileWeb(file) {
41
+ return Effect.sync(() => ({ _tag: "Weak", value: fromFileWeb(file) }))
42
+ }
43
+ })
44
+ )