@fireproof/core 0.6.3-dev2 → 0.6.4

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.
@@ -8,7 +8,6 @@ import { nocache as cache } from 'prolly-trees/cache';
8
8
  import { CIDCounter, bf, simpleCompare as compare } from 'prolly-trees/utils';
9
9
  import * as codec from '@ipld/dag-cbor';
10
10
  import { sha256 as hasher } from 'multiformats/hashes/sha2';
11
- // import { blake2b256 as hasher } from '@multiformats/blake2/blake2b'
12
11
  import { doTransaction } from './blockstore.js';
13
12
  import { create as createBlock } from 'multiformats/block';
14
13
  const blockOpts = { cache, chunker: bf(30), codec, hasher, compare };
package/dist/src/valet.js CHANGED
@@ -6,8 +6,8 @@ import * as CBW from '@ipld/car/buffer-writer';
6
6
  import * as raw from 'multiformats/codecs/raw';
7
7
  import * as Block from 'multiformats/block';
8
8
  import * as dagcbor from '@ipld/dag-cbor';
9
+ import { openDB } from 'idb';
9
10
  import cargoQueue from 'async/cargoQueue.js';
10
- import { Loader } from './loader.js';
11
11
  // @ts-ignore
12
12
  // @ts-ignore
13
13
  import { bf, simpleCompare as compare } from 'prolly-trees/utils';
@@ -44,7 +44,6 @@ export class Valet {
44
44
  constructor(name = 'default', keyMaterial) {
45
45
  this.name = name;
46
46
  this.setKeyMaterial(keyMaterial);
47
- this.loader = new Loader(name, this.keyId); // todo send this config.loader, if we ever need it
48
47
  this.uploadQueue = cargoQueue(async (tasks, callback) => {
49
48
  // console.log(
50
49
  // 'queue worker',
@@ -77,9 +76,6 @@ export class Valet {
77
76
  // })
78
77
  });
79
78
  }
80
- saveHeader(header) {
81
- return this.loader.saveHeader(header);
82
- }
83
79
  getKeyMaterial() {
84
80
  return this.keyMaterial;
85
81
  }
@@ -120,6 +116,18 @@ export class Valet {
120
116
  throw new Error('missing lastCid for car header');
121
117
  }
122
118
  }
119
+ withDB = async (dbWorkFun) => {
120
+ if (!this.idb) {
121
+ this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
122
+ upgrade(db, oldVersion, newVersion, transaction) {
123
+ if (oldVersion < 1) {
124
+ db.createObjectStore('cars');
125
+ }
126
+ }
127
+ });
128
+ }
129
+ return await dbWorkFun(this.idb);
130
+ };
123
131
  /**
124
132
  * Iterate over all blocks in the store.
125
133
  *
@@ -159,7 +167,6 @@ export class Valet {
159
167
  blockHasher: blockOpts.hasher,
160
168
  blockCodec: blockOpts.codec
161
169
  });
162
- this.valetRoot = indexNode;
163
170
  }
164
171
  const got = await indexNode.get(cid);
165
172
  // console.log('getCarCIDForCID', cid, got)
@@ -204,14 +211,13 @@ export class Valet {
204
211
  * @param {*} value
205
212
  */
