@seedprotocol/sdk 0.1.59 → 0.1.61

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
@@ -1,19 +1,22 @@
1
- # [WIP] Seed Protocol SDK
1
+ # Seed Protocol SDK
2
2
 
3
- This API is a work in progress. It is not yet ready for production use. These docs are for keeping the community
4
- informed
5
- and generating feedback.
3
+ The official SDK for [Seed Protocol](https://seedprotocol.io/).
6
4
 
7
- ## Current research questions
5
+ The SDK is a heavily opinionated ORM that saves its database (SQLite) and files (OPFS) within the user's browser. All
6
+ user data
7
+ is fetched from, or written to, the Ethereum Attestation Service (EAS) and Arweave (More attestation services
8
+ and decentralized storage providers will be supported in the future).
8
9
 
9
- - Can we use TypeORM backed by Sqlite Wasm for more performant and future-proof storage?
10
- - Track this research here: [TypeORM Sqlite Wasm](https://github.com/JournoDAO/typeorm-sqlite-wasm)
11
- - What would the tooling look like to allow export of data model as ProtoBuf and/or JSON Schema?
12
- - Looking at [ts-proto](https://github.com/stephenh/ts-proto) for Typescript
10
+ With all the remote storage on decentralized, public infrastructure, there's no server component to manage or rely on.
13
11
 
14
- ## Installing
12
+ The hope is that this local-first and distributed approach will make it easier for developers to build apps with Seed
13
+ Protocol
14
+ without ever custodying user data on their own infrastructure.
15
+
16
+ The SDK is currently used and developed by [PermaPress](https://permapress.xyz), the first client for Seed Protocol.
17
+ PermaPress is a product developed by JournoLabs (formerly JournoDAO).
15
18
 
16
- This package is not yet published to npm, but when it is, this will be the command to install it:
19
+ ## Installing
17
20
 
18
21
  ```bash
19
22
  yarn add @seedprotocol/sdk
@@ -21,47 +24,65 @@ yarn add @seedprotocol/sdk
21
24
 
22
25
  ## Getting Started
23
26
 
24
- The first thing to do when integrating Seed SDK is define you data model.
27
+ The first thing to do when integrating Seed SDK is define your data model by placing a `schema.ts` file in the root
28
+ of your project.
25
29
 
26
- For example, let's pretend we're creating a blog that uses Seed Protocol as its content store. We start by defining
27
- our `Models`, their `Properties`, and what type of data each `Property` is expecting.
30
+ As an example, here's the actual data model for PermaPress:
28
31
 
29
32
  ```typescript=
30
- import {Model, Property, List, createStore} from '@seedprotocol/sdk'
31
-
32
-
33
- const Image = Model({
34
- storageTransactionId: Property.String(),
35
- uri: Property.String(),
36
- alt: Property.String(),
37
- },)
38
-
39
- const Link = Model({
40
- url: Property.String(),
41
- text: Property.String(),
42
- },)
43
-
44
- const Identity = Model({
45
- name: Property.String(),
46
- bio: Property.String(),
47
- avatarImage: Image,
48
- },)
49
-
50
- const Post = Model({
51
- title: Property.String(),
52
- summary: Property.String(),
53
- featureImage: Image,
54
- html: Property.String(),
55
- json: Property.String(),
56
- authors: Property.List(Identity,),
57
- },)
58
-
59
- createStore({
33
+ import { ImageSrc, List, Model, Relation, Text } from '@/browser/schema'
34
+
35
+ @Model
36
+ class Image {
37
+ @Text() storageTransactionId!: string
38
+ @Text() uri!: string
39
+ @Text() alt!: string
40
+ @ImageSrc() src!: string
41
+ }
42
+
43
+ @Model
44
+ class Post {
45
+ @Text() title!: string
46
+ @Text() summary!: string
47
+ @Relation('Image', 'ImageSrc') featureImage!: string
48
+ @Text('ItemStorage', '/html', '.html') html!: string
49
+ @Text('ItemStorage', '/json', '.json') json!: string
50
+ @Text() storageTransactionId!: string
51
+ @List('Identity') authors!: string[]
52
+ @Text() importUrl!: string
53
+ }
54
+
55
+ @Model
56
+ class Identity {
57
+ @Text() name!: string
58
+ @Text() profile!: string
59
+ @Text() displayName!: string
60
+ @Relation('Image', 'ImageSrc') avatarImage!: string
61
+ @Relation('Image', 'ImageSrc') coverImage!: string
62
+ }
63
+
64
+ @Model
65
+ class Link {
66
+ @Text() url!: string
67
+ @Text() text!: string
68
+ }
69
+
70
+ const models = {
60
71
  Identity,
61
72
  Image,
62
73
  Link,
63
74
  Post,
64
- },)
75
+ }
76
+
77
+ const endpoints = {
78
+ filePaths: '/api/seed/migrations',
79
+ files: '/app-files',
80
+ }
81
+
82
+ export { models, endpoints }
83
+
84
+ export default { models, endpoints }
85
+
65
86
  ```
66
87
 
67
88
  This will create a database locally in the browser with all the tables and fields necessary to support your Models. Feel
@@ -989,7 +989,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
989
989
  if (propertyRecordSchema &&
990
990
  propertyRecordSchema.storageType &&
991
991
  propertyRecordSchema.storageType === 'ItemStorage') {
992
- const { Item } = yield import('./index-C_WqqX4v.js');
992
+ const { Item } = yield import('./index-tV-MoWhc.js');
993
993
  const item = yield Item.find({
994
994
  seedLocalId,
995
995
  modelName: itemModelName,
@@ -2877,7 +2877,7 @@ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
2877
2877
  if (!models$1) {
2878
2878
  return;
2879
2879
  }
2880
- const { models: SeedModels } = yield import('./seed.schema.config-BH9Kq1yX.js');
2880
+ const { models: SeedModels } = yield import('./seed.schema.config-BkdBBwUC.js');
2881
2881
  const allModels = Object.assign(Object.assign({}, SeedModels), models$1);
2882
2882
  let hasModelsInDb = false;
2883
2883
  const schemaDefsByModelName = new Map();
@@ -6334,16 +6334,6 @@ const getServiceUniqueKey = (service) => {
6334
6334
  }
6335
6335
  return uniqueKey;
6336
6336
  };
6337
- const useIsDbReady = () => {
6338
- const [isDbReady, setIsDbReady] = useState(false);
6339
- const { internalStatus } = useGlobalServiceStatus();
6340
- useEffect(() => {
6341
- if (internalStatus === 'ready') {
6342
- setIsDbReady(true);
6343
- }
6344
- }, [internalStatus]);
6345
- return isDbReady;
6346
- };
6347
6337
  const useServices = () => {
6348
6338
  const [actors, setActors] = useState([]);
6349
6339
  const [percentComplete, setPercentComplete] = useState(5);
@@ -6461,6 +6451,7 @@ const useItem = ({ modelName, seedLocalId, seedUid }) => {
6461
6451
  });
6462
6452
  if (!foundItem) {
6463
6453
  logger$2('[useItem] [getItemFromDb] no item found', modelName, seedLocalId);
6454
+ isReadingDb.current = false;
6464
6455
  return;
6465
6456
  }
6466
6457
  setItem(foundItem);
@@ -6510,35 +6501,39 @@ const useItem = ({ modelName, seedLocalId, seedUid }) => {
6510
6501
  };
6511
6502
  const useItems = ({ modelName, deleted }) => {
6512
6503
  const [items, setItems] = useImmer([]);
6513
- const [isReadingDb, setIsReadingDb] = useState(false);
6514
- const [isInitialized, setIsInitialized] = useState(false);
6515
- const isDbReady = useIsDbReady();
6504
+ const { status, internalStatus } = useGlobalServiceStatus();
6516
6505
  const modelNameRef = useRef(modelName);
6517
- const readFromDb = useCallback((event) => __awaiter(void 0, void 0, void 0, function* () {
6518
- if (!event ||
6519
- !event.modelName ||
6520
- event.modelName !== modelNameRef.current ||
6521
- isReadingDb) {
6506
+ const isReadingDb = useRef(false);
6507
+ const readFromDb = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
6508
+ if (isReadingDb.current || internalStatus !== 'ready') {
6522
6509
  return;
6523
6510
  }
6524
- setIsReadingDb(true);
6511
+ isReadingDb.current = true;
6525
6512
  const allItems = yield Item.all(modelNameRef.current, deleted);
6513
+ setItems(() => []);
6526
6514
  setItems(() => allItems);
6527
- setIsReadingDb(false);
6528
- }), [modelName, isReadingDb]);
6515
+ isReadingDb.current = false;
6516
+ }), [internalStatus]);
6517
+ const listenerRef = useRef(readFromDb);
6529
6518
  useEffect(() => {
6530
- if (isDbReady && !isInitialized) {
6531
- const _fetchItems = () => __awaiter(void 0, void 0, void 0, function* () {
6532
- yield readFromDb({ modelName });
6533
- setIsInitialized(true);
6534
- });
6535
- _fetchItems();
6519
+ listenerRef.current = readFromDb;
6520
+ }, [readFromDb]);
6521
+ useEffect(() => {
6522
+ if (internalStatus === 'ready') {
6523
+ listenerRef.current();
6536
6524
  }
6537
- }, [isInitialized, isDbReady]);
6525
+ }, [internalStatus, status]);
6538
6526
  useEffect(() => {
6539
- eventEmitter.addListener('item.requestAll', readFromDb);
6527
+ eventEmitter.addListener('item.requestAll', (event) => {
6528
+ if (!event ||
6529
+ !event.modelName ||
6530
+ event.modelName !== modelNameRef.current) {
6531
+ return;
6532
+ }
6533
+ listenerRef.current();
6534
+ });
6540
6535
  return () => {
6541
- eventEmitter.removeListener('item.requestAll');
6536
+ eventEmitter.removeListener('item.requestAll', readFromDb);
6542
6537
  };
6543
6538
  }, []);
6544
6539
  return {
@@ -6548,7 +6543,6 @@ const useItems = ({ modelName, deleted }) => {
6548
6543
  item.createdAt,
6549
6544
  ], ['desc']).slice(0, 10),
6550
6545
  isReadingDb,
6551
- isInitialized,
6552
6546
  };
6553
6547
  };
6554
6548
  const useItemIsReady = () => {
@@ -6774,7 +6768,7 @@ const client = {
6774
6768
  console.error('fs listeners not ready during init');
6775
6769
  }
6776
6770
  globalService.send({ type: 'init', endpoints, models, addresses });
6777
- import('./seed.schema.config-BH9Kq1yX.js').then(({ models }) => {
6771
+ import('./seed.schema.config-BkdBBwUC.js').then(({ models }) => {
6778
6772
  for (const [key, value] of Object.entries(models)) {
6779
6773
  setModel(key, value);
6780
6774
  }
@@ -7347,4 +7341,4 @@ if (isNode()) {
7347
7341
  }
7348
7342
 
7349
7343
  export { GET_SCHEMAS as G, Item as I, Json as J, List as L, Model as M, Property as P, Relation as R, Text as T, GET_SEEDS as a, GET_SEED_IDS as b, GET_STORAGE_TRANSACTION_ID as c, GET_VERSIONS as d, GET_PROPERTIES as e, GET_ALL_PROPERTIES_FOR_ALL_VERSIONS as f, itemMachineAll as g, ImageSrc as h, itemMachineSingle as i, ItemProperty as j, useItem as k, useItemProperties as l, useCreateItem as m, useItemProperty as n, useDeleteItem as o, useGlobalServiceStatus as p, useServices as q, getGlobalService as r, client as s, getCorrectId as t, useItems as u, withSeed as w };
7350
- //# sourceMappingURL=index-RCrXtjiO.js.map
7344
+ //# sourceMappingURL=index-BBcjMsIh.js.map