@fireproof/core 0.6.4 → 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,8 +8,8 @@
8
8
  </h3>
9
9
 
10
10
  <p align="center">
11
- <a href="https://github.com/jchris/fireproof/actions/workflows/test.yml">
12
- <img src="https://github.com/jchris/fireproof/actions/workflows/test.yml/badge.svg" alt="Test" style="max-width: 100%;">
11
+ <a href="https://github.com/fireproof-storage/fireproof/actions/workflows/test.yml">
12
+ <img src="https://github.com/fireproof-storage/fireproof/actions/workflows/test.yml/badge.svg" alt="Test" style="max-width: 100%;">
13
13
  </a>
14
14
  <a href="https://standardjs.com" rel="nofollow">
15
15
  <img src="https://img.shields.io/badge/code_style-standard-brightgreen.svg" alt="JavaScript Style Guide" style="max-width: 100%;">
@@ -38,14 +38,14 @@ With Fireproof, you **build first** and connect it to your cloud of choice when
38
38
  ```js
39
39
  const completedTodos = useLiveQuery((doc) => doc.completed, { key: true })
40
40
  ```
41
- This is the README for the core database technology. [The `useFireproof` hook documentation has features and a getting started guide](https://github.com/fireproof-storage/fireproof/blob/main/packages/react/README.md), like `useLiveDocument` and database setup helpers. Don't forget to star 🌟 this repo on the way over.
41
+ This is the README for the core database technology. [The `useFireproof` hook documentation has features and a getting started guide](https://github.com/fireproof-storage/fireproof/blob/main/packages/react/README.md), like `useDocument` and database setup helpers. Don't forget to star 🌟 this repo on the way over.
42
42
 
43
43
  ## AI Assistant Quick Start
44
44
 
45
45
  Because Fireproof is designed around the mantra of build-first, it's ideal for AI-assisted app development as you can get an app up and running before even considering the cloud. If you are using GPT-3.5, GPT-4, or Bard, you can [easily enable the AI to write React apps using Fireproof](https://hackernoon.com/get-chatgpt-to-focus-on-coding-on-the-right-apis-with-gptdoc-strings). Paste this line of code into your prompt, along with a detailed description of the app to build:
46
46
 
47
47
  ```
48
- Fireproof/React/Usage: import { useFireproof } from '@fireproof/react'; function App() { const { useLiveQuery, useLiveDocument, database } = useFireproof(); const result = useLiveQuery(doc => doc.word, { limit: 10 }); const [{ count }, saveCountDocument] = useLiveDocument({_id: 'count', count: 0}); return (<><p>{count} changes</p><input type='text' onChange={() => saveCountDocument({count: count + 1})} onSubmit={e => database.put({word: e.target.value})} /><ul>{result.map(row => (<li key={row.id}>{row.key}</li>))}</ul></>)}
48
+ Fireproof/React/Usage: import { useFireproof } from '@fireproof/react'; function App() { const { useLiveQuery, useDocument, database } = useFireproof(); const result = useLiveQuery(doc => doc.word, { limit: 10 }); const [{ count }, saveCountDocument] = useDocument({_id: 'count', count: 0}); return (<><p>{count} changes</p><input type='text' onChange={() => saveCountDocument({count: count + 1})} onSubmit={e => database.put({word: e.target.value})} /><ul>{result.map(row => (<li key={row.id}>{row.key}</li>))}</ul></>)}
49
49
  ```
50
50
 
51
51
  Here are some examples that worked for us:
@@ -127,13 +127,23 @@ export class DbIndex {
127
127
  applyMapFn(mapFn, name) {
128
128
  if (typeof mapFn === 'string') {
129
129
  this.mapFnString = mapFn;
130
+ // make a regex that matches strings that only have letters, numbers, and spaces
131
+ const regex = /^[a-zA-Z0-9 ]+$/;
132
+ // if the string matches the regex, make a function that returns the value at that key
133
+ if (regex.test(mapFn)) {
134
+ this.mapFn = (doc, emit) => {
135
+ if (doc[mapFn])
136
+ emit(doc[mapFn]);
137
+ };
138
+ this.includeDocsDefault = true;
139
+ }
130
140
  }
131
141
  else {
132
142
  this.mapFn = mapFn;
133
143
  this.mapFnString = mapFn.toString();
134
144
  }
135
145
  const matches = /=>\s*(.*)/.exec(this.mapFnString);
136
- this.includeDocsDefault = matches && matches.length > 0;
146
+ this.includeDocsDefault = this.includeDocsDefault || (matches && matches.length > 0);
137
147
  this.name = name || this.makeName();
138
148
  }
139
149
  makeName() {
@@ -0,0 +1,90 @@
1
+ import randomBytes from 'randombytes';
2
+ import { Database, parseCID } from './database.js';
3
+ import { Listener } from './listener.js';
4
+ import { DbIndex as Index } from './db-index.js';
5
+ // import { TransactionBlockstore } from './blockstore.js'
6
+ import { localGet } from './utils.js';
7
+ import { Sync } from './sync.js';
8
+ // todo remove Listener in 0.7.0
9
+ export { Index, Listener, Database, Sync };
10
+ class Fireproof {
11
+ /**
12
+ * @function storage
13
+ * @memberof Fireproof
14
+ * Creates a new Fireproof instance with default storage settings
15
+ * Most apps should use this and not worry about the details.
16
+ * @static
17
+ * @returns {Database} - a new Fireproof instance
18
+ */
19
+ static storage = (name = null, opts = {}) => {
20
+ if (name) {
21
+ opts.name = name;
22
+ // todo this can come from a registry also eg remote database / config, etc
23
+ const existing = localGet('fp.' + name);
24
+ if (existing) {
25
+ const existingConfig = JSON.parse(existing);
26
+ return Fireproof.fromConfig(name, existingConfig, opts);
27
+ }
28
+ else {
29
+ const instanceKey = randomBytes(32).toString('hex'); // pass null to disable encryption
30
+ opts.key = instanceKey;
31
+ return new Database(name, [], opts);
32
+ }
33
+ }
34
+ else {
35
+ return new Database(null, [], opts);
36
+ }
37
+ };
38
+ static fromConfig(name, existingConfig, opts = {}) {
39
+ opts.key = existingConfig.key;
40
+ const fp = new Database(name, [], opts);
41
+ return Fireproof.fromJSON(existingConfig, fp);
42
+ }
43
+ static fromJSON(json, database) {
44
+ database.hydrate({ car: json.car, indexCar: json.indexCar, clock: json.clock.map(c => parseCID(c)), name: json.name, key: json.key });
45
+ if (json.indexes) {
46
+ for (const { name, code, clock: { byId, byKey, db } } of json.indexes) {
47
+ Index.fromJSON(database, {
48
+ clock: {
49
+ byId: byId ? parseCID(byId) : null,
50
+ byKey: byKey ? parseCID(byKey) : null,
51
+ db: (db && db.length > 0) ? db.map(c => parseCID(c)) : null
52
+ },
53
+ code,
54
+ name
55
+ });
56
+ }
57
+ }
58
+ return database;
59
+ }
60
+ static snapshot(database, clock) {
61
+ const definition = database.toJSON();
62
+ const withBlocks = new Database(database.name);
63
+ withBlocks.blocks = database.blocks;
64
+ if (clock) {
65
+ definition.clock = clock.map(c => parseCID(c));
66
+ definition.indexes.forEach(index => {
67
+ index.clock.byId = null;
68
+ index.clock.byKey = null;
69
+ index.clock.db = null;
70
+ });
71
+ }
72
+ const snappedDb = Fireproof.fromJSON(definition, withBlocks);
73
+ [...database.indexes.values()].forEach(index => {
74
+ snappedDb.indexes.get(index.mapFnString).mapFn = index.mapFn;
75
+ });
76
+ return snappedDb;
77
+ }
78
+ static async zoom(database, clock) {
79
+ ;
80
+ [...database.indexes.values()].forEach(index => {
81
+ index.indexById = { root: null, cid: null };
82
+ index.indexByKey = { root: null, cid: null };
83
+ index.dbHead = null;
84
+ });
85
+ database.clock = clock.map(c => parseCID(c));
86
+ await database.notifyReset(); // hmm... indexes should listen to this? might be more complex than worth it. so far this is the only caller
87
+ return database;
88
+ }
89
+ }
90
+ export { Fireproof };
package/dist/import.js ADDED
@@ -0,0 +1,29 @@
1
+ import { createReadStream } from 'fs';
2
+ import { join } from 'path';
3
+ import { parse } from '@jsonlines/core';
4
+ import cargoQueue from 'async/cargoQueue.js';
5
+ // todo maybe this goes in a utils package for tree-shaking?
6
+ async function loadData(database, filename) {
7
+ const fullFilePath = join(process.cwd(), filename);
8
+ const readableStream = createReadStream(fullFilePath);
9
+ const parseStream = parse();
10
+ readableStream.pipe(parseStream);
11
+ const saveQueue = cargoQueue(async (tasks, callback) => {
12
+ for (const t of tasks) {
13
+ await database.put(t);
14
+ }
15
+ callback();
16
+ });
17
+ parseStream.on('data', async (data) => {
18
+ saveQueue.push(data);
19
+ });
20
+ let res;
21
+ const p = new Promise((resolve, reject) => {
22
+ res = resolve;
23
+ });
24
+ saveQueue.drain(async (x) => {
25
+ res();
26
+ });
27
+ return p;
28
+ }
29
+ export { loadData };
package/dist/loader.js ADDED
@@ -0,0 +1,23 @@
1
+ import { Browser } from './storage/browser.js';
2
+ import { Filesystem } from './storage/filesystem.js';
3
+ import { Rest } from './storage/rest.js';
4
+ const FORCE_IDB = typeof process !== 'undefined' && !!process.env?.FORCE_IDB;
5
+ /* global window */
6
+ export const Loader = {
7
+ appropriate: (name, config = {}) => {
8
+ let isBrowser = false;
9
+ try {
10
+ isBrowser = window.localStorage && true;
11
+ }
12
+ catch (e) { }
13
+ if (config.type === 'rest') {
14
+ return new Rest(name, config);
15
+ }
16
+ if (FORCE_IDB || isBrowser) {
17
+ return new Browser(name, config);
18
+ }
19
+ else {
20
+ return new Filesystem(name, config);
21
+ }
22
+ }
23
+ };
@@ -398,7 +398,7 @@ declare class DbIndex {
398
398
  applyMapFn(mapFn: any, name: any): void;
399
399
  mapFnString: any;
400
400
  mapFn: any;
401
- includeDocsDefault: boolean;
401
+ includeDocsDefault: any;
402
402
  name: any;
403
403
  makeName(): any;
404
404
  toJSON(): {
@@ -41711,12 +41711,21 @@ class DbIndex {
41711
41711
  applyMapFn (mapFn, name) {
41712
41712
  if (typeof mapFn === 'string') {
41713
41713
  this.mapFnString = mapFn;
41714
+ // make a regex that matches strings that only have letters, numbers, and spaces
41715
+ const regex = /^[a-zA-Z0-9 ]+$/;
41716
+ // if the string matches the regex, make a function that returns the value at that key
41717
+ if (regex.test(mapFn)) {
41718
+ this.mapFn = (doc, emit) => {
41719
+ if (doc[mapFn]) emit(doc[mapFn]);
41720
+ };
41721
+ this.includeDocsDefault = true;
41722
+ }
41714
41723
  } else {
41715
41724
  this.mapFn = mapFn;
41716
41725
  this.mapFnString = mapFn.toString();
41717
41726
  }
41718
41727
  const matches = /=>\s*(.*)/.exec(this.mapFnString);
41719
- this.includeDocsDefault = matches && matches.length > 0;
41728
+ this.includeDocsDefault = this.includeDocsDefault || (matches && matches.length > 0);
41720
41729
  this.name = name || this.makeName();
41721
41730
  }
41722
41731