206
213
  async parkCar(carCid, value, cids) {
207
- // const callId = Math.random().toString(36).substring(7)
208
214
  // console.log('parkCar', this.instanceId, this.name, carCid, cids)
209
215
  const combinedReader = await this.getCombinedReader(carCid);
210
216
  const mapNode = await addCidsToCarIndex(combinedReader, this.valetRoot, this.valetRootCid, Array.from(cids).map(cid => ({ key: cid.toString(), value: carCid.toString() })));
211
217
  this.valetRoot = mapNode;
212
218
  this.valetRootCid = mapNode.cid;
213
219
  // make a block set with all the cids of the map
214
- const saveValetBlocks = new VMemoryBlockstore();
220
+ const saveValetBlocks = new VMemoryBlockstore(); // todo this blockstore should read from the last valetCid car also
215
221
  for await (const cidx of mapNode.cids()) {
216
222
  const bytes = await combinedReader.get(cidx);
217
223
  saveValetBlocks.put(cidx, bytes);
@@ -224,8 +230,7 @@ export class Valet {
224
230
  newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks);
225
231
  }
226
232
  // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
227
- // console.log('writeCars', callId, carCid.toString(), newValetCidCar.cid.toString())
228
- await this.loader.writeCars([
233
+ await this.writeCars([
229
234
  {
230
235
  cid: carCid,
231
236
  bytes: value,
@@ -239,7 +244,6 @@ export class Valet {
239
244
  }
240
245
  ]);
241
246
  this.valetRootCarCid = newValetCidCar.cid; // goes to clock
242
- // console.log('wroteCars', callId, carCid.toString(), newValetCidCar.cid.toString())
243
247
  // console.log('parked car', carCid, value.length, Array.from(cids))
244
248
  // upload to web3.storage if we have credentials
245
249
  if (this.uploadFunction) {
@@ -256,12 +260,27 @@ export class Valet {
256
260
  // console.log('no upload function', carCid, value.length, this.uploadFunction)
257
261
  }
258
262
  }
263
+ async writeCars(cars) {
264
+ return await this.withDB(async (db) => {
265
+ const tx = db.transaction(['cars'], 'readwrite');
266
+ for (const { cid, bytes, replaces } of cars) {
267
+ await tx.objectStore('cars').put(bytes, cid.toString());
268
+ // todo remove old maps
269
+ if (replaces) {
270
+ await tx.objectStore('cars').delete(replaces.toString());
271
+ }
272
+ }
273
+ return await tx.done;
274
+ });
275
+ }
259
276
  remoteBlockFunction = null;
260
277
  async getCarReader(carCid) {
261
278
  carCid = carCid.toString();
262
- const carBytes = await this.loader.readCar(carCid);
263
- // const callID = Math.random().toString(36).substring(7)
264
- // console.log('getCarReader', callID, carCid)
279
+ const carBytes = await this.withDB(async (db) => {
280
+ const tx = db.transaction(['cars'], 'readonly');
281
+ // console.log('getCarReader', carCid)
282
+ return await tx.objectStore('cars').get(carCid);
283
+ });
265
284
  const reader = await CarReader.fromBytes(carBytes);
266
285
  if (this.keyMaterial) {
267
286
  const roots = await reader.getRoots();
@@ -284,7 +303,6 @@ export class Valet {
284
303
  const { blocks } = await blocksFromEncryptedCarBlock(roots[0], readerGetWithCodec, this.keyMaterial);
285
304
  // last block is the root ??? todo
286
305
  const rootBlock = blocks[blocks.length - 1];
287
- // console.log('got reader', callID, carCid)
288
306
  return {
289
307
  root: rootBlock,
290
308
  get: async (dataCID) => {
@@ -406,8 +424,6 @@ const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
406
424
  };
407
425
  const addCidsToCarIndex = async (blockstore, valetRoot, valetRootCid, bulkOperations) => {
408
426
  let indexNode;
409
- // const callID = Math.random().toString(32).substring(2, 8)
410
- // console.log('addCidsToCarIndex', callID, valetRootCid, bulkOperations.length)
411
427
  if (valetRootCid) {
412
428
  if (valetRoot) {
413
429
  indexNode = valetRoot;
@@ -429,7 +445,6 @@ const addCidsToCarIndex = async (blockstore, valetRoot, valetRootCid, bulkOperat
429
445
  // console.log('adding', key, value)
430
446
  await indexNode.set(key, value);
431
447
  }
432
- // console.log('newCidsToCarIndex', callID, indexNode.cid, bulkOperations.length)
433
448
  return indexNode;
434
449
  };
435
450
  export class VMemoryBlockstore {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fireproof/core",
3
- "version": "0.6.3-dev2",
3
+ "version": "0.6.4",
4
4
  "description": "Live data for React, accelerated by proofs, powered by IPFS",
5
5
  "main": "dist/src/fireproof.js",
6
6
  "module": "dist/src/fireproof.mjs",
@@ -40,8 +40,6 @@
40
40
  "dependencies": {
41
41
  "@ipld/car": "^5.1.0",
42
42
  "@ipld/dag-cbor": "^9.0.0",
43
- "@jsonlines/core": "^1.0.2",
44
- "@multiformats/blake2": "^1.0.13",
45
43
  "@rollup/plugin-commonjs": "^24.0.1",
46
44
  "archy": "^1.0.0",
47
45
  "async": "^3.2.4",
package/src/database.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { visMerkleClock, visMerkleTree, vis, put, get, getAll, eventsSince } from './prolly.js'
3
3
  import { doTransaction, TransactionBlockstore } from './blockstore.js'
4
4
  import charwise from 'charwise'
5
+ import { localSet } from './utils.js'
5
6
  import { CID } from 'multiformats'
6
7
 
7
8
  // TypeScript Types
@@ -33,7 +34,7 @@ export class Database {
33
34
  this.name = name
34
35
  this.instanceId = `fp.${this.name}.${Math.random().toString(36).substring(2, 7)}`
35
36
  this.blocks = new TransactionBlockstore(name, config.key)
36
- this.indexBlocks = new TransactionBlockstore(name ? name + '.indexes' : null, config.key)
37
+ this.indexBlocks = new TransactionBlockstore(name + '.indexes', config.key)
37
38
  this.clock = clock
38
39
  this.config = config
39
40
  }
@@ -77,7 +78,7 @@ export class Database {
77
78
 
78
79
  maybeSaveClock () {
79
80
  if (this.name && this.blocks.valet) {
80
- this.blocks.valet.saveHeader(JSON.stringify(this))
81
+ localSet('fp.' + this.name, JSON.stringify(this))
81
82
  }
82
83
  }
83
84
 
@@ -313,7 +314,6 @@ export class Database {
313
314
  console.error('failed', event)
314
315
  throw new Error('failed to put at storage layer')
315
316
  }
316
- // await new Promise(resolve => setTimeout(resolve, 10)) // makes concurrent tests work
317
317
  this.applyClock(prevClock, result.head)
318
318
  await this.notifyListeners([decodedEvent]) // this type is odd
319
319
  return {
package/src/fireproof.js CHANGED
@@ -1,10 +1,9 @@
1
1
  import randomBytes from 'randombytes'
2
- // import { randomBytes } from 'crypto'
3
2
  import { Database, parseCID } from './database.js'
4
3
  import { Listener } from './listener.js'
5
4
  import { DbIndex as Index } from './db-index.js'
6
5
  // import { TransactionBlockstore } from './blockstore.js'
7
- import { Loader } from './loader.js'
6
+ import { localGet } from './utils.js'
8
7
  import { Sync } from './sync.js'
9
8
 
10
9
  // todo remove Listener in 0.7.0
@@ -22,8 +21,8 @@ export class Fireproof {
22
21
  static storage = (name = null, opts = {}) => {
23
22
  if (name) {
24
23
  opts.name = name
25
- const loader = new Loader(name, opts.loader)
26
- const existing = loader.getHeader()
24
+ // todo this can come from a registry also eg remote database / config, etc
25
+ const existing = localGet('fp.' + name)
27
26
  if (existing) {
28
27
  const existingConfig = JSON.parse(existing)
29
28
  return Fireproof.fromConfig(name, existingConfig, opts)
package/src/prolly.js CHANGED
@@ -15,8 +15,6 @@ import { nocache as cache } from 'prolly-trees/cache'
15
15
  import { CIDCounter, bf, simpleCompare as compare } from 'prolly-trees/utils'
16
16
  import * as codec from '@ipld/dag-cbor'
17
17
  import { sha256 as hasher } from 'multiformats/hashes/sha2'
18
- // import { blake2b256 as hasher } from '@multiformats/blake2/blake2b'
19
-
20
18
  import { doTransaction } from './blockstore.js'
21
19
  import { create as createBlock } from 'multiformats/block'
22
20
  const blockOpts = { cache, chunker: bf(30), codec, hasher, compare }
package/src/utils.js ADDED
@@ -0,0 +1,16 @@
1
+
2
+ /* global localStorage */
3
+ let storageSupported = false
4
+ try {
5
+ storageSupported = window.localStorage && true
6
+ } catch (e) {}
7
+ export function localGet (key) {
8
+ if (storageSupported) {
9
+ return localStorage && localStorage.getItem(key)
10
+ }
11
+ }
12
+ export function localSet (key, value) {
13
+ if (storageSupported) {
14
+ return localStorage && localStorage.setItem(key, value)
15
+ }
16
+ }
package/src/valet.js CHANGED
@@ -6,9 +6,8 @@ import * as CBW from '@ipld/car/buffer-writer'
6
6
  import * as raw from 'multiformats/codecs/raw'
7
7
  import * as Block from 'multiformats/block'
8
8
  import * as dagcbor from '@ipld/dag-cbor'
9
+ import { openDB } from 'idb'
9
10
  import cargoQueue from 'async/cargoQueue.js'
10
- import { Loader } from './loader.js'
11
-
12
11
  // @ts-ignore
13
12
 
14
13
  // @ts-ignore
@@ -54,7 +53,6 @@ export class Valet {
54
53
  constructor (name = 'default', keyMaterial) {
55
54
  this.name = name
56
55
  this.setKeyMaterial(keyMaterial)
57
- this.loader = new Loader(name, this.keyId) // todo send this config.loader, if we ever need it
58
56
  this.uploadQueue = cargoQueue(async (tasks, callback) => {
59
57
  // console.log(
60
58
  // 'queue worker',
@@ -89,10 +87,6 @@ export class Valet {
89
87
  })
90
88
  }
91
89
 
92
- saveHeader (header) {
93
- return this.loader.saveHeader(header)
94
- }
95
-
96
90
  getKeyMaterial () {
97
91
  return this.keyMaterial
98
92
  }
@@ -133,6 +127,19 @@ export class Valet {
133
127
  }
134
128
  }
135
129
 
130
+ withDB = async dbWorkFun => {
131
+ if (!this.idb) {
132
+ this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
133
+ upgrade (db, oldVersion, newVersion, transaction) {
134
+ if (oldVersion < 1) {
135
+ db.createObjectStore('cars')
136
+ }
137
+ }
138
+ })
139
+ }
140
+ return await dbWorkFun(this.idb)
141
+ }
142
+
136
143
  /**
137
144
  * Iterate over all blocks in the store.
138
145
  *
@@ -173,7 +180,6 @@ export class Valet {
173
180
  blockHasher: blockOpts.hasher,
174
181
  blockCodec: blockOpts.codec
175
182
  })
176
- this.valetRoot = indexNode
177
183
  }
178
184
 
179
185
  const got = await indexNode.get(cid)
@@ -220,7 +226,6 @@ export class Valet {
220
226
  * @param {*} value
221
227
  */
222
228
  async parkCar (carCid, value, cids) {
223
- // const callId = Math.random().toString(36).substring(7)
224
229
  // console.log('parkCar', this.instanceId, this.name, carCid, cids)
225
230
  const combinedReader = await this.getCombinedReader(carCid)
226
231
  const mapNode = await addCidsToCarIndex(
@@ -233,7 +238,7 @@ export class Valet {
233
238
  this.valetRoot = mapNode
234
239
  this.valetRootCid = mapNode.cid
235
240
  // make a block set with all the cids of the map
236
- const saveValetBlocks = new VMemoryBlockstore()
241
+ const saveValetBlocks = new VMemoryBlockstore() // todo this blockstore should read from the last valetCid car also
237
242
 
238
243
  for await (const cidx of mapNode.cids()) {
239
244
  const bytes = await combinedReader.get(cidx)
@@ -246,8 +251,7 @@ export class Valet {
246
251
  newValetCidCar = await blocksToCarBlock(this.valetRootCid, saveValetBlocks)
247
252
  }
248
253
  // console.log('newValetCidCar', this.name, Math.floor(newValetCidCar.bytes.length / 1024))
249
- // console.log('writeCars', callId, carCid.toString(), newValetCidCar.cid.toString())
250
- await this.loader.writeCars([
254
+ await this.writeCars([
251
255
  {
252
256
  cid: carCid,
253
257
  bytes: value,
@@ -263,8 +267,6 @@ export class Valet {
263
267
 
264
268
  this.valetRootCarCid = newValetCidCar.cid // goes to clock
265
269
 
266
- // console.log('wroteCars', callId, carCid.toString(), newValetCidCar.cid.toString())
267
-
268
270
  // console.log('parked car', carCid, value.length, Array.from(cids))
269
271
  // upload to web3.storage if we have credentials
270
272
  if (this.uploadFunction) {
@@ -281,13 +283,29 @@ export class Valet {
281
283
  }
282
284
  }
283
285
 
286
+ async writeCars (cars) {
287
+ return await this.withDB(async db => {
288
+ const tx = db.transaction(['cars'], 'readwrite')
289
+ for (const { cid, bytes, replaces } of cars) {
290
+ await tx.objectStore('cars').put(bytes, cid.toString())
291
+ // todo remove old maps
292
+ if (replaces) {
293
+ await tx.objectStore('cars').delete(replaces.toString())
294
+ }
295
+ }
296
+ return await tx.done
297
+ })
298
+ }
299
+
284
300
  remoteBlockFunction = null
285
301
 
286
302
  async getCarReader (carCid) {
287
303
  carCid = carCid.toString()
288
- const carBytes = await this.loader.readCar(carCid)
289
- // const callID = Math.random().toString(36).substring(7)
290
- // console.log('getCarReader', callID, carCid)
304
+ const carBytes = await this.withDB(async db => {
305
+ const tx = db.transaction(['cars'], 'readonly')
306
+ // console.log('getCarReader', carCid)
307
+ return await tx.objectStore('cars').get(carCid)
308
+ })
291
309
  const reader = await CarReader.fromBytes(carBytes)
292
310
  if (this.keyMaterial) {
293
311
  const roots = await reader.getRoots()
@@ -311,7 +329,7 @@ export class Valet {
311
329
 
312
330
  // last block is the root ??? todo
313
331
  const rootBlock = blocks[blocks.length - 1]
314
- // console.log('got reader', callID, carCid)
332
+
315
333
  return {
316
334
  root: rootBlock,
317
335
  get: async dataCID => {
@@ -438,8 +456,6 @@ const blocksFromEncryptedCarBlock = async (cid, get, keyMaterial) => {
438
456
 
439
457
  const addCidsToCarIndex = async (blockstore, valetRoot, valetRootCid, bulkOperations) => {
440
458
  let indexNode
441
- // const callID = Math.random().toString(32).substring(2, 8)
442
- // console.log('addCidsToCarIndex', callID, valetRootCid, bulkOperations.length)
443
459
  if (valetRootCid) {
444
460
  if (valetRoot) {
445
461
  indexNode = valetRoot
@@ -459,7 +475,6 @@ const addCidsToCarIndex = async (blockstore, valetRoot, valetRootCid, bulkOperat
459
475
  // console.log('adding', key, value)
460
476
  await indexNode.set(key, value)
461
477
  }
462
- // console.log('newCidsToCarIndex', callID, indexNode.cid, bulkOperations.length)
463
478
  return indexNode
464
479
  }
465
480
 
package/src/loader.js DELETED
@@ -1,168 +0,0 @@
1
- import {
2
- readFileSync
3
- // createReadStream
4
- } from 'node:fs'
5
- import { mkdir, writeFile } from 'node:fs/promises'
6
- import { openDB } from 'idb'
7
- import { join, dirname } from 'path'
8
- // import { parse } from '@jsonlines/core'
9
- // import cargoQueue from 'async/cargoQueue.js'
10
- import { homedir } from 'os'
11
-
12
- const defaultConfig = {
13
- dataDir: join(homedir(), '.fireproof'),
14
- headerKeyPrefix: 'fp.'
15
- }
16
-
17
- const FORCE_IDB = typeof process !== 'undefined' && !!process.env?.FORCE_IDB
18
-
19
- /* global localStorage */
20
-
21
- export class Loader {
22
- constructor (name, keyId, config = defaultConfig) {
23
- this.name = name
24
- this.keyId = keyId
25
- this.config = config
26
- this.isBrowser = false
27
- try {
28
- this.isBrowser = window.localStorage && true
29
- } catch (e) {}
30
- }
31
-
32
- withDB = async (dbWorkFun) => {
33
- if (!this.idb) {
34
- this.idb = await openDB(`fp.${this.keyId}.${this.name}.valet`, 3, {
35
- upgrade (db, oldVersion, newVersion, transaction) {
36
- if (oldVersion < 1) {
37
- db.createObjectStore('cars')
38
- }
39
- }
40
- })
41
- }
42
- return await dbWorkFun(this.idb)
43
- }
44
-
45
- async writeCars (cars) {
46
- // console.log('writeCars', this.config.dataDir, this.name, cars.map(c => c.cid.toString()))
47
- // console.log('writeCars', cars.length)
48
-
49
- if (FORCE_IDB || this.isBrowser) {
50
- await this.writeCarsIDB(cars)
51
- } else {
52
- const writes = []
53
- for (const { cid, bytes } of cars) {
54
- const carFilename = join(this.config.dataDir, this.name, `${cid.toString()}.car`)
55
- // console.log('writeCars', carFilename)
56
- writes.push(writeSync(carFilename, bytes))
57
- }
58
- await Promise.all(writes)
59
- }
60
- }
61
-
62
- async writeCarsIDB (cars) {
63
- return await this.withDB(async db => {
64
- const tx = db.transaction(['cars'], 'readwrite')
65
- for (const { cid, bytes, replaces } of cars) {
66
- await tx.objectStore('cars').put(bytes, cid.toString())
67
- // todo remove old maps
68
- if (replaces) {
69
- await tx.objectStore('cars').delete(replaces.toString())
70
- }
71
- }
72
- return await tx.done
73
- })
74
- }
75
-
76
- async readCar (carCid) {
77
- if (FORCE_IDB || this.isBrowser) {
78
- return await this.readCarIDB(carCid)
79
- } else {
80
- const carFilename = join(this.config.dataDir, this.name, `${carCid.toString()}.car`)
81
- const got = readFileSync(carFilename)
82
- // console.log('readCar', carFilename, got.constructor.name)
83
- return got
84
- }
85
- }
86
-
87
- async readCarIDB (carCid) {
88
- return await this.withDB(async db => {
89
- const tx = db.transaction(['cars'], 'readonly')
90
- // console.log('getCarReader', carCid)
91
- return await tx.objectStore('cars').get(carCid)
92
- })
93
- }
94
-
95
- getHeader () {
96
- if (this.isBrowser) {
97
- return localStorage.getItem(this.config.headerKeyPrefix + this.name)
98
- } else {
99
- return loadSync(this.headerFilename())
100
- // return null
101
- }
102
- }
103
-
104
- async saveHeader (stringValue) {
105
- // console.log('saveHeader', this.isBrowser)
106
- if (this.isBrowser) {
107
- // console.log('localStorage!', this.config.headerKeyPrefix)
108
- return localStorage.setItem(this.config.headerKeyPrefix + this.name, stringValue)
109
- } else {
110
- // console.log('no localStorage', this.config.dataDir, this.name)
111
- // console.log('saving clock to', this.headerFilename(), stringValue)
112
-
113
- try {
114
- await writeSync(this.headerFilename(), stringValue)
115
- } catch (error) {
116
- console.log('error', error)
117
- }
118
-
119
- // console.log('saved clock to', this.headerFilename())
120
- }
121
- }
122
-
123
- headerFilename () {
124
- // console.log('headerFilename', this.config.dataDir, this.name)
125
- return join(this.config.dataDir, this.name, 'header.json')
126
- }
127
-
128
- // async loadData (database, filename) {
129
- // const fullFilePath = join(process.cwd(), filename)
130
- // const readableStream = createReadStream(fullFilePath)
131
- // const parseStream = parse()
132
- // readableStream.pipe(parseStream)
133
-
134
- // const saveQueue = cargoQueue(async (tasks, callback) => {
135
- // for (const t of tasks) {
136
- // await database.put(t)
137
- // }
138
- // callback()
139
- // })
140
-
141
- // parseStream.on('data', async (data) => {
142
- // saveQueue.push(data)
143
- // })
144
- // let res
145
- // const p = new Promise((resolve, reject) => {
146
- // res = resolve
147
- // })
148
- // saveQueue.drain(async (x) => {
149
- // res()
150
- // })
151
- // return p
152
- // }
153
- }
154
-
155
- function loadSync (filename) {
156
- try {
157
- return readFileSync(filename, 'utf8').toString()
158
- } catch (error) {
159
- // console.log('error', error)
160
- return null
161
- }
162
- }
163
-
164
- async function writeSync (fullpath, stringValue) {
165
- await mkdir(dirname(fullpath), { recursive: true })
166
- // writeFileSync(fullpath, stringValue)
167
- await writeFile(fullpath, stringValue)
168
- }