@seedprotocol/sdk 0.1.13 → 0.1.14

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 (37) hide show
  1. package/dist/bin.js +16 -15
  2. package/dist/bin.js.map +1 -1
  3. package/dist/{events-DbpQM9qG.js → events-DY-qRoqO.js} +1785 -1675
  4. package/dist/events-DY-qRoqO.js.map +1 -0
  5. package/dist/{index-D2_skdGT.js → index-Do5zWGFy.js} +19 -17
  6. package/dist/index-Do5zWGFy.js.map +1 -0
  7. package/dist/main.js +16 -15
  8. package/dist/main.js.map +1 -1
  9. package/dist/{seed-DM5koJUz.js → seed-BJtzMyfP.js} +20 -18
  10. package/dist/seed-BJtzMyfP.js.map +1 -0
  11. package/dist/{seed-CSOeghww.js → seed-CVV8OMEg.js} +2 -2
  12. package/dist/{seed-CSOeghww.js.map → seed-CVV8OMEg.js.map} +1 -1
  13. package/dist/{seed-DHOFK9DF.js → seed-Ch6JPrtQ.js} +20 -18
  14. package/dist/seed-Ch6JPrtQ.js.map +1 -0
  15. package/dist/{seed.schema.config-Cz8esgav.js → seed.schema.config-t5AiIDm_.js} +16 -15
  16. package/dist/seed.schema.config-t5AiIDm_.js.map +1 -0
  17. package/dist/types/src/browser/index.d.ts +0 -1
  18. package/dist/types/src/browser/index.d.ts.map +1 -1
  19. package/dist/types/src/browser/react/db.d.ts +4 -0
  20. package/dist/types/src/browser/react/db.d.ts.map +1 -0
  21. package/dist/types/src/browser/react/index.d.ts +4 -53
  22. package/dist/types/src/browser/react/index.d.ts.map +1 -1
  23. package/dist/types/src/browser/react/item.d.ts +36 -0
  24. package/dist/types/src/browser/react/item.d.ts.map +1 -0
  25. package/dist/types/src/browser/react/property.d.ts +12 -0
  26. package/dist/types/src/browser/react/property.d.ts.map +1 -0
  27. package/dist/types/src/browser/react/services.d.ts +30 -0
  28. package/dist/types/src/browser/react/services.d.ts.map +1 -0
  29. package/dist/types/src/index.d.ts +1 -2
  30. package/dist/types/src/index.d.ts.map +1 -1
  31. package/dist/types/src/shared/helpers/index.d.ts +1 -1
  32. package/package.json +1 -1
  33. package/dist/events-DbpQM9qG.js.map +0 -1
  34. package/dist/index-D2_skdGT.js.map +0 -1
  35. package/dist/seed-DHOFK9DF.js.map +0 -1
  36. package/dist/seed-DM5koJUz.js.map +0 -1
  37. package/dist/seed.schema.config-Cz8esgav.js.map +0 -1
@@ -1,28 +1,30 @@
1
- import { Type } from '@sinclair/typebox';
2
- import { useState, useEffect, useCallback, useRef } from 'react';
1
+ import { useImmer } from 'use-immer';
2
+ import { sql, count, max, eq, and, or, isNull, relations } from 'drizzle-orm';
3
+ import { useState, useCallback, useEffect, useRef } from 'react';
4
+ import debug from 'debug';
3
5
  import { fromCallback, setup, assign, createActor, waitFor, emit } from 'xstate';
4
6
  import { BehaviorSubject } from 'rxjs';
5
7
  import { fs, configureSingle } from '@zenfs/core';
6
- import { sql, count, max, eq, and, or, isNull, relations } from 'drizzle-orm';
7
- import { drizzle } from 'drizzle-orm/sqlite-proxy';
8
- import debug from 'debug';
9
- import 'dayjs';
10
- import { customAlphabet } from 'nanoid';
11
- import * as nanoIdDictionary from 'nanoid-dictionary';
12
8
  import { startCase, debounce, camelCase, orderBy } from 'lodash-es';
13
- import { sqliteTable, text, int, blob, check, unique } from 'drizzle-orm/sqlite-core';
9
+ import { immerable, produce } from 'immer';
10
+ import pluralize from 'pluralize';
11
+ import { useSelector } from '@xstate/react';
12
+ import { orderBy as orderBy$1 } from 'lodash';
13
+ import { createBrowserInspector } from '@statelyai/inspect';
14
+ import 'reflect-metadata';
15
+ import { Type } from '@sinclair/typebox';
16
+ import Arweave from 'arweave';
17
+ import { WebAccess } from '@zenfs/dom';
18
+ import { drizzle } from 'drizzle-orm/sqlite-proxy';
14
19
  import { QueryClient } from '@tanstack/react-query';
15
20
  import { GraphQLClient } from 'graphql-request';
16
21
  import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
17
22
  import { persistQueryClient } from '@tanstack/react-query-persist-client';
18
23
  import path, { basename } from 'path';
19
- import { immerable } from 'immer';
20
- import pluralize from 'pluralize';
21
- import { createBrowserInspector } from '@statelyai/inspect';
22
- import { WebAccess } from '@zenfs/dom';
23
- import Arweave from 'arweave';
24
- import { useImmer } from 'use-immer';
25
- import { useSelector } from '@xstate/react';
24
+ import { sqliteTable, text, int, blob, check, unique } from 'drizzle-orm/sqlite-core';
25
+ import 'dayjs';
26
+ import { customAlphabet } from 'nanoid';
27
+ import * as nanoIdDictionary from 'nanoid-dictionary';
26
28
  import EventEmitter from 'eventemitter3';
27
29
 
28
30
  const isNode = () => {
@@ -213,14 +215,14 @@ const getSqlite = async () => {
213
215
  }
214
216
  };
215
217
 
216
- const logger$e = debug('app:db:actors');
218
+ const logger$g = debug('app:db:actors');
217
219
  let seedDb;
218
220
  let appDb;
219
221
  let sdkConfigDb;
220
222
  let sqliteWasmClient$1;
221
223
  const checkStatus = fromCallback(({ sendBack, input: { context } }) => {
222
224
  const { dbName, dirName } = context;
223
- logger$e('[db/actors] checkStatus context', context);
225
+ logger$g('[db/actors] checkStatus context', context);
224
226
  const pathToDir = `${BROWSER_FS_TOP_DIR}/${dirName}`;
225
227
  const pathToDbDir = `${pathToDir}/db`;
226
228
  const pathToDb = `${pathToDbDir}/${dbName}.sqlite3`;
@@ -251,7 +253,7 @@ const checkStatus = fromCallback(({ sendBack, input: { context } }) => {
251
253
  });
252
254
  });
253
255
  const connectToDb = fromCallback(({ sendBack, input: { context } }) => {
254
- logger$e('[db/actors] connectToDb context', context);
256
+ logger$g('[db/actors] connectToDb context', context);
255
257
  const { dbName, pathToDir } = context;
256
258
  let isConnecting = false;
257
259
  let dbId;
@@ -266,16 +268,16 @@ const connectToDb = fromCallback(({ sendBack, input: { context } }) => {
266
268
  }
267
269
  //@ts-ignore
268
270
  response = yield sqliteWasmClient$1('config-get', {});
269
- logger$e(response);
270
- logger$e('Running SQLite3 version', response.result.version.libVersion);
271
+ logger$g(response);
272
+ logger$g('Running SQLite3 version', response.result.version.libVersion);
271
273
  //@ts-ignore
272
274
  response = yield sqliteWasmClient$1('open', {
273
275
  filename: `file:${pathToDir}/db/${dbName}.sqlite3?vfs=opfs`,
274
276
  });
275
- logger$e(response);
277
+ logger$g(response);
276
278
  dbId = response.dbId;
277
279
  // logger(`dbId: ${dbId}`)
278
- logger$e('OPFS is available, created persisted database at', response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'));
280
+ logger$g('OPFS is available, created persisted database at', response.result.filename.replace(/^file:(.*?)\?vfs=opfs$/, '$1'));
279
281
  });
280
282
  const interval = setInterval(() => {
281
283
  // TODO: Add a timeout
@@ -395,7 +397,7 @@ const dbExec = (dbId_1, params_1, sql_1, dbName_1, ...args_1) => __awaiter(void
395
397
  });
396
398
  const migrate = fromCallback(({ sendBack, input: { context } }) => {
397
399
  const { pathToDbDir, dirName, dbId, dbName } = context;
398
- logger$e('[db/actors] migrate context', context);
400
+ logger$g('[db/actors] migrate context', context);
399
401
  const schemaGlobString = `${BROWSER_FS_TOP_DIR}/${dirName}/schema/*`;
400
402
  const isSeedDb = dbName === DB_NAME_SEED;
401
403
  const isAppDb = dbName === DB_NAME_APP;
@@ -675,7 +677,7 @@ const initialize$3 = fromCallback(({ sendBack, input: { context } }) => {
675
677
  }
676
678
  });
677
679
 
678
- const logger$d = debug('app:shared:helpers');
680
+ const logger$f = debug('app:shared:helpers');
679
681
  const { alphanumeric } = nanoIdDictionary;
680
682
  const generateId = () => {
681
683
  return customAlphabet(alphanumeric, 10)();
@@ -738,7 +740,7 @@ const convertTxIdToImageSrc = (txId) => __awaiter(void 0, void 0, void 0, functi
738
740
  const imageFilePath = `/files/images/${txId}`;
739
741
  const fileExists = yield fs.promises.exists(imageFilePath);
740
742
  if (!fileExists) {
741
- logger$d(`[ItemView] [updateImageSrc] ${imageFilePath} does not exist`);
743
+ logger$f(`[ItemView] [updateImageSrc] ${imageFilePath} does not exist`);
742
744
  return;
743
745
  }
744
746
  const uint = yield fs.promises.readFile(imageFilePath);
@@ -1517,7 +1519,7 @@ const getAddressesFromDb = () => __awaiter(void 0, void 0, void 0, function* ()
1517
1519
  return JSON.parse(addressArrayString);
1518
1520
  });
1519
1521
 
1520
- const logger$c = debug('app:property:actors:hydrateFromDb');
1522
+ const logger$e = debug('app:property:actors:hydrateFromDb');
1521
1523
  const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
1522
1524
  const { seedUid, seedLocalId, propertyName: propertyNameRaw, propertyValue, propertyRecordSchema, itemModelName, } = context;
1523
1525
  let propertyName = propertyNameRaw;
@@ -1585,23 +1587,23 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
1585
1587
  const firstRow = rows[0];
1586
1588
  const { localId, uid, propertyName: propertyNameFromDb, propertyValue: propertyValueFromDb, seedLocalId: seedLocalIdFromDb, seedUid: seedUidFromDb, schemaUid: schemaUidFromDb, refResolvedValue, refResolvedDisplayValue, } = firstRow;
1587
1589
  if (propertyName && !propertyNameFromDb) {
1588
- logger$c(`Property name from code is ${propertyName} but has not value in db ${propertyNameFromDb} for Property.${localId}`);
1590
+ logger$e(`Property name from code is ${propertyName} but has not value in db ${propertyNameFromDb} for Property.${localId}`);
1589
1591
  }
1590
1592
  if (propertyName &&
1591
1593
  propertyNameFromDb &&
1592
1594
  !propertyNameFromDb.includes(propertyName) &&
1593
1595
  !propertyName.includes(propertyNameFromDb) &&
1594
1596
  propertyNameFromDb !== propertyName) {
1595
- logger$c(`Property name from db ${propertyNameFromDb} does not match property name ${propertyName} for Property.${localId}`);
1597
+ logger$e(`Property name from db ${propertyNameFromDb} does not match property name ${propertyName} for Property.${localId}`);
1596
1598
  }
1597
1599
  if (propertyValue && propertyValueFromDb !== propertyValue) {
1598
- logger$c(`Property value from db ${propertyValueFromDb} does not match property value ${propertyValue} for Property.${localId}`);
1600
+ logger$e(`Property value from db ${propertyValueFromDb} does not match property value ${propertyValue} for Property.${localId}`);
1599
1601
  }
1600
1602
  if (seedLocalIdFromDb !== seedLocalId) {
1601
- logger$c(`Seed local id from db ${seedLocalIdFromDb} does not match seed local id ${seedLocalId} for Property.${localId}`);
1603
+ logger$e(`Seed local id from db ${seedLocalIdFromDb} does not match seed local id ${seedLocalId} for Property.${localId}`);
1602
1604
  }
1603
1605
  if (seedUidFromDb !== seedUid) {
1604
- logger$c(`Seed uid from db ${seedUidFromDb} does not match seed uid ${seedUid} for Property.${localId}`);
1606
+ logger$e(`Seed uid from db ${seedUidFromDb} does not match seed uid ${seedUid} for Property.${localId}`);
1605
1607
  }
1606
1608
  sendBack({
1607
1609
  type: 'updateContext',
@@ -1616,7 +1618,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
1616
1618
  renderValue: refResolvedDisplayValue,
1617
1619
  });
1618
1620
  if (propertyNameFromDb === 'storageTransactionId') {
1619
- const { Item } = yield import('./index-D2_skdGT.js');
1621
+ const { Item } = yield import('./index-Do5zWGFy.js');
1620
1622
  const item = yield Item.find({
1621
1623
  seedLocalId,
1622
1624
  modelName: itemModelName,
@@ -1634,7 +1636,7 @@ const hydrateFromDb = fromCallback(({ sendBack, input: { context } }) => {
1634
1636
  const renderValue = yield fs.promises
1635
1637
  .readFile(htmlFilePath, 'utf8')
1636
1638
  .catch((error) => {
1637
- logger$c('Error reading html file', error);
1639
+ logger$e('Error reading html file', error);
1638
1640
  });
1639
1641
  property
1640
1642
  .getService()
@@ -1715,7 +1717,7 @@ const getVersionData = (_a) => __awaiter(void 0, [_a], void 0, function* ({ seed
1715
1717
 
1716
1718
  const eventEmitter = new EventEmitter();
1717
1719
 
1718
- const logger$b = debug('app:write');
1720
+ const logger$d = debug('app:write');
1719
1721
  const sendItemUpdateEvent = ({ modelName, seedLocalId, seedUid }) => {
1720
1722
  if (!modelName || (!seedLocalId && !seedUid)) {
1721
1723
  return;
@@ -1793,7 +1795,7 @@ const deleteItem = (_a) => __awaiter(void 0, [_a], void 0, function* ({ seedLoca
1793
1795
  });
1794
1796
  const updateItemPropertyValue = (_a) => __awaiter(void 0, [_a], void 0, function* ({ propertyLocalId, propertyName, newValue, seedUid, seedLocalId, modelName, refSeedType, refResolvedValue, refResolvedDisplayValue, versionLocalId, versionUid, schemaUid, }) {
1795
1797
  if (!propertyLocalId && !seedLocalId) {
1796
- logger$b(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
1798
+ logger$d(`[db/write] [updateItemPropertyValue] no propertyLocalId or seedLocalId for property: ${propertyName}`);
1797
1799
  return;
1798
1800
  }
1799
1801
  let safeNewValue = newValue;
@@ -1832,7 +1834,7 @@ const updateItemPropertyValue = (_a) => __awaiter(void 0, [_a], void 0, function
1832
1834
  const schemaUid = mostRecentRecord[9];
1833
1835
  const easDataType = mostRecentRecord[10];
1834
1836
  if (propertyValueFromDb === newValue) {
1835
- logger$b(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
1837
+ logger$d(`[db/write] [updateItemPropertyValue] value is the same as most recent record for property: ${propertyNameFromDb}`);
1836
1838
  return;
1837
1839
  }
1838
1840
  // This means we already have a local-only record so we should just update that one
@@ -2247,7 +2249,7 @@ const setModel = (modelName, model) => {
2247
2249
  };
2248
2250
 
2249
2251
  var _a$1;
2250
- const logger$a = debug('app:property:class');
2252
+ const logger$c = debug('app:property:class');
2251
2253
  const namesThatEndWithId = [];
2252
2254
  class ItemProperty {
2253
2255
  // private constructor(localIdOrUid) {
@@ -2295,7 +2297,7 @@ class ItemProperty {
2295
2297
  serviceInput.propertyValue = JSON.parse(propertyValue);
2296
2298
  }
2297
2299
  catch (e) {
2298
- logger$a('List property value is not JSON', e);
2300
+ logger$c('List property value is not JSON', e);
2299
2301
  }
2300
2302
  }
2301
2303
  const propertyNameSingular = pluralize(propertyName, 1);
@@ -2357,7 +2359,7 @@ class ItemProperty {
2357
2359
  this._service.start();
2358
2360
  }
2359
2361
  _updateResponseListener(event) {
2360
- logger$a(`[ItemProperty] [_updateResponseListener] [${this.itemModelName}.${this.seedLocalId}] ${this.propertyName} event`, event);
2362
+ logger$c(`[ItemProperty] [_updateResponseListener] [${this.itemModelName}.${this.seedLocalId}] ${this.propertyName} event`, event);
2361
2363
  }
2362
2364
  static create(props) {
2363
2365
  const { propertyName, seedLocalId, uid } = props;
@@ -2493,7 +2495,7 @@ class ItemProperty {
2493
2495
  }
2494
2496
  unload() {
2495
2497
  this._service.stop();
2496
- logger$a(`[XXXXXX] [ItemProperty] [${this.seedLocalId}] [unload] removing listener`, this._updateResponseEvent);
2498
+ logger$c(`[XXXXXX] [ItemProperty] [${this.seedLocalId}] [unload] removing listener`, this._updateResponseEvent);
2497
2499
  eventEmitter.removeListener(this._updateResponseEvent, this._updateResponseListener);
2498
2500
  }
2499
2501
  }
@@ -3782,7 +3784,7 @@ const getPropertiesForSeed = (seedLocalId, seedUid) => __awaiter(void 0, void 0,
3782
3784
  return propertiesData;
3783
3785
  });
3784
3786
 
3785
- const logger$9 = debug('app:db:queries:getItem');
3787
+ const logger$b = debug('app:db:queries:getItem');
3786
3788
  const getItemDataFromDb = (_a) => __awaiter(void 0, [_a], void 0, function* ({ modelName, seedLocalId, seedUid, }) {
3787
3789
  if (!seedLocalId && !seedUid) {
3788
3790
  throw new Error('[db/queries] [getItem] no seedLocalId or seedUid');
@@ -3790,7 +3792,7 @@ const getItemDataFromDb = (_a) => __awaiter(void 0, [_a], void 0, function* ({ m
3790
3792
  if (seedUid && !seedLocalId) {
3791
3793
  const seedData = yield getSeedData({ seedUid });
3792
3794
  if (!seedData) {
3793
- logger$9('[db/queries] [getItem] no seedData seedUid', seedUid);
3795
+ logger$b('[db/queries] [getItem] no seedData seedUid', seedUid);
3794
3796
  return;
3795
3797
  }
3796
3798
  seedLocalId = seedData.localId;
@@ -4218,7 +4220,7 @@ const fetchDbData = fromCallback(({ sendBack, input: { context } }) => {
4218
4220
  return () => { };
4219
4221
  });
4220
4222
 
4221
- const logger$8 = debug('app:allItemsActors:fetchSeeds');
4223
+ const logger$a = debug('app:allItemsActors:fetchSeeds');
4222
4224
  const fetchSeeds = fromCallback(({ sendBack, input: { context } }) => {
4223
4225
  const { queryVariables, modelName } = context;
4224
4226
  if (!queryVariables) {
@@ -4228,7 +4230,7 @@ const fetchSeeds = fromCallback(({ sendBack, input: { context } }) => {
4228
4230
  const _fetchSeeds = () => __awaiter(void 0, void 0, void 0, function* () {
4229
4231
  const queryKey = [`getSeeds${modelName}`];
4230
4232
  const cachedResults = queryClient.getQueryData(queryKey);
4231
- logger$8(`[allItemsActors] [fetchSeeds] cachedResults ${Date.now()}`, cachedResults);
4233
+ logger$a(`[allItemsActors] [fetchSeeds] cachedResults ${Date.now()}`, cachedResults);
4232
4234
  const results = yield queryClient.fetchQuery({
4233
4235
  queryKey,
4234
4236
  queryFn: () => __awaiter(void 0, void 0, void 0, function* () { return easClient.request(GET_SEEDS, queryVariables); }),
@@ -4799,1723 +4801,1831 @@ const getArweave = () => {
4799
4801
  });
4800
4802
  };
4801
4803
 
4802
- const logger$7 = debug('app:global:actors');
4803
- const initialize = fromCallback(({ sendBack, input: { event, context } }) => {
4804
- const { internalService, models, endpoints } = context;
4805
- const { addresses } = event;
4806
- let environment = 'browser';
4807
- if (isNode()) {
4808
- environment = 'node';
4809
- }
4810
- if (isReactNative()) {
4811
- environment = 'react-native';
4812
- }
4813
- let internalSubscription;
4814
- if (environment === 'browser' && models) {
4815
- const _initFileSystem = () => __awaiter(void 0, void 0, void 0, function* () {
4816
- return;
4817
- // return new Promise((resolve) => {
4818
- // })
4819
- });
4820
- const _initInternal = () => __awaiter(void 0, void 0, void 0, function* () {
4821
- return new Promise((resolve) => {
4822
- internalSubscription = internalService.subscribe((snapshot) => {
4823
- logger$7('[sdk] [internal] snapshot', snapshot);
4824
- if (snapshot.value === 'ready') {
4825
- resolve();
4826
- }
4827
- });
4828
- internalService.send({ type: 'init', endpoints, addresses });
4829
- });
4830
- });
4831
- _initFileSystem().then(() => {
4832
- logger$7('[global/actors] File system initialized');
4833
- });
4834
- _initInternal().then(() => {
4835
- logger$7('[global/actors] Internal initialized');
4836
- sendBack({ type: GLOBAL_INITIALIZING_INTERNAL_SERVICE_READY });
4837
- internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
4838
- });
4839
- // _initEas().then(() => {
4840
- // logger('EAS initialized')
4841
- // })
4842
- }
4843
- sendBack({ type: GLOBAL_INITIALIZING_SEND_CONFIG, environment });
4844
- return () => {
4845
- internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
4846
- };
4847
- });
4848
- const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
4849
- const { models: models$1 } = context;
4850
- const _addModelsToDb = () => __awaiter(void 0, void 0, void 0, function* () {
4851
- var _a;
4852
- const sdkConfigDb = getSdkDb();
4853
- if (!models$1) {
4804
+ const logger$9 = debug('app:react:db');
4805
+ const useDbsAreReady = () => {
4806
+ const [dbsAreReady, setDbsAreReady] = useState(false);
4807
+ const update = useCallback(() => {
4808
+ if (dbsAreReady) {
4854
4809
  return;
4855
4810
  }
4856
- const { models: SeedModels } = yield import('./seed.schema.config-Cz8esgav.js');
4857
- const allModels = Object.assign(Object.assign({}, SeedModels), models$1);
4858
- let hasModelsInDb = false;
4859
- const schemaDefsByModelName = new Map();
4860
- for (const [modelName, _] of Object.entries(allModels)) {
4861
- logger$7('[helpers/db] [addModelsToInternalDb] starting modelName:', modelName);
4862
- let foundModel;
4863
- const foundModelsQuery = yield sdkConfigDb
4864
- .select()
4865
- .from(models)
4866
- .where(eq(models.name, modelName));
4867
- if (!foundModelsQuery || foundModelsQuery.length === 0) {
4868
- yield sdkConfigDb.insert(models).values({
4869
- name: modelName,
4811
+ setDbsAreReady(true);
4812
+ }, []);
4813
+ useEffect(() => {
4814
+ let globalSubscription;
4815
+ let internalSubscription;
4816
+ const _waitForDbs = () => __awaiter(void 0, void 0, void 0, function* () {
4817
+ const globalService = getGlobalService();
4818
+ const internalService = globalService.getSnapshot().context.internalService;
4819
+ if (!internalService) {
4820
+ logger$9('[useDbsAreReady] [useEffect] no internalService');
4821
+ globalSubscription = globalService.subscribe(({ context }) => {
4822
+ if (!internalSubscription && context && context.internalService) {
4823
+ globalSubscription === null || globalSubscription === void 0 ? void 0 : globalSubscription.unsubscribe();
4824
+ internalSubscription = context.internalService.subscribe((snapshot) => {
4825
+ if (snapshot.value === 'ready') {
4826
+ update();
4827
+ internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
4828
+ }
4829
+ });
4830
+ }
4870
4831
  });
4871
- logger$7('[global/actors] [addModelsToDb] inserted model:', modelName);
4872
- const foundModels = yield sdkConfigDb
4873
- .select({
4874
- id: models.id,
4875
- name: models.name,
4876
- uid: modelUids.uid,
4877
- })
4878
- .from(models)
4879
- .leftJoin(modelUids, eq(models.id, modelUids.modelId))
4880
- .where(eq(models.name, modelName))
4881
- .limit(1);
4882
- foundModel = foundModels[0];
4883
- }
4884
- if (foundModelsQuery && foundModelsQuery.length > 0) {
4885
- foundModel = foundModelsQuery[0];
4832
+ return;
4886
4833
  }
4887
- if (!foundModel) {
4888
- hasModelsInDb = false;
4889
- break;
4834
+ const currentState = internalService.getSnapshot().value;
4835
+ if (currentState === 'ready') {
4836
+ update();
4837
+ return;
4890
4838
  }
4891
- schemaDefsByModelName.set(modelName, {
4892
- dbId: foundModel.id,
4893
- schemaDef: `bytes32 ${toSnakeCase(modelName)}`,
4839
+ internalSubscription = internalService.subscribe((snapshot) => {
4840
+ if (snapshot.value === 'ready') {
4841
+ update();
4842
+ internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
4843
+ }
4894
4844
  });
4895
- }
4896
- if (!hasModelsInDb) {
4897
- return false;
4898
- }
4899
- const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
4900
- const { schemas } = yield queryClient.fetchQuery({
4901
- queryKey: [`getSchemasVersion`],
4902
- queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
4903
- return easClient.request(GET_SCHEMAS, {
4904
- where: {
4905
- schema: {
4906
- in: schemaDefs,
4907
- },
4908
- },
4909
- });
4910
- }),
4911
4845
  });
4912
- if (!schemas || schemas.length === 0) {
4913
- throw new Error(`No schemas found`);
4914
- }
4915
- for (const schema of schemas) {
4916
- const modelId = (_a = Array.from(schemaDefsByModelName.values()).find(({ schemaDef }) => schemaDef === schema.schema)) === null || _a === void 0 ? void 0 : _a.dbId;
4917
- if (!modelId) {
4918
- throw new Error(`No modelId found for schema ${schema.schema}`);
4846
+ _waitForDbs();
4847
+ return () => {
4848
+ if (globalSubscription) {
4849
+ globalSubscription.unsubscribe();
4919
4850
  }
4920
- yield sdkConfigDb
4921
- .insert(modelUids)
4922
- .values({
4923
- modelId,
4924
- uid: schema.id,
4925
- })
4926
- .onConflictDoNothing();
4927
- }
4928
- });
4929
- _addModelsToDb().then((hasModelsInDb) => {
4930
- sendBack({ type: GLOBAL_ADDING_MODELS_TO_DB_SUCCESS });
4931
- for (const [modelName, model] of Object.entries(models$1)) {
4932
- const service = context[`${modelName}Service`];
4933
- service.send({ type: 'modelsFound' });
4851
+ if (internalSubscription) {
4852
+ internalSubscription.unsubscribe();
4853
+ }
4854
+ };
4855
+ }, []);
4856
+ return {
4857
+ dbsAreReady,
4858
+ };
4859
+ };
4860
+
4861
+ const finalStrings = ['idle', 'ready', 'done', 'success'];
4862
+ const getServiceName = (service) => {
4863
+ let name = 'actor';
4864
+ if (service && service.uniqueKey) {
4865
+ name = service.uniqueKey;
4866
+ }
4867
+ if (service && !service.uniqueKey && service.logic && service.logic.config) {
4868
+ name = getServiceUniqueKey(service);
4869
+ }
4870
+ return name;
4871
+ };
4872
+ const getServiceValue = (service) => {
4873
+ let value;
4874
+ if (service && service.getSnapshot() && service.getSnapshot().value) {
4875
+ value = service.getSnapshot().value;
4876
+ }
4877
+ if (getServiceName(service) === 'global') {
4878
+ if (value &&
4879
+ typeof value === 'object' &&
4880
+ Object.keys(value).length > 0 &&
4881
+ Object.keys(value)[0] === 'initialized') {
4882
+ value = 'ready';
4934
4883
  }
4935
- eventEmitter.emit('syncDbWithEas');
4936
- return;
4937
- });
4938
- return () => { };
4939
- });
4940
- const getSchemaForModel = fromCallback(({ sendBack, input: { context, event } }) => {
4941
- const { modelName } = event;
4942
- if (!modelName) {
4943
- console.warn('No modelName found');
4944
- return;
4945
4884
  }
4946
- const { models } = context;
4947
- if (!models) {
4948
- console.warn('No models found');
4885
+ return value;
4886
+ };
4887
+ const getServiceUniqueKey = (service) => {
4888
+ if (!service || !service.logic || !service.logic.config) {
4949
4889
  return;
4950
4890
  }
4951
- const model = Object.entries(models).find(([modelNameFromConfig]) => modelNameFromConfig === modelName);
4952
- if (!model) {
4953
- throw new Error(`Model ${modelName} not found`);
4891
+ const config = service.logic.config;
4892
+ if (!config.id) {
4893
+ return;
4954
4894
  }
4955
- logger$7('[service/actor] [getSchemaForModel] model:', model);
4956
- sendBack({ type: 'schemaForModel', schema: model.schema });
4957
- return () => { };
4958
- });
4959
-
4960
- class SqliteConnectionManager {
4961
- constructor(sqliteModule, idleTimeout = 300000) {
4962
- // Default idle timeout: 5 minutes
4963
- this.sqliteModule = sqliteModule;
4964
- this.idleTimeout = idleTimeout;
4965
- this.databases = {};
4966
- this.idleTimers = {};
4895
+ let uniqueKey = config.id;
4896
+ if (config.id.includes('@seedSdk/')) {
4897
+ uniqueKey = config.id.match(/^.*@seedSdk\/(\w+)[\.\w]*/)[1];
4967
4898
  }
4968
- resetIdleTimer(dbName) {
4969
- if (this.idleTimers[dbName]) {
4970
- clearTimeout(this.idleTimers[dbName]);
4899
+ const snapshot = service.getSnapshot();
4900
+ if (snapshot) {
4901
+ const context = snapshot.context;
4902
+ if (context && context.dbName) {
4903
+ uniqueKey = context.dbName;
4904
+ }
4905
+ if (context && context.modelNamePlural) {
4906
+ uniqueKey = context.modelNamePlural;
4907
+ }
4908
+ if (context && context.modelName) {
4909
+ uniqueKey = pluralize(context.modelName.toLowerCase());
4971
4910
  }
4972
- this.idleTimers[dbName] = setTimeout(() => {
4973
- this.closeConnection(dbName);
4974
- }, this.idleTimeout);
4975
4911
  }
4976
- getConnection(dbName) {
4977
- return __awaiter(this, void 0, void 0, function* () {
4978
- if (this.databases[dbName]) {
4979
- this.resetIdleTimer(dbName);
4980
- return this.databases[dbName];
4981
- }
4982
- const db = new this.sqliteModule();
4983
- yield db.open(dbName);
4984
- this.databases[dbName] = db;
4985
- this.resetIdleTimer(dbName);
4986
- return db;
4987
- });
4988
- }
4989
- execute(dbName_1, sql_1) {
4990
- return __awaiter(this, arguments, void 0, function* (dbName, sql, params = []) {
4991
- const db = yield this.getConnection(dbName);
4992
- const result = db.exec(sql, params);
4993
- this.resetIdleTimer(dbName);
4994
- return result;
4995
- });
4996
- }
4997
- closeConnection(dbName) {
4998
- if (this.databases[dbName]) {
4999
- this.databases[dbName].close();
5000
- delete this.databases[dbName];
5001
- if (this.idleTimers[dbName]) {
5002
- clearTimeout(this.idleTimers[dbName]);
5003
- delete this.idleTimers[dbName];
4912
+ return uniqueKey;
4913
+ };
4914
+ const useServices = () => {
4915
+ const [actors, setActors] = useState([]);
4916
+ const [percentComplete, setPercentComplete] = useState(5);
4917
+ const actorsMap = new Map();
4918
+ useEffect(() => {
4919
+ const globalServiceListener = (event) => {
4920
+ if (event.actorRef &&
4921
+ event.actorRef.logic &&
4922
+ event.actorRef.logic.config) {
4923
+ const uniqueKey = getServiceUniqueKey(event.actorRef);
4924
+ if (!uniqueKey) {
4925
+ return;
4926
+ }
4927
+ event.actorRef.uniqueKey = uniqueKey;
4928
+ actorsMap.set(uniqueKey, event.actorRef);
4929
+ let actorsArray = Array.from(actorsMap.values());
4930
+ actorsArray = orderBy$1(actorsArray, (a) => a.logic.config.id, ['asc']);
4931
+ setActors(produce(actors, (draft) => {
4932
+ return actorsArray;
4933
+ }));
5004
4934
  }
4935
+ };
4936
+ eventEmitter.addListener('inspect.globalService', globalServiceListener);
4937
+ return () => {
4938
+ eventEmitter.removeListener('inspect.globalService', globalServiceListener);
4939
+ };
4940
+ }, []);
4941
+ useEffect(() => {
4942
+ const globalService = actors.find((actor) => getServiceName(actor) === 'global');
4943
+ const internalService = actors.find((actor) => getServiceName(actor) === 'internal');
4944
+ if (!globalService || !internalService) {
4945
+ return;
5005
4946
  }
5006
- }
5007
- }
4947
+ if (getServiceValue(globalService) === 'ready' &&
4948
+ getServiceValue(internalService) === 'ready') {
4949
+ const denominator = actors.length;
4950
+ const finishedActors = actors.filter((actor) => {
4951
+ const value = getServiceValue(actor);
4952
+ return finalStrings.includes(value);
4953
+ });
4954
+ const numerator = finishedActors.length;
4955
+ const percentComplete = (numerator / denominator) * 100;
4956
+ setPercentComplete(percentComplete);
4957
+ }
4958
+ }, [actors]);
4959
+ return {
4960
+ services: actors,
4961
+ percentComplete,
4962
+ };
4963
+ };
4964
+ const useGlobalServiceStatus = () => {
4965
+ const globalService = getGlobalService();
4966
+ const status = useSelector(globalService, (snapshot) => {
4967
+ return snapshot.value;
4968
+ });
4969
+ const internalStatus = useSelector(globalService.getSnapshot().context.internalService, (snapshot) => {
4970
+ if (!snapshot) {
4971
+ return;
4972
+ }
4973
+ return snapshot.value;
4974
+ });
4975
+ useSelector(globalService, (snapshot) => {
4976
+ return snapshot.context.internalService;
4977
+ });
4978
+ return {
4979
+ status,
4980
+ internalStatus,
4981
+ };
4982
+ };
5008
4983
 
5009
- const logger$6 = debug('app:services:internal:helpers');
5010
- /**
5011
- * Recursively create directories if they don't exist.
5012
- * @param {string} dirPath - The directory path to create.
5013
- */
5014
- const createDirectories = (dirPath) => __awaiter(void 0, void 0, void 0, function* () {
5015
- const dirPathExists = yield fs.promises.exists(dirPath);
5016
- if (dirPathExists) {
5017
- return;
5018
- }
5019
- const parentDir = path.dirname(dirPath);
5020
- const parentDirExists = yield fs.promises.exists(parentDir);
5021
- if (!parentDirExists) {
5022
- yield createDirectories(parentDir);
5023
- }
5024
- yield fs.promises.mkdir(dirPath, { recursive: true });
5025
- });
5026
- let busy = false;
5027
- const downloadFile = (url, localFilePath) => __awaiter(void 0, void 0, void 0, function* () {
5028
- try {
5029
- const response = yield fetch(url);
5030
- const fileData = yield response.text().catch((error) => {
5031
- console.error(`Failed to parse text from ${url}:`, error);
5032
- });
5033
- if (!fileData) {
5034
- console.error(`No file data from ${url}`);
4984
+ const logger$8 = debug('app:react:item');
4985
+ const useItem = ({ modelName, seedLocalId, seedUid }) => {
4986
+ const [item, setItem] = useImmer(undefined);
4987
+ const [itemSubscription, setItemSubscription] = useState();
4988
+ const { status, internalStatus } = useGlobalServiceStatus();
4989
+ const isReadingDb = useRef(false);
4990
+ const itemStatus = useSelector(item === null || item === void 0 ? void 0 : item.getService(), (snapshot) => snapshot === null || snapshot === void 0 ? void 0 : snapshot.value);
4991
+ const updateItem = useCallback((newItem) => {
4992
+ setItem(() => newItem);
4993
+ }, []);
4994
+ const readFromDb = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
4995
+ if (isReadingDb.current ||
4996
+ internalStatus !== 'ready' ||
4997
+ (!seedUid && !seedLocalId)) {
5035
4998
  return;
5036
4999
  }
5037
- const localDirPath = path.dirname(localFilePath);
5038
- if (busy) {
5000
+ isReadingDb.current = true;
5001
+ const foundItem = yield Item.find({
5002
+ modelName,
5003
+ seedLocalId,
5004
+ seedUid,
5005
+ });
5006
+ if (!foundItem) {
5007
+ logger$8('[useItem] [getItemFromDb] no item found', modelName, seedLocalId);
5039
5008
  return;
5040
5009
  }
5041
- busy = true;
5042
- yield createDirectories(localDirPath);
5043
- const filename = path.basename(localFilePath);
5044
- const regex = /(\d+)[\w_]+\.(sql|json)$/;
5045
- const match = filename.match(regex);
5046
- let migrationNumber;
5047
- if (match && match.length > 1) {
5048
- migrationNumber = match[1];
5010
+ updateItem(foundItem);
5011
+ isReadingDb.current = false;
5012
+ }), [internalStatus]);
5013
+ useEffect(() => {
5014
+ if (internalStatus === 'ready') {
5015
+ readFromDb();
5049
5016
  }
5050
- if (migrationNumber) {
5051
- const filesInDir = yield fs.promises.readdir(localDirPath);
5052
- for (const file of filesInDir) {
5053
- if (file === filename) {
5054
- continue;
5055
- }
5056
- const innerMatch = file.match(regex);
5057
- let existingFileMigrationNumber;
5058
- if (innerMatch && innerMatch.length > 1) {
5059
- existingFileMigrationNumber = innerMatch[1];
5060
- }
5061
- if (migrationNumber &&
5062
- existingFileMigrationNumber &&
5063
- existingFileMigrationNumber === migrationNumber) {
5064
- yield fs.promises.unlink(path.join(localDirPath, file));
5017
+ }, [internalStatus, status]);
5018
+ useEffect(() => {
5019
+ if (item && !itemSubscription) {
5020
+ const subscription = item.subscribe((_) => __awaiter(void 0, void 0, void 0, function* () {
5021
+ const newItem = yield Item.find({ modelName, seedLocalId, seedUid });
5022
+ if (!newItem) {
5023
+ logger$8('[useItem] [itemSubscription] no item found', modelName, seedLocalId);
5024
+ return;
5065
5025
  }
5066
- }
5067
- }
5068
- // if (filename === '_journal.json') {
5069
- // const exists = await fs.promises.exists(localFilePath)
5070
- // if (exists) {
5071
- // await fs.promises.rm(localFilePath)
5072
- // }
5073
- // await fs.promises.writeFile(localFilePath, fileData)
5074
- // }
5075
- //
5076
- // if (filename !== '_journal.json') {
5077
- // await fs.promises.writeFile(localFilePath, fileData)
5078
- // }
5079
- yield fs.promises.writeFile(localFilePath, fileData);
5080
- }
5081
- catch (error) {
5082
- if (JSON.stringify(error).includes('File exists')) {
5083
- yield fs.promises.readFile(localFilePath, 'utf-8');
5026
+ setItem(() => newItem);
5027
+ }));
5028
+ setItemSubscription(subscription);
5084
5029
  }
5085
- logger$6(`[Error] Failed to download file from ${url}:`, error);
5086
- }
5087
- busy = false;
5088
- });
5089
- const fetchDirectory = (url) => __awaiter(void 0, void 0, void 0, function* () {
5090
- const response = yield fetch(url);
5091
- return response.json();
5092
- });
5093
- const fetchFilesRecursively = (url, localPath, fileList) => __awaiter(void 0, void 0, void 0, function* () {
5094
- try {
5095
- for (const file of fileList) {
5096
- const fileUrl = `${url}/${file}`;
5097
- const fileLocalPath = path.join(localPath, file);
5098
- // logger(`[fetchFilesRecursively] fileUrl: ${fileUrl}`)
5099
- // logger(`[fetchFilesRecursively] fileLocalPath: ${fileLocalPath}`)
5100
- yield downloadFile(fileUrl, fileLocalPath);
5030
+ return () => {
5031
+ itemSubscription === null || itemSubscription === void 0 ? void 0 : itemSubscription.unsubscribe();
5032
+ };
5033
+ }, [item, itemSubscription]);
5034
+ useEffect(() => {
5035
+ const seedId = seedUid || seedLocalId;
5036
+ eventEmitter.addListener(`item.${modelName}.${seedId}.update`, readFromDb);
5037
+ return () => {
5038
+ eventEmitter.removeListener(`item.${modelName}.${seedId}.update`, readFromDb);
5039
+ };
5040
+ }, []);
5041
+ return {
5042
+ item,
5043
+ itemStatus,
5044
+ };
5045
+ };
5046
+ const useItems = ({ modelName, options }) => {
5047
+ const [items, setItems] = useImmer([]);
5048
+ const [isReadingDb, setIsReadingDb] = useState(false);
5049
+ const [isInitialized, setIsInitialized] = useState(false);
5050
+ const { dbsAreReady } = useDbsAreReady();
5051
+ const modelNameRef = useRef(modelName);
5052
+ const readFromDb = useCallback((event) => __awaiter(void 0, void 0, void 0, function* () {
5053
+ if (!event ||
5054
+ !event.modelName ||
5055
+ event.modelName !== modelNameRef.current ||
5056
+ isReadingDb) {
5057
+ return;
5101
5058
  }
5102
- }
5103
- catch (error) {
5104
- console.error(`Failed to fetch files from ${url}:`, error);
5105
- }
5106
- });
5107
- const confirmFilesExist = (filePaths) => __awaiter(void 0, void 0, void 0, function* () {
5108
- let everythingDownloaded = false;
5109
- for (const filePath of filePaths) {
5110
- const fullPath = path.join(BROWSER_FS_TOP_DIR, filePath);
5111
- everythingDownloaded = yield fs.promises.exists(fullPath);
5112
- }
5113
- if (!everythingDownloaded) {
5114
- setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
5115
- yield confirmFilesExist(filePaths);
5116
- }), 500);
5117
- }
5118
- });
5119
- const syncDbFiles = (_a) => __awaiter(void 0, [_a], void 0, function* ({ filePaths, files }) {
5120
- const fileList = yield fetchDirectory(filePaths);
5121
- yield fetchFilesRecursively(files, BROWSER_FS_TOP_DIR, fileList);
5122
- yield confirmFilesExist(fileList);
5123
- logger$6('[syncDbFiles] Files synced!');
5124
- });
5125
-
5126
- const logger$5 = debug('app:files:download');
5127
- const downloadAllFilesRequestHandler = (_a) => __awaiter(void 0, [_a], void 0, function* ({ endpoints, eventId, }) {
5128
- yield syncDbFiles(endpoints);
5129
- eventEmitter.emit('fs.downloadAll.success', { eventId });
5130
- eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
5131
- });
5132
- const downloadAllFilesBinaryRequestHandler = () => __awaiter(void 0, void 0, void 0, function* () {
5133
- const addresses = yield getAddressesFromDb();
5134
- const { filesMetadata } = yield queryClient.fetchQuery({
5135
- queryKey: ['getFilesMetadata', ...addresses],
5136
- queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
5137
- return easClient.request(GET_FILES_METADATA, {
5138
- where: {
5139
- attester: {
5140
- in: addresses,
5141
- },
5142
- schema: {
5143
- is: {
5144
- id: {
5145
- equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
5146
- },
5147
- },
5148
- },
5149
- },
5150
- });
5151
- }),
5152
- });
5153
- if (!(yield fs.promises.exists('/files'))) {
5154
- yield fs.promises.mkdir('/files', { recursive: true });
5155
- }
5156
- if (!(yield fs.promises.exists('/files/html'))) {
5157
- yield fs.promises.mkdir('/files/html', { recursive: true });
5158
- }
5159
- if (!(yield fs.promises.exists('/files/json'))) {
5160
- yield fs.promises.mkdir('/files/json', { recursive: true });
5161
- }
5162
- if (!(yield fs.promises.exists('/files/images'))) {
5163
- yield fs.promises.mkdir('/files/images', { recursive: true });
5164
- }
5165
- const seedDb = getDb(DB_NAME_SEED);
5166
- if (!seedDb) {
5167
- console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
5168
- return [];
5169
- }
5170
- for (const fileMetadata of filesMetadata) {
5171
- const json = JSON.parse(fileMetadata.decodedDataJson);
5172
- const transactionId = json[0].value.value;
5173
- const excludedTransactionsQuery = yield seedDb
5174
- .select()
5175
- .from(appState)
5176
- .where(eq(appState.key, 'excludedTransactions'));
5177
- let excludedTransactions = new Set();
5178
- if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
5179
- const valueString = excludedTransactionsQuery[0].value;
5180
- if (valueString) {
5181
- const excludedTransactionsArray = JSON.parse(valueString);
5182
- excludedTransactions = new Set(excludedTransactionsArray);
5183
- }
5184
- }
5185
- if (excludedTransactions.has(transactionId)) {
5186
- continue;
5187
- }
5188
- const arweave = getArweave();
5189
- if (!arweave) {
5190
- console.warn('[fetchAll/actors] [fetchAllBinaryData] arweave not available');
5191
- return [];
5192
- }
5193
- try {
5194
- const res = yield fetch(`https://${ARWEAVE_HOST}/tx/${transactionId}/status`);
5195
- if (res.status !== 200) {
5196
- logger$5(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
5197
- excludedTransactions.add(transactionId);
5198
- yield writeAppState(seedDb, 'excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
5199
- continue;
5200
- }
5201
- const dataString = yield arweave.transactions
5202
- .getData(transactionId, {
5203
- decode: true,
5204
- string: true,
5205
- })
5206
- .catch((error) => {
5207
- console.error(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`, error);
5208
- });
5209
- if (!dataString) {
5210
- logger$5(`[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not found`);
5211
- }
5212
- let contentType = identifyString(dataString);
5213
- if (contentType !== 'json' &&
5214
- contentType !== 'base64' &&
5215
- contentType !== 'html') {
5216
- const possibleImageType = getImageDataType(dataString);
5217
- if (!possibleImageType) {
5218
- logger$5(`[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not in expected format: ${possibleImageType}`);
5219
- continue;
5220
- }
5221
- contentType = possibleImageType;
5222
- }
5223
- if (contentType === 'url') {
5224
- const url = dataString;
5225
- const response = yield fetch(url);
5226
- if (!response.ok) {
5227
- throw new Error(`Failed to fetch image: ${response.statusText}`);
5228
- }
5229
- // Get the image as a Blob
5230
- const blob = yield response.blob();
5231
- const buffer = yield blob.arrayBuffer();
5232
- const bufferUint8Array = new Uint8Array(buffer);
5233
- // Extract the file extension from the URL
5234
- const extensionMatch = url.match(/\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i);
5235
- if (!extensionMatch) {
5236
- throw new Error('Unable to determine the file extension from the URL.');
5237
- }
5238
- const fileExtension = extensionMatch[0]; // e.g., ".jpg"
5239
- // Set the file name (you can customize this)
5240
- // const fileNameFromUrl = `${transactionId}${fileExtension}`
5241
- yield fs.promises.writeFile(`/files/images/${transactionId}`, bufferUint8Array, {
5242
- encoding: 'binary',
5243
- });
5244
- continue;
5245
- }
5246
- const mimeType = getMimeType(dataString);
5247
- let fileName = transactionId;
5248
- if (contentType === 'base64') {
5249
- if (mimeType) {
5250
- fileName += `.${mimeType}`;
5251
- }
5252
- // Remove the Base64 header if it exists (e.g., "data:image/png;base64,")
5253
- const base64Data = dataString.split(',').pop() || '';
5254
- // Decode the Base64 string to binary
5255
- const binaryString = atob(base64Data);
5256
- const length = binaryString.length;
5257
- const binaryData = new Uint8Array(length);
5258
- for (let i = 0; i < length; i++) {
5259
- binaryData[i] = binaryString.charCodeAt(i);
5260
- }
5261
- yield fs.promises.writeFile(`/files/images/${fileName}`, binaryData, {
5262
- encoding: 'binary',
5263
- });
5264
- // if (dataUint8Array && dataUint8Array instanceof Uint8Array) {
5265
- // await fs.promises.writeFile(
5266
- // `/files/images/${fileName}`,
5267
- // dataUint8Array,
5268
- // )
5269
- // }
5270
- }
5271
- if (contentType === 'html') {
5272
- fileName += '.html';
5273
- yield fs.promises.writeFile(`/files/html/${fileName}`, dataString);
5274
- }
5275
- if (contentType === 'json') {
5276
- fileName += '.json';
5277
- yield fs.promises.writeFile(`/files/json/${fileName}`, dataString);
5278
- }
5279
- }
5280
- catch (error) {
5281
- logger$5(error);
5282
- }
5283
- }
5284
- });
5285
-
5286
- let isInitialized = false;
5287
- const fsInitHandler = (_) => __awaiter(void 0, void 0, void 0, function* () {
5288
- if (isInitialized) {
5289
- eventEmitter.emit('fs.init.response', { success: true });
5290
- return;
5291
- }
5292
- try {
5293
- const handle = yield navigator.storage.getDirectory();
5294
- // await configure({ backend: WebAccess, handle })
5295
- yield configureSingle({
5296
- backend: WebAccess,
5297
- handle,
5298
- });
5299
- isInitialized = true;
5300
- eventEmitter.emit('fs.init.response', { success: true });
5301
- }
5302
- catch (e) {
5303
- if (!isInitialized) {
5304
- console.error('[fs.init] error initializing fs', e);
5305
- eventEmitter.emit('fs.init.response', {
5306
- success: false,
5307
- error: e,
5059
+ setIsReadingDb(true);
5060
+ const allItems = yield Item.all(modelNameRef.current);
5061
+ setItems(() => allItems);
5062
+ setIsReadingDb(false);
5063
+ }), [modelName]);
5064
+ useEffect(() => {
5065
+ if (dbsAreReady && !isInitialized) {
5066
+ const _fetchItems = () => __awaiter(void 0, void 0, void 0, function* () {
5067
+ yield readFromDb({ modelName });
5068
+ setIsInitialized(true);
5308
5069
  });
5070
+ _fetchItems();
5309
5071
  }
5310
- // TODO: We can ignore this for now but should figure out if this is being called excessively
5311
- }
5312
- });
5313
- let areReady = false;
5314
- const setupFsListeners = () => {
5315
- eventEmitter.addListener('fs.downloadAll.request', downloadAllFilesRequestHandler);
5316
- eventEmitter.addListener('fs.downloadAllBinary.request', downloadAllFilesBinaryRequestHandler);
5317
- eventEmitter.addListener('fs.init', fsInitHandler);
5318
- areReady = true;
5319
- };
5320
- const areFsListenersReady = () => {
5321
- return areReady;
5322
- };
5323
- const isFsInitialized = () => {
5324
- return isInitialized;
5072
+ }, [dbsAreReady, isInitialized]);
5073
+ useEffect(() => {
5074
+ eventEmitter.addListener('item.requestAll', readFromDb);
5075
+ return () => {
5076
+ eventEmitter.removeListener('item.requestAll');
5077
+ };
5078
+ }, []);
5079
+ return {
5080
+ items: orderBy(items, [
5081
+ (item) => item.lastVersionPublishedAt ||
5082
+ item.attestationCreatedAt ||
5083
+ item.createdAt,
5084
+ ], ['desc']).slice(0, 10),
5085
+ isReadingDb,
5086
+ isInitialized,
5087
+ };
5325
5088
  };
5326
-
5327
- const logger$4 = debug('app:internal:actors');
5328
- let sqliteWasmClient;
5329
- let manager;
5330
- const validateInput = fromCallback(({ sendBack, input: { event } }) => {
5331
- const { endpoints, addresses } = event;
5332
- if (typeof window === 'undefined') {
5333
- throw new Error('validateInput called from non-browser context');
5334
- }
5335
- if (!endpoints || !endpoints.filePaths || !endpoints.files) {
5336
- throw new Error('validateInput called with invalid endpoints');
5337
- }
5338
- if (!addresses || !addresses.length) {
5339
- throw new Error('validateInput called with invalid addresses');
5340
- }
5341
- const _validateInput = () => __awaiter(void 0, void 0, void 0, function* () {
5342
- sendBack({
5343
- type: INTERNAL_VALIDATING_INPUT_SUCCESS,
5344
- endpoints,
5345
- addresses,
5346
- });
5347
- });
5348
- _validateInput().then(() => {
5349
- return;
5350
- });
5351
- });
5352
- const prepareDb = fromCallback(({ sendBack, input: { event, context } }) => {
5353
- const _prepareDb = () => __awaiter(void 0, void 0, void 0, function* () {
5354
- if (typeof window === 'undefined') {
5355
- return;
5089
+ const useItemIsReady = () => {
5090
+ const [itemListenersReady, setItemListenersReady] = useState(false);
5091
+ const itemEventListenersHandler = useCallback((_) => {
5092
+ setItemListenersReady(true);
5093
+ }, []);
5094
+ useEffect(() => {
5095
+ const areReady = getAreItemEventHandlersReady();
5096
+ if (areReady) {
5097
+ itemEventListenersHandler(true);
5356
5098
  }
5357
- sqliteWasmClient = yield getSqlite();
5358
- });
5359
- const interval = setInterval(() => {
5360
- // TODO: Add a timeout
5361
- // TODO: Add a cancel token to the promise so we can prevent more loops starting while we're checking the successful outcome
5362
- if (sqliteWasmClient) {
5363
- clearInterval(interval);
5364
- manager = new SqliteConnectionManager(sqliteWasmClient);
5365
- sendBack({ type: 'prepareDbSuccess', manager });
5099
+ eventEmitter.addListener('item.events.setupAllItemsEventHandlers', itemEventListenersHandler);
5100
+ return () => {
5101
+ eventEmitter.removeListener('item.events.setupAllItemsEventHandlers');
5102
+ };
5103
+ }, []);
5104
+ return {
5105
+ isReady: itemListenersReady,
5106
+ };
5107
+ };
5108
+ const useCreateItem = (modelName) => {
5109
+ const [isCreatingItem, setIsCreatingItem] = useState(false);
5110
+ const { isReady } = useItemIsReady();
5111
+ const createItem = useCallback((itemData) => __awaiter(void 0, void 0, void 0, function* () {
5112
+ if (!isReady) {
5113
+ console.error(`[useCreateItem] [createItem] called before listeners are ready`, itemData);
5366
5114
  return;
5367
5115
  }
5368
- _prepareDb().then(() => {
5116
+ if (isCreatingItem) {
5117
+ // TODO: should we setup a queue for this?
5118
+ console.error(`[useCreateItem] [createItem] already creating item`, itemData);
5369
5119
  return;
5370
- });
5371
- }, 500);
5372
- return () => {
5373
- if (interval) {
5374
- clearInterval(interval);
5375
5120
  }
5121
+ setIsCreatingItem(true);
5122
+ const { seedLocalId } = yield createNewItem(Object.assign({ modelName }, itemData));
5123
+ yield Item.find({ modelName, seedLocalId });
5124
+ eventEmitter.emit('item.requestAll', { modelName });
5125
+ setIsCreatingItem(false);
5126
+ }), [isCreatingItem, isReady]);
5127
+ return {
5128
+ createItem,
5129
+ isCreatingItem,
5376
5130
  };
5377
- });
5378
- const configureFs = fromCallback(({ sendBack, input: { context } }) => {
5379
- const { endpoints, seedDbService, appDbService, sdkDbService } = context;
5380
- logger$4('[internal/actors] [configureFs] Configuring FS');
5381
- const services = [seedDbService, appDbService, sdkDbService];
5382
- const _configureFs = () => __awaiter(void 0, void 0, void 0, function* () {
5383
- logger$4('[internal/actors] [configureFs] calling _configureFs');
5384
- logger$4('[internal/actors] [configureFs] areFsListenersReady:', areFsListenersReady());
5385
- logger$4('[internal/actors] [configureFs] isFsInitialized:', isFsInitialized());
5386
- yield waitForEvent({
5387
- req: {
5388
- eventLabel: 'fs.downloadAll.request',
5389
- data: { endpoints },
5390
- },
5391
- res: {
5392
- eventLabel: 'fs.downloadAll.success',
5393
- },
5394
- });
5395
- yield Promise.all(services.map((service) => __awaiter(void 0, void 0, void 0, function* () {
5396
- const { dirName } = service.getSnapshot().context;
5397
- const journalPath = `${BROWSER_FS_TOP_DIR}/${dirName}/db/meta/_journal.json`;
5398
- const journalExists = yield fs.promises.exists(journalPath);
5399
- if (journalExists) {
5400
- service.send({ type: DB_WAITING_FOR_FILES_RECEIVED });
5401
- }
5402
- // return new Promise<void>((resolve) => {
5403
- // const interval = setInterval(() => {
5404
- // journalExistsSync = fs.existsSync(journalPath)
5405
- // logger(
5406
- // '[internal/actors] [configureFs] journalExistsSync:',
5407
- // journalExistsSync,
5408
- // )
5409
- // if (journalExistsSync) {
5410
- // service.send({ type: DB_WAITING_FOR_FILES_RECEIVED })
5411
- // clearInterval(interval)
5412
- // resolve()
5413
- // }
5414
- // }, 200)
5415
- // })
5416
- })));
5417
- logger$4('[internal/actors] [configureFs] fs configured!');
5418
- });
5419
- // Some of our dependencies use fs sync functions, which don't work with
5420
- // OPFS. ZenFS creates an async cache of all files so that the sync functions
5421
- // work, but we have to wait for it to be built. Otherwise things like
5422
- // drizzleMigrate will fail since they can't see the migration files yet.
5423
- _configureFs().then(() => {
5424
- sendBack({ type: INTERNAL_CONFIGURING_FS_SUCCESS });
5425
- return;
5426
- });
5427
- return () => { };
5428
- });
5429
- const loadSeedDb = fromCallback(({ sendBack, input: { context } }) => {
5430
- const { seedDbService } = context;
5431
- if (seedDbService.getSnapshot().value === 'ready') {
5432
- sendBack({ type: INTERNAL_LOADING_SEED_DB_SUCCESS });
5433
- return () => { };
5434
- }
5435
- let subscription;
5436
- const _loadSeedDb = () => __awaiter(void 0, void 0, void 0, function* () {
5437
- yield waitFor(seedDbService, (snapshot) => snapshot.value === 'ready');
5438
- subscription = seedDbService.subscribe({
5439
- next: (snapshot) => {
5440
- sendBack({ type: DB_ON_SNAPSHOT, dbName: DB_NAME_SEED, snapshot });
5441
- },
5442
- });
5443
- });
5444
- _loadSeedDb().then(() => {
5445
- sendBack({ type: INTERNAL_LOADING_SEED_DB_SUCCESS });
5131
+ };
5132
+ const useDeleteItem = () => {
5133
+ const [isDeletingItem, setIsDeletingItem] = useState(false);
5134
+ const destroy = useCallback((item) => __awaiter(void 0, void 0, void 0, function* () {
5135
+ if (!item) {
5136
+ return;
5137
+ }
5138
+ setIsDeletingItem(true);
5139
+ const { modelName } = item.getService().getSnapshot().context;
5140
+ yield deleteItem({ seedLocalId: item.seedLocalId });
5141
+ eventEmitter.emit('item.requestAll', { modelName });
5142
+ setIsDeletingItem(false);
5143
+ }), [isDeletingItem]);
5144
+ useEffect(() => { }, []);
5145
+ return {
5146
+ deleteItem: destroy,
5147
+ isDeletingItem,
5148
+ };
5149
+ };
5150
+
5151
+ const logger$7 = debug('app:react:property');
5152
+ const useItemProperty = (propertyName, seedLocalId) => {
5153
+ const [property, setProperty] = useImmer(undefined);
5154
+ const [isReadingFromDb, setIsReadingFromDb] = useState(false);
5155
+ const [isInitialized, setIsInitialized] = useState(false);
5156
+ const dbsAreReady = useDbsAreReady();
5157
+ const value = useSelector(property === null || property === void 0 ? void 0 : property.getService(), (snapshot) => {
5158
+ if (!snapshot || !snapshot.context) {
5159
+ return;
5160
+ }
5161
+ return snapshot.context.renderValue || snapshot.context.propertyValue;
5446
5162
  });
5447
- return () => {
5448
- if (subscription) {
5449
- subscription.unsubscribe();
5163
+ const status = useSelector(property === null || property === void 0 ? void 0 : property.getService(), (snapshot) => snapshot === null || snapshot === void 0 ? void 0 : snapshot.value);
5164
+ useEffect(() => {
5165
+ if (dbsAreReady && property && property.value !== value) {
5166
+ readFromDb();
5167
+ }
5168
+ }, [dbsAreReady, property, value]);
5169
+ const readFromDb = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
5170
+ if (!dbsAreReady && isReadingFromDb) {
5171
+ return;
5450
5172
  }
5173
+ setIsReadingFromDb(true);
5174
+ const foundProperty = yield ItemProperty.find({ propertyName, seedLocalId });
5175
+ setIsReadingFromDb(false);
5176
+ if (!foundProperty) {
5177
+ logger$7(`[useItemPropertyTest] [readFromDb] no property found for Item.${seedLocalId}.${propertyName}`);
5178
+ return;
5179
+ }
5180
+ setProperty(() => foundProperty);
5181
+ setIsInitialized(true);
5182
+ }), [dbsAreReady, isReadingFromDb]);
5183
+ useEffect(() => {
5184
+ readFromDb();
5185
+ }, []);
5186
+ // TODO: How can we force a re-render when the property is updated?
5187
+ // Right now, the value will trigger an update because it's using a selector
5188
+ // and a change is pushed to the hook listener.
5189
+ return {
5190
+ property,
5191
+ isInitialized,
5192
+ isReadingFromDb,
5193
+ value,
5194
+ status,
5451
5195
  };
5452
- });
5453
- const saveConfig = fromCallback(({ sendBack, receive, input: { context } }) => {
5454
- if (typeof window === 'undefined') {
5455
- console.error('seedInitBrowser called from non-browser context');
5456
- sendBack({
5457
- type: 'error',
5458
- error: 'Browser method called from non-browser context',
5459
- });
5460
- }
5461
- const { endpoints, addresses } = context;
5462
- if (!endpoints) {
5463
- throw new Error('saveConfig called with invalid endpoints');
5464
- }
5465
- const _saveConfig = () => __awaiter(void 0, void 0, void 0, function* () {
5466
- // logger('[sdk] [internal/actors] starting _saveConfig')
5467
- const seedDb = getDb(DB_NAME_SEED);
5468
- if (!seedDb) {
5469
- throw new Error('Seed DB not found');
5196
+ };
5197
+ const useItemProperties = (item) => {
5198
+ const [propertyObj, setPropertyObj] = useImmer({});
5199
+ useState(false);
5200
+ const updatePropertyObj = useCallback((event) => {
5201
+ if (!item) {
5202
+ console.error('[XXXXXX] [updatePropertyObj] no item when expected');
5203
+ return;
5470
5204
  }
5471
- const endpointsValueString = JSON.stringify(endpoints);
5472
- const addressesValueString = JSON.stringify(addresses);
5473
- // TODO: Figure out how to define on conflict with multiple rows added
5474
- try {
5475
- // logger('[sdk] [internal/actors] Saving endpoints to db')
5476
- yield seedDb
5477
- .insert(appState)
5478
- .values({
5479
- key: 'endpoints',
5480
- value: endpointsValueString,
5481
- })
5482
- .onConflictDoUpdate({
5483
- target: appState.key,
5484
- set: {
5485
- value: endpointsValueString,
5486
- },
5487
- setWhere: sql `key = 'endpoints'`,
5488
- });
5489
- // logger('[sdk] [internal/actors] Saving addresses to db')
5490
- yield seedDb
5491
- .insert(appState)
5492
- .values({
5493
- key: 'addresses',
5494
- value: addressesValueString,
5495
- })
5496
- .onConflictDoUpdate({
5497
- target: appState.key,
5498
- set: {
5499
- value: addressesValueString,
5500
- },
5501
- setWhere: sql `key = 'addresses'`,
5502
- });
5503
- logger$4('[sdk] [internal/actors] Should be done saving');
5205
+ const { propertyName, propertyValue } = event;
5206
+ if (!propertyName) {
5207
+ return;
5504
5208
  }
5505
- catch (error) {
5506
- console.error('Error saving config:', error);
5209
+ setPropertyObj((draft) => {
5210
+ draft[propertyName] = propertyValue;
5211
+ });
5212
+ }, [item]);
5213
+ useEffect(() => {
5214
+ if (!item) {
5215
+ return;
5507
5216
  }
5508
- });
5509
- _saveConfig().then(() => {
5510
- logger$4('[sdk] [internal/actors] Successfully saved config');
5511
- return sendBack({ type: INTERNAL_SAVING_CONFIG_SUCCESS });
5512
- });
5513
- return () => { };
5514
- });
5515
- const loadAppDb = fromCallback(({ sendBack, input: { context } }) => {
5516
- const { appDbService } = context;
5517
- let subscription;
5518
- const _loadAppDb = () => __awaiter(void 0, void 0, void 0, function* () {
5519
- return new Promise((resolve) => {
5520
- if (appDbService.getSnapshot().value === 'ready') {
5521
- return resolve();
5522
- }
5523
- subscription = appDbService.subscribe({
5524
- next: (snapshot) => {
5217
+ const eventKey = `item.${item.seedLocalId}.property.update`;
5218
+ eventEmitter.addListener(eventKey, updatePropertyObj);
5219
+ return () => {
5220
+ eventEmitter.removeListener(eventKey, updatePropertyObj);
5221
+ };
5222
+ }, [item]);
5223
+ return {
5224
+ properties: propertyObj,
5225
+ };
5226
+ };
5227
+
5228
+ const logger$6 = debug('app:global:actors');
5229
+ const initialize = fromCallback(({ sendBack, input: { event, context } }) => {
5230
+ const { internalService, models, endpoints } = context;
5231
+ const { addresses } = event;
5232
+ let environment = 'browser';
5233
+ if (isNode()) {
5234
+ environment = 'node';
5235
+ }
5236
+ if (isReactNative()) {
5237
+ environment = 'react-native';
5238
+ }
5239
+ let internalSubscription;
5240
+ if (environment === 'browser' && models) {
5241
+ const _initFileSystem = () => __awaiter(void 0, void 0, void 0, function* () {
5242
+ return;
5243
+ // return new Promise((resolve) => {
5244
+ // })
5245
+ });
5246
+ const _initInternal = () => __awaiter(void 0, void 0, void 0, function* () {
5247
+ return new Promise((resolve) => {
5248
+ internalSubscription = internalService.subscribe((snapshot) => {
5249
+ logger$6('[sdk] [internal] snapshot', snapshot);
5525
5250
  if (snapshot.value === 'ready') {
5526
- return resolve();
5251
+ resolve();
5527
5252
  }
5528
- sendBack({ type: DB_ON_SNAPSHOT, dbName: DB_NAME_APP, snapshot });
5529
- },
5253
+ });
5254
+ internalService.send({ type: 'init', endpoints, addresses });
5530
5255
  });
5531
5256
  });
5532
- });
5533
- _loadAppDb().then(() => {
5534
- sendBack({ type: INTERNAL_LOADING_APP_DB_SUCCESS });
5535
- logger$4('[sdk] [internal/actors] Successfully loaded app DB');
5536
- });
5537
- return () => {
5538
- if (subscription) {
5539
- subscription.unsubscribe();
5540
- }
5257
+ _initFileSystem().then(() => {
5258
+ logger$6('[global/actors] File system initialized');
5259
+ });
5260
+ _initInternal().then(() => {
5261
+ logger$6('[global/actors] Internal initialized');
5262
+ sendBack({ type: GLOBAL_INITIALIZING_INTERNAL_SERVICE_READY });
5263
+ internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
5264
+ });
5265
+ // _initEas().then(() => {
5266
+ // logger('EAS initialized')
5267
+ // })
5268
+ }
5269
+ sendBack({ type: GLOBAL_INITIALIZING_SEND_CONFIG, environment });
5270
+ return () => {
5271
+ internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
5541
5272
  };
5542
5273
  });
5543
- const loadSdkDb = fromCallback(({ sendBack, input: { context } }) => {
5544
- const { sdkDbService } = context;
5545
- logger$4('[sdk] [internal/actors] Loading SDK DB');
5546
- let subscription;
5547
- const _loadSdkDb = () => __awaiter(void 0, void 0, void 0, function* () {
5548
- return new Promise((resolve) => {
5549
- if (sdkDbService.getSnapshot().value === 'ready') {
5550
- return resolve();
5274
+ const addModelsToDb = fromCallback(({ sendBack, input: { context } }) => {
5275
+ const { models: models$1 } = context;
5276
+ const _addModelsToDb = () => __awaiter(void 0, void 0, void 0, function* () {
5277
+ var _a;
5278
+ const sdkConfigDb = getSdkDb();
5279
+ if (!models$1) {
5280
+ return;
5281
+ }
5282
+ const { models: SeedModels } = yield import('./seed.schema.config-t5AiIDm_.js');
5283
+ const allModels = Object.assign(Object.assign({}, SeedModels), models$1);
5284
+ let hasModelsInDb = false;
5285
+ const schemaDefsByModelName = new Map();
5286
+ for (const [modelName, _] of Object.entries(allModels)) {
5287
+ logger$6('[helpers/db] [addModelsToInternalDb] starting modelName:', modelName);
5288
+ let foundModel;
5289
+ const foundModelsQuery = yield sdkConfigDb
5290
+ .select()
5291
+ .from(models)
5292
+ .where(eq(models.name, modelName));
5293
+ if (!foundModelsQuery || foundModelsQuery.length === 0) {
5294
+ yield sdkConfigDb.insert(models).values({
5295
+ name: modelName,
5296
+ });
5297
+ logger$6('[global/actors] [addModelsToDb] inserted model:', modelName);
5298
+ const foundModels = yield sdkConfigDb
5299
+ .select({
5300
+ id: models.id,
5301
+ name: models.name,
5302
+ uid: modelUids.uid,
5303
+ })
5304
+ .from(models)
5305
+ .leftJoin(modelUids, eq(models.id, modelUids.modelId))
5306
+ .where(eq(models.name, modelName))
5307
+ .limit(1);
5308
+ foundModel = foundModels[0];
5551
5309
  }
5552
- subscription = sdkDbService.subscribe({
5553
- next: (snapshot) => {
5554
- if (snapshot.value === 'ready') {
5555
- return resolve();
5556
- }
5557
- sendBack({
5558
- type: DB_ON_SNAPSHOT,
5559
- dbName: DB_NAME_SDK_CONFIG,
5560
- snapshot,
5561
- });
5562
- },
5310
+ if (foundModelsQuery && foundModelsQuery.length > 0) {
5311
+ foundModel = foundModelsQuery[0];
5312
+ }
5313
+ if (!foundModel) {
5314
+ hasModelsInDb = false;
5315
+ break;
5316
+ }
5317
+ schemaDefsByModelName.set(modelName, {
5318
+ dbId: foundModel.id,
5319
+ schemaDef: `bytes32 ${toSnakeCase(modelName)}`,
5563
5320
  });
5321
+ }
5322
+ if (!hasModelsInDb) {
5323
+ return false;
5324
+ }
5325
+ const schemaDefs = Array.from(schemaDefsByModelName.values()).map(({ schemaDef }) => schemaDef);
5326
+ const { schemas } = yield queryClient.fetchQuery({
5327
+ queryKey: [`getSchemasVersion`],
5328
+ queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
5329
+ return easClient.request(GET_SCHEMAS, {
5330
+ where: {
5331
+ schema: {
5332
+ in: schemaDefs,
5333
+ },
5334
+ },
5335
+ });
5336
+ }),
5564
5337
  });
5338
+ if (!schemas || schemas.length === 0) {
5339
+ throw new Error(`No schemas found`);
5340
+ }
5341
+ for (const schema of schemas) {
5342
+ const modelId = (_a = Array.from(schemaDefsByModelName.values()).find(({ schemaDef }) => schemaDef === schema.schema)) === null || _a === void 0 ? void 0 : _a.dbId;
5343
+ if (!modelId) {
5344
+ throw new Error(`No modelId found for schema ${schema.schema}`);
5345
+ }
5346
+ yield sdkConfigDb
5347
+ .insert(modelUids)
5348
+ .values({
5349
+ modelId,
5350
+ uid: schema.id,
5351
+ })
5352
+ .onConflictDoNothing();
5353
+ }
5565
5354
  });
5566
- _loadSdkDb().then(() => {
5567
- sendBack({ type: INTERNAL_LOADING_SDK_DB_SUCCESS });
5568
- logger$4('[sdk] [internal/actors] Successfully loaded SDK DB');
5569
- });
5570
- return () => {
5571
- if (subscription) {
5572
- subscription.unsubscribe();
5355
+ _addModelsToDb().then((hasModelsInDb) => {
5356
+ sendBack({ type: GLOBAL_ADDING_MODELS_TO_DB_SUCCESS });
5357
+ for (const [modelName, model] of Object.entries(models$1)) {
5358
+ const service = context[`${modelName}Service`];
5359
+ service.send({ type: 'modelsFound' });
5573
5360
  }
5574
- };
5361
+ eventEmitter.emit('syncDbWithEas');
5362
+ return;
5363
+ });
5364
+ return () => { };
5365
+ });
5366
+ const getSchemaForModel = fromCallback(({ sendBack, input: { context, event } }) => {
5367
+ const { modelName } = event;
5368
+ if (!modelName) {
5369
+ console.warn('No modelName found');
5370
+ return;
5371
+ }
5372
+ const { models } = context;
5373
+ if (!models) {
5374
+ console.warn('No models found');
5375
+ return;
5376
+ }
5377
+ const model = Object.entries(models).find(([modelNameFromConfig]) => modelNameFromConfig === modelName);
5378
+ if (!model) {
5379
+ throw new Error(`Model ${modelName} not found`);
5380
+ }
5381
+ logger$6('[service/actor] [getSchemaForModel] model:', model);
5382
+ sendBack({ type: 'schemaForModel', schema: model.schema });
5383
+ return () => { };
5575
5384
  });
5576
5385
 
5577
- const logger$3 = debug('app:services:db:machine');
5578
- const { CHECKING_STATUS, VALIDATING, WAITING_FOR_FILES, CONNECTING_TO_DB, MIGRATING, } = DbState;
5579
- const dbMachine = setup({
5580
- types: {
5581
- context: {},
5582
- input: {},
5583
- },
5584
- actors: {
5585
- checkStatus,
5586
- validate,
5587
- connectToDb,
5588
- migrate,
5589
- },
5590
- }).createMachine({
5591
- id: MachineIds.DB,
5592
- initial: CHECKING_STATUS,
5593
- context: ({ input }) => input,
5594
- on: {
5595
- [DB_WAITING_FOR_FILES_RECEIVED]: {
5596
- actions: assign({
5597
- hasFiles: ({ event }) => {
5598
- logger$3('[db/machine] DB_WAITING_FOR_FILES_RECEIVED event:', event);
5599
- return true;
5600
- },
5601
- }),
5602
- },
5603
- updateHasFiles: {
5604
- target: `.${CHECKING_STATUS}`,
5605
- actions: assign({
5606
- hasFiles: ({ context, event }) => {
5607
- logger$3('[db/machine] updateHasFiles event:', event);
5608
- logger$3('[db/machine] updateHasFiles context:', context);
5609
- return event.hasFiles;
5610
- },
5611
- }),
5612
- },
5613
- },
5614
- // always: {
5615
- // target: `.${CHECKING_STATUS}`,
5616
- // guard: ({ context, event }) => context.hasFiles && event.type === 'updateHasFiles',
5617
- // },
5618
- states: {
5619
- idle: {
5620
- on: {
5621
- start: CHECKING_STATUS,
5622
- },
5623
- meta: {
5624
- displayText: 'DB starting ...',
5625
- percentComplete: 0,
5626
- },
5627
- },
5628
- [CHECKING_STATUS]: {
5629
- on: {
5630
- [DB_CHECK_STATUS_UPDATE_PATHS]: {
5631
- actions: assign({
5632
- pathToDb: ({ event }) => event.pathToDb,
5633
- pathToDir: ({ event }) => event.pathToDir,
5634
- pathToDbDir: ({ event }) => event.pathToDbDir,
5635
- }),
5636
- },
5637
- [DB_CHECK_STATUS_EXISTS]: CONNECTING_TO_DB,
5638
- },
5639
- invoke: {
5640
- src: 'checkStatus',
5641
- input: ({ context, event }) => ({ context, event }),
5642
- },
5643
- meta: {
5644
- displayText: 'Checking DB status',
5645
- percentComplete: 60,
5646
- },
5647
- },
5648
- [CONNECTING_TO_DB]: {
5649
- on: {
5650
- [DB_CREATING_SUCCESS]: {
5651
- target: VALIDATING,
5652
- actions: assign({
5653
- dbId: ({ event }) => event.dbId,
5654
- }),
5655
- },
5656
- },
5657
- invoke: {
5658
- src: 'connectToDb',
5659
- input: ({ context }) => ({ context }),
5660
- },
5661
- meta: {
5662
- displayText: 'Connecting to local DB',
5663
- percentComplete: 70,
5664
- },
5665
- },
5666
- [VALIDATING]: {
5667
- on: {
5668
- [DB_VALIDATING_SUCCESS]: {
5669
- target: MIGRATING,
5670
- // guard: ({ context }) => context.hasFiles,
5671
- },
5672
- [DB_VALIDATING_WAIT]: {
5673
- target: WAITING_FOR_FILES,
5674
- // guard: ({ context }) => !context.hasFiles,
5675
- },
5676
- },
5677
- invoke: {
5678
- src: 'validate',
5679
- input: ({ context }) => ({ context }),
5680
- },
5681
- meta: {
5682
- displayText: 'Validating DB',
5683
- percentComplete: 80,
5684
- },
5685
- },
5686
- // Here we're waiting for migration and schema files to be downloaded
5687
- [WAITING_FOR_FILES]: {
5688
- on: {
5689
- [DB_WAITING_FOR_FILES_RECEIVED]: {
5690
- target: MIGRATING,
5691
- actions: assign({
5692
- hasFiles: true,
5693
- }),
5694
- },
5695
- [DB_MIGRATING_SUCCESS]: 'ready',
5696
- },
5697
- entry: ({ context }) => {
5698
- if (context.hasFiles) {
5699
- emit({ type: DB_WAITING_FOR_FILES_RECEIVED });
5386
+ class SqliteConnectionManager {
5387
+ constructor(sqliteModule, idleTimeout = 300000) {
5388
+ // Default idle timeout: 5 minutes
5389
+ this.sqliteModule = sqliteModule;
5390
+ this.idleTimeout = idleTimeout;
5391
+ this.databases = {};
5392
+ this.idleTimers = {};
5393
+ }
5394
+ resetIdleTimer(dbName) {
5395
+ if (this.idleTimers[dbName]) {
5396
+ clearTimeout(this.idleTimers[dbName]);
5397
+ }
5398
+ this.idleTimers[dbName] = setTimeout(() => {
5399
+ this.closeConnection(dbName);
5400
+ }, this.idleTimeout);
5401
+ }
5402
+ getConnection(dbName) {
5403
+ return __awaiter(this, void 0, void 0, function* () {
5404
+ if (this.databases[dbName]) {
5405
+ this.resetIdleTimer(dbName);
5406
+ return this.databases[dbName];
5407
+ }
5408
+ const db = new this.sqliteModule();
5409
+ yield db.open(dbName);
5410
+ this.databases[dbName] = db;
5411
+ this.resetIdleTimer(dbName);
5412
+ return db;
5413
+ });
5414
+ }
5415
+ execute(dbName_1, sql_1) {
5416
+ return __awaiter(this, arguments, void 0, function* (dbName, sql, params = []) {
5417
+ const db = yield this.getConnection(dbName);
5418
+ const result = db.exec(sql, params);
5419
+ this.resetIdleTimer(dbName);
5420
+ return result;
5421
+ });
5422
+ }
5423
+ closeConnection(dbName) {
5424
+ if (this.databases[dbName]) {
5425
+ this.databases[dbName].close();
5426
+ delete this.databases[dbName];
5427
+ if (this.idleTimers[dbName]) {
5428
+ clearTimeout(this.idleTimers[dbName]);
5429
+ delete this.idleTimers[dbName];
5430
+ }
5431
+ }
5432
+ }
5433
+ }
5434
+
5435
+ const logger$5 = debug('app:services:internal:helpers');
5436
+ /**
5437
+ * Recursively create directories if they don't exist.
5438
+ * @param {string} dirPath - The directory path to create.
5439
+ */
5440
+ const createDirectories = (dirPath) => __awaiter(void 0, void 0, void 0, function* () {
5441
+ const dirPathExists = yield fs.promises.exists(dirPath);
5442
+ if (dirPathExists) {
5443
+ return;
5444
+ }
5445
+ const parentDir = path.dirname(dirPath);
5446
+ const parentDirExists = yield fs.promises.exists(parentDir);
5447
+ if (!parentDirExists) {
5448
+ yield createDirectories(parentDir);
5449
+ }
5450
+ yield fs.promises.mkdir(dirPath, { recursive: true });
5451
+ });
5452
+ let busy = false;
5453
+ const downloadFile = (url, localFilePath) => __awaiter(void 0, void 0, void 0, function* () {
5454
+ try {
5455
+ const response = yield fetch(url);
5456
+ const fileData = yield response.text().catch((error) => {
5457
+ console.error(`Failed to parse text from ${url}:`, error);
5458
+ });
5459
+ if (!fileData) {
5460
+ console.error(`No file data from ${url}`);
5461
+ return;
5462
+ }
5463
+ const localDirPath = path.dirname(localFilePath);
5464
+ if (busy) {
5465
+ return;
5466
+ }
5467
+ busy = true;
5468
+ yield createDirectories(localDirPath);
5469
+ const filename = path.basename(localFilePath);
5470
+ const regex = /(\d+)[\w_]+\.(sql|json)$/;
5471
+ const match = filename.match(regex);
5472
+ let migrationNumber;
5473
+ if (match && match.length > 1) {
5474
+ migrationNumber = match[1];
5475
+ }
5476
+ if (migrationNumber) {
5477
+ const filesInDir = yield fs.promises.readdir(localDirPath);
5478
+ for (const file of filesInDir) {
5479
+ if (file === filename) {
5480
+ continue;
5700
5481
  }
5701
- },
5702
- },
5703
- [MIGRATING]: {
5704
- on: {
5705
- [DB_MIGRATING_WAIT]: WAITING_FOR_FILES,
5706
- [DB_MIGRATING_SUCCESS]: {
5707
- target: 'ready',
5708
- },
5709
- },
5710
- invoke: {
5711
- src: 'migrate',
5712
- input: ({ context }) => ({ context }),
5713
- },
5714
- meta: {
5715
- displayText: 'Migrating DB',
5716
- percentComplete: 90,
5717
- },
5718
- },
5719
- ready: {
5720
- target: 'idle',
5721
- meta: {
5722
- displayText: 'Wrapping up the db ...',
5723
- percentComplete: 100,
5724
- },
5725
- },
5726
- },
5482
+ const innerMatch = file.match(regex);
5483
+ let existingFileMigrationNumber;
5484
+ if (innerMatch && innerMatch.length > 1) {
5485
+ existingFileMigrationNumber = innerMatch[1];
5486
+ }
5487
+ if (migrationNumber &&
5488
+ existingFileMigrationNumber &&
5489
+ existingFileMigrationNumber === migrationNumber) {
5490
+ yield fs.promises.unlink(path.join(localDirPath, file));
5491
+ }
5492
+ }
5493
+ }
5494
+ // if (filename === '_journal.json') {
5495
+ // const exists = await fs.promises.exists(localFilePath)
5496
+ // if (exists) {
5497
+ // await fs.promises.rm(localFilePath)
5498
+ // }
5499
+ // await fs.promises.writeFile(localFilePath, fileData)
5500
+ // }
5501
+ //
5502
+ // if (filename !== '_journal.json') {
5503
+ // await fs.promises.writeFile(localFilePath, fileData)
5504
+ // }
5505
+ yield fs.promises.writeFile(localFilePath, fileData);
5506
+ }
5507
+ catch (error) {
5508
+ if (JSON.stringify(error).includes('File exists')) {
5509
+ yield fs.promises.readFile(localFilePath, 'utf-8');
5510
+ }
5511
+ logger$5(`[Error] Failed to download file from ${url}:`, error);
5512
+ }
5513
+ busy = false;
5514
+ });
5515
+ const fetchDirectory = (url) => __awaiter(void 0, void 0, void 0, function* () {
5516
+ const response = yield fetch(url);
5517
+ return response.json();
5518
+ });
5519
+ const fetchFilesRecursively = (url, localPath, fileList) => __awaiter(void 0, void 0, void 0, function* () {
5520
+ try {
5521
+ for (const file of fileList) {
5522
+ const fileUrl = `${url}/${file}`;
5523
+ const fileLocalPath = path.join(localPath, file);
5524
+ // logger(`[fetchFilesRecursively] fileUrl: ${fileUrl}`)
5525
+ // logger(`[fetchFilesRecursively] fileLocalPath: ${fileLocalPath}`)
5526
+ yield downloadFile(fileUrl, fileLocalPath);
5527
+ }
5528
+ }
5529
+ catch (error) {
5530
+ console.error(`Failed to fetch files from ${url}:`, error);
5531
+ }
5532
+ });
5533
+ const confirmFilesExist = (filePaths) => __awaiter(void 0, void 0, void 0, function* () {
5534
+ let everythingDownloaded = false;
5535
+ for (const filePath of filePaths) {
5536
+ const fullPath = path.join(BROWSER_FS_TOP_DIR, filePath);
5537
+ everythingDownloaded = yield fs.promises.exists(fullPath);
5538
+ }
5539
+ if (!everythingDownloaded) {
5540
+ setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
5541
+ yield confirmFilesExist(filePaths);
5542
+ }), 500);
5543
+ }
5544
+ });
5545
+ const syncDbFiles = (_a) => __awaiter(void 0, [_a], void 0, function* ({ filePaths, files }) {
5546
+ const fileList = yield fetchDirectory(filePaths);
5547
+ yield fetchFilesRecursively(files, BROWSER_FS_TOP_DIR, fileList);
5548
+ yield confirmFilesExist(fileList);
5549
+ logger$5('[syncDbFiles] Files synced!');
5727
5550
  });
5728
5551
 
5729
- const logger$2 = debug('app:services:internal:machine');
5730
- createBrowserInspector({
5731
- autoStart: false,
5552
+ const logger$4 = debug('app:files:download');
5553
+ const downloadAllFilesRequestHandler = (_a) => __awaiter(void 0, [_a], void 0, function* ({ endpoints, eventId, }) {
5554
+ yield syncDbFiles(endpoints);
5555
+ eventEmitter.emit('fs.downloadAll.success', { eventId });
5556
+ eventEmitter.emit('fs.downloadAllBinary.request', { endpoints });
5732
5557
  });
5733
- const { IDLE, VALIDATING_INPUT, SAVING_CONFIG, CONFIGURING_FS, LOADING_DBS, LOADING_SEED_DB, LOADING_APP_DB, LOADING_SDK_DB, } = InternalState;
5734
- // Create the state machine
5735
- const internalMachine = setup({
5736
- types: {
5737
- context: {},
5738
- input: {},
5739
- },
5740
- actors: {
5741
- prepareDb,
5742
- validateInput,
5743
- configureFs,
5744
- loadSeedDb,
5745
- saveConfig,
5746
- loadAppDb,
5747
- loadSdkDb,
5748
- },
5749
- }).createMachine({
5750
- id: MachineIds.INTERNAL,
5751
- initial: IDLE,
5752
- context: ({ input }) => {
5753
- return Object.assign(Object.assign({}, input), { error: undefined, hasFiles: false });
5754
- },
5755
- states: {
5756
- [IDLE]: {
5757
- on: {
5758
- reValidate: VALIDATING_INPUT,
5759
- init: {
5760
- target: VALIDATING_INPUT,
5761
- actions: [
5762
- assign({
5763
- seedDbService: ({ spawn }) => spawn(dbMachine, {
5764
- input: {
5765
- dbName: DB_NAME_SEED,
5766
- dirName: DB_DIR_NAME_SEED,
5767
- },
5768
- }),
5769
- }),
5770
- assign({
5771
- appDbService: ({ spawn }) => spawn(dbMachine, {
5772
- input: {
5773
- dbName: DB_NAME_APP,
5774
- dirName: DB_DIR_NAME_APP,
5775
- },
5776
- }),
5777
- }),
5778
- assign({
5779
- sdkDbService: ({ spawn }) => spawn(dbMachine, {
5780
- input: {
5781
- dbName: DB_NAME_SDK_CONFIG,
5782
- dirName: DB_DIR_NAME_SDK,
5783
- },
5784
- }),
5785
- }),
5786
- ],
5787
- },
5788
- },
5789
- meta: {
5790
- displayText: 'Waiting for something to happen ...',
5791
- percentComplete: 0,
5792
- },
5793
- },
5794
- [VALIDATING_INPUT]: {
5795
- on: {
5796
- [INTERNAL_VALIDATING_INPUT_SUCCESS]: {
5797
- target: 'preparingDb',
5798
- actions: assign({
5799
- endpoints: ({ event }) => event.endpoints,
5800
- addresses: ({ event }) => event.addresses,
5801
- }),
5802
- },
5803
- },
5804
- invoke: {
5805
- src: 'validateInput',
5806
- input: ({ context, event }) => ({ context, event }),
5807
- },
5808
- meta: {
5809
- displayText: 'Validating input',
5810
- percentComplete: 20,
5811
- },
5812
- tags: ['loading'],
5813
- },
5814
- preparingDb: {
5815
- on: {
5816
- prepareDbSuccess: {
5817
- target: CONFIGURING_FS,
5818
- },
5819
- },
5820
- invoke: {
5821
- src: 'prepareDb',
5822
- input: ({ context, event }) => ({ context, event }),
5823
- },
5824
- },
5825
- [CONFIGURING_FS]: {
5826
- on: {
5827
- [INTERNAL_CONFIGURING_FS_SUCCESS]: {
5828
- target: LOADING_SEED_DB,
5829
- actions: assign({ hasFiles: true }),
5830
- },
5831
- },
5832
- invoke: {
5833
- src: 'configureFs',
5834
- input: ({ context, event }) => ({ context, event }),
5835
- },
5836
- meta: {
5837
- displayText: 'Downloading app files',
5838
- percentComplete: 30,
5839
- },
5840
- tags: ['loading'],
5841
- },
5842
- // We run this before the other DBs because it holds the config we need to
5843
- // rebuild. If we get interrupted after this then we don't have to start
5844
- // from scratch.
5845
- [LOADING_SEED_DB]: {
5846
- on: {
5847
- [INTERNAL_LOADING_SEED_DB_SUCCESS]: SAVING_CONFIG,
5848
- // [DB_ON_SNAPSHOT]: {
5849
- // actions: emit(({ event: { snapshot } }) => {
5850
- // return { type: CHILD_SNAPSHOT, snapshot }
5851
- // }),
5852
- // },
5853
- },
5854
- invoke: {
5855
- src: 'loadSeedDb',
5856
- input: ({ context, event }) => ({ context, event }),
5857
- },
5858
- meta: {
5859
- displayText: 'Loading seed database',
5860
- percentComplete: 50,
5861
- },
5862
- tags: ['loading'],
5863
- },
5864
- // Save developer's config to DB
5865
- [SAVING_CONFIG]: {
5866
- on: {
5867
- [INTERNAL_SAVING_CONFIG_SUCCESS]: LOADING_DBS,
5868
- },
5869
- invoke: {
5870
- src: 'saveConfig',
5871
- input: ({ context, event }) => ({ context, event }),
5872
- },
5873
- meta: {
5874
- displayText: 'Saving configuration',
5875
- percentComplete: 80,
5876
- },
5877
- tags: ['loading'],
5878
- },
5879
- // The DBs can be loaded in parallel since they are independent of each other
5880
- [LOADING_DBS]: {
5881
- type: 'parallel',
5882
- states: {
5883
- [LOADING_APP_DB]: {
5884
- initial: 'loading',
5885
- states: {
5886
- loading: {
5887
- on: {
5888
- [INTERNAL_LOADING_APP_DB_SUCCESS]: {
5889
- target: 'appDbLoaded',
5890
- actions: () => {
5891
- logger$2('[sdk] [internal/index] App DB loaded!');
5892
- },
5893
- },
5894
- },
5895
- invoke: {
5896
- src: 'loadAppDb',
5897
- input: ({ context, event }) => ({ context, event }),
5898
- },
5899
- },
5900
- appDbLoaded: {
5901
- type: 'final',
5902
- entry: () => {
5903
- logger$2('[sdk] [internal/index] Entered appDbLoaded!');
5904
- },
5905
- },
5558
+ const downloadAllFilesBinaryRequestHandler = () => __awaiter(void 0, void 0, void 0, function* () {
5559
+ const addresses = yield getAddressesFromDb();
5560
+ const { filesMetadata } = yield queryClient.fetchQuery({
5561
+ queryKey: ['getFilesMetadata', ...addresses],
5562
+ queryFn: () => __awaiter(void 0, void 0, void 0, function* () {
5563
+ return easClient.request(GET_FILES_METADATA, {
5564
+ where: {
5565
+ attester: {
5566
+ in: addresses,
5906
5567
  },
5907
- },
5908
- [LOADING_SDK_DB]: {
5909
- initial: 'loading',
5910
- states: {
5911
- loading: {
5912
- on: {
5913
- [INTERNAL_LOADING_SDK_DB_SUCCESS]: {
5914
- target: 'sdkConfigDbLoaded',
5915
- actions: () => {
5916
- logger$2('[sdk] [internal/index] SDK Config DB loaded!');
5917
- },
5918
- },
5919
- },
5920
- invoke: {
5921
- src: 'loadSdkDb',
5922
- input: ({ context, event }) => ({ context, event }),
5923
- },
5924
- },
5925
- sdkConfigDbLoaded: {
5926
- type: 'final',
5927
- entry: () => {
5928
- logger$2('[sdk] [internal/index] Entered sdkConfigDbLoaded!');
5568
+ schema: {
5569
+ is: {
5570
+ id: {
5571
+ equals: '0x55fdefb36fcbbaebeb7d6b41dc3a1a9666e4e42154267c889de064faa7ede517',
5929
5572
  },
5930
5573
  },
5931
5574
  },
5932
5575
  },
5933
- },
5934
- onDone: {
5935
- target: 'ready',
5936
- actions: () => {
5937
- logger$2('[sdk] [internal/index] All DBs loaded! Should be headed to ready');
5938
- eventEmitter.emit('allDbsLoaded');
5939
- },
5940
- },
5941
- meta: {
5942
- displayText: 'Loading databases',
5943
- percentComplete: 90,
5944
- },
5945
- tags: ['loading'],
5946
- },
5947
- ready: {
5948
- entry: () => {
5949
- logger$2('[sdk] [internal/index] Ready!');
5950
- },
5951
- meta: {
5952
- displayText: "Crossing the t's ...",
5953
- percentComplete: 90,
5954
- },
5955
- },
5956
- error: {
5957
- on: {
5958
- retry: {
5959
- target: CONFIGURING_FS,
5960
- actions: assign({ error: undefined }),
5961
- },
5962
- },
5963
- entry: () => {
5964
- logger$2('[sdk] [internal/index] Error!');
5965
- },
5966
- meta: {
5967
- displayText: 'Whoops! Something went wrong.',
5968
- percentComplete: null,
5969
- },
5970
- tags: ['error'],
5971
- },
5972
- },
5973
- });
5974
-
5975
- const { UNINITIALIZED, INITIALIZING, INITIALIZED, GETTING_SEED_CLASS, GETTING_SCHEMA_FOR_MODEL, ADDING_MODELS_TO_DB, } = GlobalState;
5976
- createBrowserInspector({
5977
- autoStart: false,
5978
- });
5979
- const globalMachine = setup({
5980
- types: {
5981
- context: {},
5982
- input: {},
5983
- },
5984
- actors: {
5985
- initialize,
5986
- addModelsToDb,
5987
- getSchemaForModel,
5988
- },
5989
- }).createMachine({
5990
- id: MachineIds.GLOBAL,
5991
- initial: UNINITIALIZED,
5992
- context: ({ input }) => input,
5993
- states: {
5994
- [UNINITIALIZED]: {
5995
- on: {
5996
- init: {
5997
- target: INITIALIZING,
5998
- guard: ({ context }) => {
5999
- return typeof window !== 'undefined';
6000
- },
6001
- actions: [
6002
- assign({
6003
- isInitialized: false,
6004
- addedModelRecordsToDb: false,
6005
- models: ({ event }) => event.models,
6006
- endpoints: ({ event }) => event.endpoints,
6007
- internalService: ({ spawn, context }) => {
6008
- return spawn(internalMachine, {
6009
- systemId: MachineIds.INTERNAL,
6010
- input: {
6011
- endpoints: context.endpoints,
6012
- },
6013
- });
6014
- },
6015
- // fileSystemService: ({ spawn, event }) => {
6016
- // return spawn(fileSystemMachine, {
6017
- // systemId: MachineIds.FILE_SYSTEM,
6018
- // input: {
6019
- // addresses: event.addresses,
6020
- // },
6021
- // })
6022
- // },
6023
- }),
6024
- assign(({ event, spawn }) => {
6025
- const allItemsServices = {};
6026
- for (const [modelName, ModelClass] of Object.entries(event.models)) {
6027
- const service = spawn(itemMachineAll, {
6028
- systemId: modelName,
6029
- input: {
6030
- modelName,
6031
- ModelClass,
6032
- modelSchema: ModelClass.schema,
6033
- items: [],
6034
- },
6035
- });
6036
- allItemsServices[`${modelName}Service`] = service;
6037
- }
6038
- return allItemsServices;
6039
- }),
6040
- ],
6041
- },
6042
- },
6043
- meta: {
6044
- displayText: 'Booting up',
6045
- percentComplete: 5,
6046
- },
6047
- tags: ['loading'],
6048
- },
6049
- [INITIALIZING]: {
6050
- on: {
6051
- [GLOBAL_INITIALIZING_SEND_CONFIG]: {
6052
- actions: assign({
6053
- endpoints: ({ event }) => event.endpoints,
6054
- environment: ({ event }) => event.environment,
6055
- addresses: ({ event }) => event.addresses,
6056
- isInitialized: true,
6057
- }),
6058
- },
6059
- [GLOBAL_INITIALIZING_INTERNAL_SERVICE_READY]: ADDING_MODELS_TO_DB,
6060
- },
6061
- invoke: {
6062
- src: 'initialize',
6063
- input: ({ event, context }) => ({ event, context }),
6064
- meta: {
6065
- displayText: 'Initializing Seed SDK',
6066
- percentComplete: 10,
6067
- },
6068
- tags: ['loading'],
6069
- },
6070
- },
6071
- [ADDING_MODELS_TO_DB]: {
6072
- on: {
6073
- [GLOBAL_ADDING_MODELS_TO_DB_SUCCESS]: {
6074
- target: INITIALIZED,
6075
- actions: assign({
6076
- addedModelRecordsToDb: true,
6077
- }),
6078
- },
6079
- },
6080
- invoke: {
6081
- src: 'addModelsToDb',
6082
- input: ({ context }) => ({ context }),
6083
- meta: {
6084
- displayText: 'Adding models to database',
6085
- },
6086
- tags: ['loading'],
6087
- },
6088
- },
6089
- [INITIALIZED]: {
6090
- type: 'parallel',
6091
- on: {
6092
- getSeedClass: `.${GETTING_SEED_CLASS}`,
6093
- getSchemaForModel: `.${GETTING_SCHEMA_FOR_MODEL}`,
6094
- },
6095
- meta: {
6096
- displayText: 'Global service ready',
6097
- percentComplete: 40,
6098
- },
6099
- tags: ['loading'],
6100
- states: {
6101
- [GETTING_SEED_CLASS]: {
6102
- entry: [
6103
- (_a) => __awaiter(void 0, [_a], void 0, function* ({ context }) {
6104
- let SeedClass;
6105
- if (context.environment === 'node') {
6106
- const { SeedNode } = yield import('./seed-DM5koJUz.js');
6107
- SeedClass = SeedNode;
6108
- }
6109
- else {
6110
- const { SeedBrowser } = yield import('./seed-DHOFK9DF.js');
6111
- SeedClass = SeedBrowser;
6112
- }
6113
- return SeedClass;
6114
- }),
6115
- ],
6116
- meta: {
6117
- displayText: 'Getting SeedClass',
6118
- },
6119
- tags: ['loading'],
6120
- },
6121
- [GETTING_SCHEMA_FOR_MODEL]: {
6122
- invoke: {
6123
- src: 'getSchemaForModel',
6124
- input: ({ event, context }) => ({ event, context }),
6125
- meta: {
6126
- displayText: 'Getting schema for model',
6127
- },
6128
- tags: ['loading'],
6129
- },
6130
- },
6131
- },
6132
- },
6133
- },
6134
- // on: {
6135
- // '*': {
6136
- // actions: emit(({ event }) => {
6137
- // return event
6138
- // }),
6139
- // },
6140
- // },
6141
- });
6142
- const globalService = createActor(globalMachine, {
6143
- input: {},
6144
- // inspect,
6145
- inspect: (inspEvent) => {
6146
- eventEmitter.emit('inspect.globalService', inspEvent);
6147
- // console.log('[sdk] [service/index] inspEvent', inspEvent)
6148
- // eventEmitter.emit('globalService', inspEvent)
6149
- // let eventType: string = inspEvent.type
6150
- // if (inspEvent.event && inspEvent.event.type) {
6151
- // eventType = inspEvent.event.type
6152
- // }
6153
- //
6154
- // if (typeof eventType === 'object') {
6155
- // eventType = JSON.stringify(eventType)
6156
- // }
6157
- //
6158
- // let srcId = inspEvent.actorRef.id
6159
- //
6160
- // if (!srcId.includes('seedSdk')) {
6161
- // srcId = inspEvent.actorRef.logic.config.id
6162
- // }
6163
- //
6164
- // if (inspEvent.type === '@xstate.snapshot') {
6165
- // if (
6166
- // inspEvent.event.type === CHILD_SNAPSHOT &&
6167
- // inspEvent.snapshot &&
6168
- // inspEvent.snapshot.machine.id === MachineIds.GLOBAL
6169
- // ) {
6170
- // return
6171
- // }
6172
- // if (inspEvent.snapshot && inspEvent.snapshot.value) {
6173
- // if (typeof window !== 'undefined') {
6174
- // eventEmitter.emit('globalService', {
6175
- // type: eventType,
6176
- // src: srcId,
6177
- // snapshot: inspEvent.snapshot,
6178
- // })
6179
- // }
6180
- // }
6181
- // } else {
6182
- // if (typeof window !== 'undefined') {
6183
- // let snapshot
6184
- //
6185
- // try {
6186
- // snapshot = inspEvent.actorRef.getSnapshot()
6187
- // } catch (e) {
6188
- // // This fails if the actor hasn't initialized yet, but that's OK I think
6189
- // // console.log('[sdk] [service/index] ERROR', e)
6190
- // }
6191
- //
6192
- // eventEmitter.emit('globalService', {
6193
- // type: eventType,
6194
- // src: srcId,
6195
- // snapshot,
6196
- // })
6197
- // }
6198
- // }
6199
- },
6200
- });
6201
- globalService.start();
6202
- const getGlobalService = () => globalService;
6203
-
6204
- const logger$1 = debug('app:react:index');
6205
- const useItemProperty = (propertyName, seedLocalId) => {
6206
- const [property, setProperty] = useImmer(undefined);
6207
- const [isReadingFromDb, setIsReadingFromDb] = useState(false);
6208
- const [isInitialized, setIsInitialized] = useState(false);
6209
- const dbsAreReady = useDbsAreReady();
6210
- const value = useSelector(property === null || property === void 0 ? void 0 : property.getService(), (snapshot) => {
6211
- if (!snapshot || !snapshot.context) {
6212
- return;
6213
- }
6214
- return snapshot.context.renderValue || snapshot.context.propertyValue;
5576
+ });
5577
+ }),
6215
5578
  });
6216
- const status = useSelector(property === null || property === void 0 ? void 0 : property.getService(), (snapshot) => snapshot === null || snapshot === void 0 ? void 0 : snapshot.value);
6217
- useEffect(() => {
6218
- if (dbsAreReady && property && property.value !== value) {
6219
- readFromDb();
6220
- }
6221
- }, [dbsAreReady, property, value]);
6222
- const readFromDb = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
6223
- if (!dbsAreReady && isReadingFromDb) {
6224
- return;
6225
- }
6226
- setIsReadingFromDb(true);
6227
- const foundProperty = yield ItemProperty.find({ propertyName, seedLocalId });
6228
- setIsReadingFromDb(false);
6229
- if (!foundProperty) {
6230
- logger$1(`[useItemPropertyTest] [readFromDb] no property found for Item.${seedLocalId}.${propertyName}`);
6231
- return;
5579
+ if (!(yield fs.promises.exists('/files'))) {
5580
+ yield fs.promises.mkdir('/files', { recursive: true });
5581
+ }
5582
+ if (!(yield fs.promises.exists('/files/html'))) {
5583
+ yield fs.promises.mkdir('/files/html', { recursive: true });
5584
+ }
5585
+ if (!(yield fs.promises.exists('/files/json'))) {
5586
+ yield fs.promises.mkdir('/files/json', { recursive: true });
5587
+ }
5588
+ if (!(yield fs.promises.exists('/files/images'))) {
5589
+ yield fs.promises.mkdir('/files/images', { recursive: true });
5590
+ }
5591
+ const seedDb = getDb(DB_NAME_SEED);
5592
+ if (!seedDb) {
5593
+ console.warn('[fetchAll/actors] [fetchAllBinaryData] seedDb not available');
5594
+ return [];
5595
+ }
5596
+ for (const fileMetadata of filesMetadata) {
5597
+ const json = JSON.parse(fileMetadata.decodedDataJson);
5598
+ const transactionId = json[0].value.value;
5599
+ const excludedTransactionsQuery = yield seedDb
5600
+ .select()
5601
+ .from(appState)
5602
+ .where(eq(appState.key, 'excludedTransactions'));
5603
+ let excludedTransactions = new Set();
5604
+ if (excludedTransactionsQuery && excludedTransactionsQuery.length === 1) {
5605
+ const valueString = excludedTransactionsQuery[0].value;
5606
+ if (valueString) {
5607
+ const excludedTransactionsArray = JSON.parse(valueString);
5608
+ excludedTransactions = new Set(excludedTransactionsArray);
5609
+ }
6232
5610
  }
6233
- setProperty(() => foundProperty);
6234
- setIsInitialized(true);
6235
- }), [dbsAreReady, isReadingFromDb]);
6236
- useEffect(() => {
6237
- readFromDb();
6238
- }, []);
6239
- // TODO: How can we force a re-render when the property is updated?
6240
- // Right now, the value will trigger an update because it's using a selector
6241
- // and a change is pushed to the hook listener.
6242
- return {
6243
- property,
6244
- isInitialized,
6245
- isReadingFromDb,
6246
- value,
6247
- status,
6248
- };
6249
- };
6250
- const useItem = ({ modelName, seedLocalId, seedUid }) => {
6251
- const [item, setItem] = useImmer(undefined);
6252
- const [itemSubscription, setItemSubscription] = useState();
6253
- const { status, internalStatus } = useGlobalServiceStatus();
6254
- const isReadingDb = useRef(false);
6255
- const itemStatus = useSelector(item === null || item === void 0 ? void 0 : item.getService(), (snapshot) => snapshot === null || snapshot === void 0 ? void 0 : snapshot.value);
6256
- const updateItem = useCallback((newItem) => {
6257
- setItem(() => newItem);
6258
- }, []);
6259
- const readFromDb = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
6260
- if (isReadingDb.current ||
6261
- internalStatus !== 'ready' ||
6262
- (!seedUid && !seedLocalId)) {
6263
- return;
5611
+ if (excludedTransactions.has(transactionId)) {
5612
+ continue;
6264
5613
  }
6265
- isReadingDb.current = true;
6266
- const foundItem = yield Item.find({
6267
- modelName,
6268
- seedLocalId,
6269
- seedUid,
6270
- });
6271
- if (!foundItem) {
6272
- logger$1('[useItem] [getItemFromDb] no item found', modelName, seedLocalId);
6273
- return;
5614
+ const arweave = getArweave();
5615
+ if (!arweave) {
5616
+ console.warn('[fetchAll/actors] [fetchAllBinaryData] arweave not available');
5617
+ return [];
6274
5618
  }
6275
- updateItem(foundItem);
6276
- isReadingDb.current = false;
6277
- }), [internalStatus]);
6278
- useEffect(() => {
6279
- if (internalStatus === 'ready') {
6280
- readFromDb();
6281
- }
6282
- }, [internalStatus, status]);
6283
- useEffect(() => {
6284
- if (item && !itemSubscription) {
6285
- const subscription = item.subscribe((_) => __awaiter(void 0, void 0, void 0, function* () {
6286
- const newItem = yield Item.find({ modelName, seedLocalId, seedUid });
6287
- if (!newItem) {
6288
- logger$1('[useItem] [itemSubscription] no item found', modelName, seedLocalId);
6289
- return;
6290
- }
6291
- setItem(() => newItem);
6292
- }));
6293
- setItemSubscription(subscription);
6294
- }
6295
- return () => {
6296
- itemSubscription === null || itemSubscription === void 0 ? void 0 : itemSubscription.unsubscribe();
6297
- };
6298
- }, [item, itemSubscription]);
6299
- useEffect(() => {
6300
- const seedId = seedUid || seedLocalId;
6301
- eventEmitter.addListener(`item.${modelName}.${seedId}.update`, readFromDb);
6302
- return () => {
6303
- eventEmitter.removeListener(`item.${modelName}.${seedId}.update`, readFromDb);
6304
- };
6305
- }, []);
6306
- return {
6307
- item,
6308
- itemStatus,
6309
- };
6310
- };
6311
- const useItems = ({ modelName, options }) => {
6312
- const [items, setItems] = useImmer([]);
6313
- const [isReadingDb, setIsReadingDb] = useState(false);
6314
- const [isInitialized, setIsInitialized] = useState(false);
6315
- const { dbsAreReady } = useDbsAreReady();
6316
- const modelNameRef = useRef(modelName);
6317
- const readFromDb = useCallback((event) => __awaiter(void 0, void 0, void 0, function* () {
6318
- if (!event ||
6319
- !event.modelName ||
6320
- event.modelName !== modelNameRef.current ||
6321
- isReadingDb) {
6322
- return;
6323
- }
6324
- setIsReadingDb(true);
6325
- const allItems = yield Item.all(modelNameRef.current);
6326
- setItems(() => allItems);
6327
- setIsReadingDb(false);
6328
- }), [modelName]);
6329
- useEffect(() => {
6330
- if (dbsAreReady && !isInitialized) {
6331
- const _fetchItems = () => __awaiter(void 0, void 0, void 0, function* () {
6332
- yield readFromDb({ modelName });
6333
- setIsInitialized(true);
5619
+ try {
5620
+ const res = yield fetch(`https://${ARWEAVE_HOST}/tx/${transactionId}/status`);
5621
+ if (res.status !== 200) {
5622
+ logger$4(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`);
5623
+ excludedTransactions.add(transactionId);
5624
+ yield writeAppState(seedDb, 'excludedTransactions', JSON.stringify(Array.from(excludedTransactions)));
5625
+ continue;
5626
+ }
5627
+ const dataString = yield arweave.transactions
5628
+ .getData(transactionId, {
5629
+ decode: true,
5630
+ string: true,
5631
+ })
5632
+ .catch((error) => {
5633
+ console.error(`[fetchAll/actors] [fetchAllBinaryData] error fetching transaction data for ${transactionId}`, error);
6334
5634
  });
6335
- _fetchItems();
6336
- }
6337
- }, [dbsAreReady, isInitialized]);
6338
- useEffect(() => {
6339
- eventEmitter.addListener('item.requestAll', readFromDb);
6340
- return () => {
6341
- eventEmitter.removeListener('item.requestAll');
6342
- };
6343
- }, []);
6344
- return {
6345
- items: orderBy(items, [
6346
- (item) => item.lastVersionPublishedAt ||
6347
- item.attestationCreatedAt ||
6348
- item.createdAt,
6349
- ], ['desc']).slice(0, 10),
6350
- isReadingDb,
6351
- isInitialized,
6352
- };
6353
- };
6354
- const useDbsAreReady = () => {
6355
- const [dbsAreReady, setDbsAreReady] = useState(false);
6356
- const update = useCallback(() => {
6357
- if (dbsAreReady) {
6358
- return;
6359
- }
6360
- setDbsAreReady(true);
6361
- }, []);
6362
- useEffect(() => {
6363
- let globalSubscription;
6364
- let internalSubscription;
6365
- const _waitForDbs = () => __awaiter(void 0, void 0, void 0, function* () {
6366
- const globalService = getGlobalService();
6367
- const internalService = globalService.getSnapshot().context.internalService;
6368
- if (!internalService) {
6369
- logger$1('[useDbsAreReady] [useEffect] no internalService');
6370
- globalSubscription = globalService.subscribe(({ context }) => {
6371
- if (!internalSubscription && context && context.internalService) {
6372
- globalSubscription === null || globalSubscription === void 0 ? void 0 : globalSubscription.unsubscribe();
6373
- internalSubscription = context.internalService.subscribe((snapshot) => {
6374
- if (snapshot.value === 'ready') {
6375
- update();
6376
- internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
6377
- }
6378
- });
6379
- }
6380
- });
6381
- return;
5635
+ if (!dataString) {
5636
+ logger$4(`[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not found`);
6382
5637
  }
6383
- const currentState = internalService.getSnapshot().value;
6384
- if (currentState === 'ready') {
6385
- update();
6386
- return;
5638
+ let contentType = identifyString(dataString);
5639
+ if (contentType !== 'json' &&
5640
+ contentType !== 'base64' &&
5641
+ contentType !== 'html') {
5642
+ const possibleImageType = getImageDataType(dataString);
5643
+ if (!possibleImageType) {
5644
+ logger$4(`[fetchAll/actors] [fetchAllBinaryData] transaction ${transactionId} data not in expected format: ${possibleImageType}`);
5645
+ continue;
5646
+ }
5647
+ contentType = possibleImageType;
6387
5648
  }
6388
- internalSubscription = internalService.subscribe((snapshot) => {
6389
- if (snapshot.value === 'ready') {
6390
- update();
6391
- internalSubscription === null || internalSubscription === void 0 ? void 0 : internalSubscription.unsubscribe();
5649
+ if (contentType === 'url') {
5650
+ const url = dataString;
5651
+ const response = yield fetch(url);
5652
+ if (!response.ok) {
5653
+ throw new Error(`Failed to fetch image: ${response.statusText}`);
6392
5654
  }
6393
- });
6394
- });
6395
- _waitForDbs();
6396
- return () => {
6397
- if (globalSubscription) {
6398
- globalSubscription.unsubscribe();
5655
+ // Get the image as a Blob
5656
+ const blob = yield response.blob();
5657
+ const buffer = yield blob.arrayBuffer();
5658
+ const bufferUint8Array = new Uint8Array(buffer);
5659
+ // Extract the file extension from the URL
5660
+ const extensionMatch = url.match(/\.(jpg|jpeg|png|gif|bmp|webp|svg)$/i);
5661
+ if (!extensionMatch) {
5662
+ throw new Error('Unable to determine the file extension from the URL.');
5663
+ }
5664
+ const fileExtension = extensionMatch[0]; // e.g., ".jpg"
5665
+ // Set the file name (you can customize this)
5666
+ // const fileNameFromUrl = `${transactionId}${fileExtension}`
5667
+ yield fs.promises.writeFile(`/files/images/${transactionId}`, bufferUint8Array, {
5668
+ encoding: 'binary',
5669
+ });
5670
+ continue;
6399
5671
  }
6400
- if (internalSubscription) {
6401
- internalSubscription.unsubscribe();
5672
+ const mimeType = getMimeType(dataString);
5673
+ let fileName = transactionId;
5674
+ if (contentType === 'base64') {
5675
+ if (mimeType) {
5676
+ fileName += `.${mimeType}`;
5677
+ }
5678
+ // Remove the Base64 header if it exists (e.g., "data:image/png;base64,")
5679
+ const base64Data = dataString.split(',').pop() || '';
5680
+ // Decode the Base64 string to binary
5681
+ const binaryString = atob(base64Data);
5682
+ const length = binaryString.length;
5683
+ const binaryData = new Uint8Array(length);
5684
+ for (let i = 0; i < length; i++) {
5685
+ binaryData[i] = binaryString.charCodeAt(i);
5686
+ }
5687
+ yield fs.promises.writeFile(`/files/images/${fileName}`, binaryData, {
5688
+ encoding: 'binary',
5689
+ });
5690
+ // if (dataUint8Array && dataUint8Array instanceof Uint8Array) {
5691
+ // await fs.promises.writeFile(
5692
+ // `/files/images/${fileName}`,
5693
+ // dataUint8Array,
5694
+ // )
5695
+ // }
5696
+ }
5697
+ if (contentType === 'html') {
5698
+ fileName += '.html';
5699
+ yield fs.promises.writeFile(`/files/html/${fileName}`, dataString);
5700
+ }
5701
+ if (contentType === 'json') {
5702
+ fileName += '.json';
5703
+ yield fs.promises.writeFile(`/files/json/${fileName}`, dataString);
6402
5704
  }
6403
- };
6404
- }, []);
6405
- return {
6406
- dbsAreReady,
6407
- };
6408
- };
6409
- const useItemIsReady = () => {
6410
- const [itemListenersReady, setItemListenersReady] = useState(false);
6411
- const itemEventListenersHandler = useCallback((_) => {
6412
- setItemListenersReady(true);
6413
- }, []);
6414
- useEffect(() => {
6415
- const areReady = getAreItemEventHandlersReady();
6416
- if (areReady) {
6417
- itemEventListenersHandler(true);
6418
- }
6419
- eventEmitter.addListener('item.events.setupAllItemsEventHandlers', itemEventListenersHandler);
6420
- return () => {
6421
- eventEmitter.removeListener('item.events.setupAllItemsEventHandlers');
6422
- };
6423
- }, []);
6424
- return {
6425
- isReady: itemListenersReady,
6426
- };
6427
- };
6428
- const useItemProperties = (item) => {
6429
- const [propertyObj, setPropertyObj] = useImmer({});
6430
- useState(false);
6431
- const updatePropertyObj = useCallback((event) => {
6432
- if (!item) {
6433
- console.error('[XXXXXX] [updatePropertyObj] no item when expected');
6434
- return;
6435
5705
  }
6436
- const { propertyName, propertyValue } = event;
6437
- if (!propertyName) {
6438
- return;
5706
+ catch (error) {
5707
+ logger$4(error);
6439
5708
  }
6440
- setPropertyObj((draft) => {
6441
- draft[propertyName] = propertyValue;
5709
+ }
5710
+ });
5711
+
5712
+ let isInitialized = false;
5713
+ const fsInitHandler = (_) => __awaiter(void 0, void 0, void 0, function* () {
5714
+ if (isInitialized) {
5715
+ eventEmitter.emit('fs.init.response', { success: true });
5716
+ return;
5717
+ }
5718
+ try {
5719
+ const handle = yield navigator.storage.getDirectory();
5720
+ // await configure({ backend: WebAccess, handle })
5721
+ yield configureSingle({
5722
+ backend: WebAccess,
5723
+ handle,
6442
5724
  });
6443
- }, [item]);
6444
- useEffect(() => {
6445
- if (!item) {
6446
- return;
6447
- }
6448
- const eventKey = `item.${item.seedLocalId}.property.update`;
6449
- eventEmitter.addListener(eventKey, updatePropertyObj);
6450
- return () => {
6451
- eventEmitter.removeListener(eventKey, updatePropertyObj);
6452
- };
6453
- }, [item]);
6454
- return {
6455
- properties: propertyObj,
6456
- };
5725
+ isInitialized = true;
5726
+ eventEmitter.emit('fs.init.response', { success: true });
5727
+ }
5728
+ catch (e) {
5729
+ if (!isInitialized) {
5730
+ console.error('[fs.init] error initializing fs', e);
5731
+ eventEmitter.emit('fs.init.response', {
5732
+ success: false,
5733
+ error: e,
5734
+ });
5735
+ }
5736
+ // TODO: We can ignore this for now but should figure out if this is being called excessively
5737
+ }
5738
+ });
5739
+ let areReady = false;
5740
+ const setupFsListeners = () => {
5741
+ eventEmitter.addListener('fs.downloadAll.request', downloadAllFilesRequestHandler);
5742
+ eventEmitter.addListener('fs.downloadAllBinary.request', downloadAllFilesBinaryRequestHandler);
5743
+ eventEmitter.addListener('fs.init', fsInitHandler);
5744
+ areReady = true;
6457
5745
  };
6458
- const useCreateItem = (modelName) => {
6459
- const [isCreatingItem, setIsCreatingItem] = useState(false);
6460
- const { isReady } = useItemIsReady();
6461
- const createItem = useCallback((itemData) => __awaiter(void 0, void 0, void 0, function* () {
6462
- if (!isReady) {
6463
- console.error(`[useCreateItem] [createItem] called before listeners are ready`, itemData);
5746
+ const areFsListenersReady = () => {
5747
+ return areReady;
5748
+ };
5749
+ const isFsInitialized = () => {
5750
+ return isInitialized;
5751
+ };
5752
+
5753
+ const logger$3 = debug('app:internal:actors');
5754
+ let sqliteWasmClient;
5755
+ let manager;
5756
+ const validateInput = fromCallback(({ sendBack, input: { event } }) => {
5757
+ const { endpoints, addresses } = event;
5758
+ if (typeof window === 'undefined') {
5759
+ throw new Error('validateInput called from non-browser context');
5760
+ }
5761
+ if (!endpoints || !endpoints.filePaths || !endpoints.files) {
5762
+ throw new Error('validateInput called with invalid endpoints');
5763
+ }
5764
+ if (!addresses || !addresses.length) {
5765
+ throw new Error('validateInput called with invalid addresses');
5766
+ }
5767
+ const _validateInput = () => __awaiter(void 0, void 0, void 0, function* () {
5768
+ sendBack({
5769
+ type: INTERNAL_VALIDATING_INPUT_SUCCESS,
5770
+ endpoints,
5771
+ addresses,
5772
+ });
5773
+ });
5774
+ _validateInput().then(() => {
5775
+ return;
5776
+ });
5777
+ });
5778
+ const prepareDb = fromCallback(({ sendBack, input: { event, context } }) => {
5779
+ const _prepareDb = () => __awaiter(void 0, void 0, void 0, function* () {
5780
+ if (typeof window === 'undefined') {
6464
5781
  return;
6465
5782
  }
6466
- if (isCreatingItem) {
6467
- // TODO: should we setup a queue for this?
6468
- console.error(`[useCreateItem] [createItem] already creating item`, itemData);
5783
+ sqliteWasmClient = yield getSqlite();
5784
+ });
5785
+ const interval = setInterval(() => {
5786
+ // TODO: Add a timeout
5787
+ // TODO: Add a cancel token to the promise so we can prevent more loops starting while we're checking the successful outcome
5788
+ if (sqliteWasmClient) {
5789
+ clearInterval(interval);
5790
+ manager = new SqliteConnectionManager(sqliteWasmClient);
5791
+ sendBack({ type: 'prepareDbSuccess', manager });
6469
5792
  return;
6470
5793
  }
6471
- setIsCreatingItem(true);
6472
- const { seedLocalId } = yield createNewItem(Object.assign({ modelName }, itemData));
6473
- yield Item.find({ modelName, seedLocalId });
6474
- eventEmitter.emit('item.requestAll', { modelName });
6475
- setIsCreatingItem(false);
6476
- }), [isCreatingItem, isReady]);
6477
- return {
6478
- createItem,
6479
- isCreatingItem,
6480
- };
6481
- };
6482
- const useDeleteItem = () => {
6483
- const [isDeletingItem, setIsDeletingItem] = useState(false);
6484
- const destroy = useCallback((item) => __awaiter(void 0, void 0, void 0, function* () {
6485
- if (!item) {
5794
+ _prepareDb().then(() => {
6486
5795
  return;
5796
+ });
5797
+ }, 500);
5798
+ return () => {
5799
+ if (interval) {
5800
+ clearInterval(interval);
6487
5801
  }
6488
- setIsDeletingItem(true);
6489
- const { modelName } = item.getService().getSnapshot().context;
6490
- yield deleteItem({ seedLocalId: item.seedLocalId });
6491
- eventEmitter.emit('item.requestAll', { modelName });
6492
- setIsDeletingItem(false);
6493
- }), [isDeletingItem]);
6494
- useEffect(() => { }, []);
6495
- return {
6496
- deleteItem: destroy,
6497
- isDeletingItem,
6498
5802
  };
6499
- };
6500
- const useGlobalServiceStatus = () => {
6501
- const globalService = getGlobalService();
6502
- const status = useSelector(globalService, (snapshot) => {
6503
- return snapshot.value;
5803
+ });
5804
+ const configureFs = fromCallback(({ sendBack, input: { context } }) => {
5805
+ const { endpoints, seedDbService, appDbService, sdkDbService } = context;
5806
+ logger$3('[internal/actors] [configureFs] Configuring FS');
5807
+ const services = [seedDbService, appDbService, sdkDbService];
5808
+ const _configureFs = () => __awaiter(void 0, void 0, void 0, function* () {
5809
+ logger$3('[internal/actors] [configureFs] calling _configureFs');
5810
+ logger$3('[internal/actors] [configureFs] areFsListenersReady:', areFsListenersReady());
5811
+ logger$3('[internal/actors] [configureFs] isFsInitialized:', isFsInitialized());
5812
+ yield waitForEvent({
5813
+ req: {
5814
+ eventLabel: 'fs.downloadAll.request',
5815
+ data: { endpoints },
5816
+ },
5817
+ res: {
5818
+ eventLabel: 'fs.downloadAll.success',
5819
+ },
5820
+ });
5821
+ yield Promise.all(services.map((service) => __awaiter(void 0, void 0, void 0, function* () {
5822
+ const { dirName } = service.getSnapshot().context;
5823
+ const journalPath = `${BROWSER_FS_TOP_DIR}/${dirName}/db/meta/_journal.json`;
5824
+ const journalExists = yield fs.promises.exists(journalPath);
5825
+ if (journalExists) {
5826
+ service.send({ type: DB_WAITING_FOR_FILES_RECEIVED });
5827
+ }
5828
+ // return new Promise<void>((resolve) => {
5829
+ // const interval = setInterval(() => {
5830
+ // journalExistsSync = fs.existsSync(journalPath)
5831
+ // logger(
5832
+ // '[internal/actors] [configureFs] journalExistsSync:',
5833
+ // journalExistsSync,
5834
+ // )
5835
+ // if (journalExistsSync) {
5836
+ // service.send({ type: DB_WAITING_FOR_FILES_RECEIVED })
5837
+ // clearInterval(interval)
5838
+ // resolve()
5839
+ // }
5840
+ // }, 200)
5841
+ // })
5842
+ })));
5843
+ logger$3('[internal/actors] [configureFs] fs configured!');
6504
5844
  });
6505
- const internalStatus = useSelector(globalService.getSnapshot().context.internalService, (snapshot) => {
6506
- if (!snapshot) {
6507
- return;
6508
- }
6509
- return snapshot.value;
5845
+ // Some of our dependencies use fs sync functions, which don't work with
5846
+ // OPFS. ZenFS creates an async cache of all files so that the sync functions
5847
+ // work, but we have to wait for it to be built. Otherwise things like
5848
+ // drizzleMigrate will fail since they can't see the migration files yet.
5849
+ _configureFs().then(() => {
5850
+ sendBack({ type: INTERNAL_CONFIGURING_FS_SUCCESS });
5851
+ return;
6510
5852
  });
6511
- useSelector(globalService, (snapshot) => {
6512
- return snapshot.context.internalService;
5853
+ return () => { };
5854
+ });
5855
+ const loadSeedDb = fromCallback(({ sendBack, input: { context } }) => {
5856
+ const { seedDbService } = context;
5857
+ if (seedDbService.getSnapshot().value === 'ready') {
5858
+ sendBack({ type: INTERNAL_LOADING_SEED_DB_SUCCESS });
5859
+ return () => { };
5860
+ }
5861
+ let subscription;
5862
+ const _loadSeedDb = () => __awaiter(void 0, void 0, void 0, function* () {
5863
+ yield waitFor(seedDbService, (snapshot) => snapshot.value === 'ready');
5864
+ subscription = seedDbService.subscribe({
5865
+ next: (snapshot) => {
5866
+ sendBack({ type: DB_ON_SNAPSHOT, dbName: DB_NAME_SEED, snapshot });
5867
+ },
5868
+ });
6513
5869
  });
6514
- return {
6515
- status,
6516
- internalStatus,
5870
+ _loadSeedDb().then(() => {
5871
+ sendBack({ type: INTERNAL_LOADING_SEED_DB_SUCCESS });
5872
+ });
5873
+ return () => {
5874
+ if (subscription) {
5875
+ subscription.unsubscribe();
5876
+ }
6517
5877
  };
6518
- };
5878
+ });
5879
+ const saveConfig = fromCallback(({ sendBack, receive, input: { context } }) => {
5880
+ if (typeof window === 'undefined') {
5881
+ console.error('seedInitBrowser called from non-browser context');
5882
+ sendBack({
5883
+ type: 'error',
5884
+ error: 'Browser method called from non-browser context',
5885
+ });
5886
+ }
5887
+ const { endpoints, addresses } = context;
5888
+ if (!endpoints) {
5889
+ throw new Error('saveConfig called with invalid endpoints');
5890
+ }
5891
+ const _saveConfig = () => __awaiter(void 0, void 0, void 0, function* () {
5892
+ // logger('[sdk] [internal/actors] starting _saveConfig')
5893
+ const seedDb = getDb(DB_NAME_SEED);
5894
+ if (!seedDb) {
5895
+ throw new Error('Seed DB not found');
5896
+ }
5897
+ const endpointsValueString = JSON.stringify(endpoints);
5898
+ const addressesValueString = JSON.stringify(addresses);
5899
+ // TODO: Figure out how to define on conflict with multiple rows added
5900
+ try {
5901
+ // logger('[sdk] [internal/actors] Saving endpoints to db')
5902
+ yield seedDb
5903
+ .insert(appState)
5904
+ .values({
5905
+ key: 'endpoints',
5906
+ value: endpointsValueString,
5907
+ })
5908
+ .onConflictDoUpdate({
5909
+ target: appState.key,
5910
+ set: {
5911
+ value: endpointsValueString,
5912
+ },
5913
+ setWhere: sql `key = 'endpoints'`,
5914
+ });
5915
+ // logger('[sdk] [internal/actors] Saving addresses to db')
5916
+ yield seedDb
5917
+ .insert(appState)
5918
+ .values({
5919
+ key: 'addresses',
5920
+ value: addressesValueString,
5921
+ })
5922
+ .onConflictDoUpdate({
5923
+ target: appState.key,
5924
+ set: {
5925
+ value: addressesValueString,
5926
+ },
5927
+ setWhere: sql `key = 'addresses'`,
5928
+ });
5929
+ logger$3('[sdk] [internal/actors] Should be done saving');
5930
+ }
5931
+ catch (error) {
5932
+ console.error('Error saving config:', error);
5933
+ }
5934
+ });
5935
+ _saveConfig().then(() => {
5936
+ logger$3('[sdk] [internal/actors] Successfully saved config');
5937
+ return sendBack({ type: INTERNAL_SAVING_CONFIG_SUCCESS });
5938
+ });
5939
+ return () => { };
5940
+ });
5941
+ const loadAppDb = fromCallback(({ sendBack, input: { context } }) => {
5942
+ const { appDbService } = context;
5943
+ let subscription;
5944
+ const _loadAppDb = () => __awaiter(void 0, void 0, void 0, function* () {
5945
+ return new Promise((resolve) => {
5946
+ if (appDbService.getSnapshot().value === 'ready') {
5947
+ return resolve();
5948
+ }
5949
+ subscription = appDbService.subscribe({
5950
+ next: (snapshot) => {
5951
+ if (snapshot.value === 'ready') {
5952
+ return resolve();
5953
+ }
5954
+ sendBack({ type: DB_ON_SNAPSHOT, dbName: DB_NAME_APP, snapshot });
5955
+ },
5956
+ });
5957
+ });
5958
+ });
5959
+ _loadAppDb().then(() => {
5960
+ sendBack({ type: INTERNAL_LOADING_APP_DB_SUCCESS });
5961
+ logger$3('[sdk] [internal/actors] Successfully loaded app DB');
5962
+ });
5963
+ return () => {
5964
+ if (subscription) {
5965
+ subscription.unsubscribe();
5966
+ }
5967
+ };
5968
+ });
5969
+ const loadSdkDb = fromCallback(({ sendBack, input: { context } }) => {
5970
+ const { sdkDbService } = context;
5971
+ logger$3('[sdk] [internal/actors] Loading SDK DB');
5972
+ let subscription;
5973
+ const _loadSdkDb = () => __awaiter(void 0, void 0, void 0, function* () {
5974
+ return new Promise((resolve) => {
5975
+ if (sdkDbService.getSnapshot().value === 'ready') {
5976
+ return resolve();
5977
+ }
5978
+ subscription = sdkDbService.subscribe({
5979
+ next: (snapshot) => {
5980
+ if (snapshot.value === 'ready') {
5981
+ return resolve();
5982
+ }
5983
+ sendBack({
5984
+ type: DB_ON_SNAPSHOT,
5985
+ dbName: DB_NAME_SDK_CONFIG,
5986
+ snapshot,
5987
+ });
5988
+ },
5989
+ });
5990
+ });
5991
+ });
5992
+ _loadSdkDb().then(() => {
5993
+ sendBack({ type: INTERNAL_LOADING_SDK_DB_SUCCESS });
5994
+ logger$3('[sdk] [internal/actors] Successfully loaded SDK DB');
5995
+ });
5996
+ return () => {
5997
+ if (subscription) {
5998
+ subscription.unsubscribe();
5999
+ }
6000
+ };
6001
+ });
6002
+
6003
+ const logger$2 = debug('app:services:db:machine');
6004
+ const { CHECKING_STATUS, VALIDATING, WAITING_FOR_FILES, CONNECTING_TO_DB, MIGRATING, } = DbState;
6005
+ const dbMachine = setup({
6006
+ types: {
6007
+ context: {},
6008
+ input: {},
6009
+ },
6010
+ actors: {
6011
+ checkStatus,
6012
+ validate,
6013
+ connectToDb,
6014
+ migrate,
6015
+ },
6016
+ }).createMachine({
6017
+ id: MachineIds.DB,
6018
+ initial: CHECKING_STATUS,
6019
+ context: ({ input }) => input,
6020
+ on: {
6021
+ [DB_WAITING_FOR_FILES_RECEIVED]: {
6022
+ actions: assign({
6023
+ hasFiles: ({ event }) => {
6024
+ logger$2('[db/machine] DB_WAITING_FOR_FILES_RECEIVED event:', event);
6025
+ return true;
6026
+ },
6027
+ }),
6028
+ },
6029
+ updateHasFiles: {
6030
+ target: `.${CHECKING_STATUS}`,
6031
+ actions: assign({
6032
+ hasFiles: ({ context, event }) => {
6033
+ logger$2('[db/machine] updateHasFiles event:', event);
6034
+ logger$2('[db/machine] updateHasFiles context:', context);
6035
+ return event.hasFiles;
6036
+ },
6037
+ }),
6038
+ },
6039
+ },
6040
+ // always: {
6041
+ // target: `.${CHECKING_STATUS}`,
6042
+ // guard: ({ context, event }) => context.hasFiles && event.type === 'updateHasFiles',
6043
+ // },
6044
+ states: {
6045
+ idle: {
6046
+ on: {
6047
+ start: CHECKING_STATUS,
6048
+ },
6049
+ meta: {
6050
+ displayText: 'DB starting ...',
6051
+ percentComplete: 0,
6052
+ },
6053
+ },
6054
+ [CHECKING_STATUS]: {
6055
+ on: {
6056
+ [DB_CHECK_STATUS_UPDATE_PATHS]: {
6057
+ actions: assign({
6058
+ pathToDb: ({ event }) => event.pathToDb,
6059
+ pathToDir: ({ event }) => event.pathToDir,
6060
+ pathToDbDir: ({ event }) => event.pathToDbDir,
6061
+ }),
6062
+ },
6063
+ [DB_CHECK_STATUS_EXISTS]: CONNECTING_TO_DB,
6064
+ },
6065
+ invoke: {
6066
+ src: 'checkStatus',
6067
+ input: ({ context, event }) => ({ context, event }),
6068
+ },
6069
+ meta: {
6070
+ displayText: 'Checking DB status',
6071
+ percentComplete: 60,
6072
+ },
6073
+ },
6074
+ [CONNECTING_TO_DB]: {
6075
+ on: {
6076
+ [DB_CREATING_SUCCESS]: {
6077
+ target: VALIDATING,
6078
+ actions: assign({
6079
+ dbId: ({ event }) => event.dbId,
6080
+ }),
6081
+ },
6082
+ },
6083
+ invoke: {
6084
+ src: 'connectToDb',
6085
+ input: ({ context }) => ({ context }),
6086
+ },
6087
+ meta: {
6088
+ displayText: 'Connecting to local DB',
6089
+ percentComplete: 70,
6090
+ },
6091
+ },
6092
+ [VALIDATING]: {
6093
+ on: {
6094
+ [DB_VALIDATING_SUCCESS]: {
6095
+ target: MIGRATING,
6096
+ // guard: ({ context }) => context.hasFiles,
6097
+ },
6098
+ [DB_VALIDATING_WAIT]: {
6099
+ target: WAITING_FOR_FILES,
6100
+ // guard: ({ context }) => !context.hasFiles,
6101
+ },
6102
+ },
6103
+ invoke: {
6104
+ src: 'validate',
6105
+ input: ({ context }) => ({ context }),
6106
+ },
6107
+ meta: {
6108
+ displayText: 'Validating DB',
6109
+ percentComplete: 80,
6110
+ },
6111
+ },
6112
+ // Here we're waiting for migration and schema files to be downloaded
6113
+ [WAITING_FOR_FILES]: {
6114
+ on: {
6115
+ [DB_WAITING_FOR_FILES_RECEIVED]: {
6116
+ target: MIGRATING,
6117
+ actions: assign({
6118
+ hasFiles: true,
6119
+ }),
6120
+ },
6121
+ [DB_MIGRATING_SUCCESS]: 'ready',
6122
+ },
6123
+ entry: ({ context }) => {
6124
+ if (context.hasFiles) {
6125
+ emit({ type: DB_WAITING_FOR_FILES_RECEIVED });
6126
+ }
6127
+ },
6128
+ },
6129
+ [MIGRATING]: {
6130
+ on: {
6131
+ [DB_MIGRATING_WAIT]: WAITING_FOR_FILES,
6132
+ [DB_MIGRATING_SUCCESS]: {
6133
+ target: 'ready',
6134
+ },
6135
+ },
6136
+ invoke: {
6137
+ src: 'migrate',
6138
+ input: ({ context }) => ({ context }),
6139
+ },
6140
+ meta: {
6141
+ displayText: 'Migrating DB',
6142
+ percentComplete: 90,
6143
+ },
6144
+ },
6145
+ ready: {
6146
+ target: 'idle',
6147
+ meta: {
6148
+ displayText: 'Wrapping up the db ...',
6149
+ percentComplete: 100,
6150
+ },
6151
+ },
6152
+ },
6153
+ });
6154
+
6155
+ const logger$1 = debug('app:services:internal:machine');
6156
+ createBrowserInspector({
6157
+ autoStart: false,
6158
+ });
6159
+ const { IDLE, VALIDATING_INPUT, SAVING_CONFIG, CONFIGURING_FS, LOADING_DBS, LOADING_SEED_DB, LOADING_APP_DB, LOADING_SDK_DB, } = InternalState;
6160
+ // Create the state machine
6161
+ const internalMachine = setup({
6162
+ types: {
6163
+ context: {},
6164
+ input: {},
6165
+ },
6166
+ actors: {
6167
+ prepareDb,
6168
+ validateInput,
6169
+ configureFs,
6170
+ loadSeedDb,
6171
+ saveConfig,
6172
+ loadAppDb,
6173
+ loadSdkDb,
6174
+ },
6175
+ }).createMachine({
6176
+ id: MachineIds.INTERNAL,
6177
+ initial: IDLE,
6178
+ context: ({ input }) => {
6179
+ return Object.assign(Object.assign({}, input), { error: undefined, hasFiles: false });
6180
+ },
6181
+ states: {
6182
+ [IDLE]: {
6183
+ on: {
6184
+ reValidate: VALIDATING_INPUT,
6185
+ init: {
6186
+ target: VALIDATING_INPUT,
6187
+ actions: [
6188
+ assign({
6189
+ seedDbService: ({ spawn }) => spawn(dbMachine, {
6190
+ input: {
6191
+ dbName: DB_NAME_SEED,
6192
+ dirName: DB_DIR_NAME_SEED,
6193
+ },
6194
+ }),
6195
+ }),
6196
+ assign({
6197
+ appDbService: ({ spawn }) => spawn(dbMachine, {
6198
+ input: {
6199
+ dbName: DB_NAME_APP,
6200
+ dirName: DB_DIR_NAME_APP,
6201
+ },
6202
+ }),
6203
+ }),
6204
+ assign({
6205
+ sdkDbService: ({ spawn }) => spawn(dbMachine, {
6206
+ input: {
6207
+ dbName: DB_NAME_SDK_CONFIG,
6208
+ dirName: DB_DIR_NAME_SDK,
6209
+ },
6210
+ }),
6211
+ }),
6212
+ ],
6213
+ },
6214
+ },
6215
+ meta: {
6216
+ displayText: 'Waiting for something to happen ...',
6217
+ percentComplete: 0,
6218
+ },
6219
+ },
6220
+ [VALIDATING_INPUT]: {
6221
+ on: {
6222
+ [INTERNAL_VALIDATING_INPUT_SUCCESS]: {
6223
+ target: 'preparingDb',
6224
+ actions: assign({
6225
+ endpoints: ({ event }) => event.endpoints,
6226
+ addresses: ({ event }) => event.addresses,
6227
+ }),
6228
+ },
6229
+ },
6230
+ invoke: {
6231
+ src: 'validateInput',
6232
+ input: ({ context, event }) => ({ context, event }),
6233
+ },
6234
+ meta: {
6235
+ displayText: 'Validating input',
6236
+ percentComplete: 20,
6237
+ },
6238
+ tags: ['loading'],
6239
+ },
6240
+ preparingDb: {
6241
+ on: {
6242
+ prepareDbSuccess: {
6243
+ target: CONFIGURING_FS,
6244
+ },
6245
+ },
6246
+ invoke: {
6247
+ src: 'prepareDb',
6248
+ input: ({ context, event }) => ({ context, event }),
6249
+ },
6250
+ },
6251
+ [CONFIGURING_FS]: {
6252
+ on: {
6253
+ [INTERNAL_CONFIGURING_FS_SUCCESS]: {
6254
+ target: LOADING_SEED_DB,
6255
+ actions: assign({ hasFiles: true }),
6256
+ },
6257
+ },
6258
+ invoke: {
6259
+ src: 'configureFs',
6260
+ input: ({ context, event }) => ({ context, event }),
6261
+ },
6262
+ meta: {
6263
+ displayText: 'Downloading app files',
6264
+ percentComplete: 30,
6265
+ },
6266
+ tags: ['loading'],
6267
+ },
6268
+ // We run this before the other DBs because it holds the config we need to
6269
+ // rebuild. If we get interrupted after this then we don't have to start
6270
+ // from scratch.
6271
+ [LOADING_SEED_DB]: {
6272
+ on: {
6273
+ [INTERNAL_LOADING_SEED_DB_SUCCESS]: SAVING_CONFIG,
6274
+ // [DB_ON_SNAPSHOT]: {
6275
+ // actions: emit(({ event: { snapshot } }) => {
6276
+ // return { type: CHILD_SNAPSHOT, snapshot }
6277
+ // }),
6278
+ // },
6279
+ },
6280
+ invoke: {
6281
+ src: 'loadSeedDb',
6282
+ input: ({ context, event }) => ({ context, event }),
6283
+ },
6284
+ meta: {
6285
+ displayText: 'Loading seed database',
6286
+ percentComplete: 50,
6287
+ },
6288
+ tags: ['loading'],
6289
+ },
6290
+ // Save developer's config to DB
6291
+ [SAVING_CONFIG]: {
6292
+ on: {
6293
+ [INTERNAL_SAVING_CONFIG_SUCCESS]: LOADING_DBS,
6294
+ },
6295
+ invoke: {
6296
+ src: 'saveConfig',
6297
+ input: ({ context, event }) => ({ context, event }),
6298
+ },
6299
+ meta: {
6300
+ displayText: 'Saving configuration',
6301
+ percentComplete: 80,
6302
+ },
6303
+ tags: ['loading'],
6304
+ },
6305
+ // The DBs can be loaded in parallel since they are independent of each other
6306
+ [LOADING_DBS]: {
6307
+ type: 'parallel',
6308
+ states: {
6309
+ [LOADING_APP_DB]: {
6310
+ initial: 'loading',
6311
+ states: {
6312
+ loading: {
6313
+ on: {
6314
+ [INTERNAL_LOADING_APP_DB_SUCCESS]: {
6315
+ target: 'appDbLoaded',
6316
+ actions: () => {
6317
+ logger$1('[sdk] [internal/index] App DB loaded!');
6318
+ },
6319
+ },
6320
+ },
6321
+ invoke: {
6322
+ src: 'loadAppDb',
6323
+ input: ({ context, event }) => ({ context, event }),
6324
+ },
6325
+ },
6326
+ appDbLoaded: {
6327
+ type: 'final',
6328
+ entry: () => {
6329
+ logger$1('[sdk] [internal/index] Entered appDbLoaded!');
6330
+ },
6331
+ },
6332
+ },
6333
+ },
6334
+ [LOADING_SDK_DB]: {
6335
+ initial: 'loading',
6336
+ states: {
6337
+ loading: {
6338
+ on: {
6339
+ [INTERNAL_LOADING_SDK_DB_SUCCESS]: {
6340
+ target: 'sdkConfigDbLoaded',
6341
+ actions: () => {
6342
+ logger$1('[sdk] [internal/index] SDK Config DB loaded!');
6343
+ },
6344
+ },
6345
+ },
6346
+ invoke: {
6347
+ src: 'loadSdkDb',
6348
+ input: ({ context, event }) => ({ context, event }),
6349
+ },
6350
+ },
6351
+ sdkConfigDbLoaded: {
6352
+ type: 'final',
6353
+ entry: () => {
6354
+ logger$1('[sdk] [internal/index] Entered sdkConfigDbLoaded!');
6355
+ },
6356
+ },
6357
+ },
6358
+ },
6359
+ },
6360
+ onDone: {
6361
+ target: 'ready',
6362
+ actions: () => {
6363
+ logger$1('[sdk] [internal/index] All DBs loaded! Should be headed to ready');
6364
+ eventEmitter.emit('allDbsLoaded');
6365
+ },
6366
+ },
6367
+ meta: {
6368
+ displayText: 'Loading databases',
6369
+ percentComplete: 90,
6370
+ },
6371
+ tags: ['loading'],
6372
+ },
6373
+ ready: {
6374
+ entry: () => {
6375
+ logger$1('[sdk] [internal/index] Ready!');
6376
+ },
6377
+ meta: {
6378
+ displayText: "Crossing the t's ...",
6379
+ percentComplete: 90,
6380
+ },
6381
+ },
6382
+ error: {
6383
+ on: {
6384
+ retry: {
6385
+ target: CONFIGURING_FS,
6386
+ actions: assign({ error: undefined }),
6387
+ },
6388
+ },
6389
+ entry: () => {
6390
+ logger$1('[sdk] [internal/index] Error!');
6391
+ },
6392
+ meta: {
6393
+ displayText: 'Whoops! Something went wrong.',
6394
+ percentComplete: null,
6395
+ },
6396
+ tags: ['error'],
6397
+ },
6398
+ },
6399
+ });
6400
+
6401
+ const { UNINITIALIZED, INITIALIZING, INITIALIZED, GETTING_SEED_CLASS, GETTING_SCHEMA_FOR_MODEL, ADDING_MODELS_TO_DB, } = GlobalState;
6402
+ createBrowserInspector({
6403
+ autoStart: false,
6404
+ });
6405
+ const globalMachine = setup({
6406
+ types: {
6407
+ context: {},
6408
+ input: {},
6409
+ },
6410
+ actors: {
6411
+ initialize,
6412
+ addModelsToDb,
6413
+ getSchemaForModel,
6414
+ },
6415
+ }).createMachine({
6416
+ id: MachineIds.GLOBAL,
6417
+ initial: UNINITIALIZED,
6418
+ context: ({ input }) => input,
6419
+ states: {
6420
+ [UNINITIALIZED]: {
6421
+ on: {
6422
+ init: {
6423
+ target: INITIALIZING,
6424
+ guard: ({ context }) => {
6425
+ return typeof window !== 'undefined';
6426
+ },
6427
+ actions: [
6428
+ assign({
6429
+ isInitialized: false,
6430
+ addedModelRecordsToDb: false,
6431
+ models: ({ event }) => event.models,
6432
+ endpoints: ({ event }) => event.endpoints,
6433
+ internalService: ({ spawn, context }) => {
6434
+ return spawn(internalMachine, {
6435
+ systemId: MachineIds.INTERNAL,
6436
+ input: {
6437
+ endpoints: context.endpoints,
6438
+ },
6439
+ });
6440
+ },
6441
+ // fileSystemService: ({ spawn, event }) => {
6442
+ // return spawn(fileSystemMachine, {
6443
+ // systemId: MachineIds.FILE_SYSTEM,
6444
+ // input: {
6445
+ // addresses: event.addresses,
6446
+ // },
6447
+ // })
6448
+ // },
6449
+ }),
6450
+ assign(({ event, spawn }) => {
6451
+ const allItemsServices = {};
6452
+ for (const [modelName, ModelClass] of Object.entries(event.models)) {
6453
+ const service = spawn(itemMachineAll, {
6454
+ systemId: modelName,
6455
+ input: {
6456
+ modelName,
6457
+ ModelClass,
6458
+ modelSchema: ModelClass.schema,
6459
+ items: [],
6460
+ },
6461
+ });
6462
+ allItemsServices[`${modelName}Service`] = service;
6463
+ }
6464
+ return allItemsServices;
6465
+ }),
6466
+ ],
6467
+ },
6468
+ },
6469
+ meta: {
6470
+ displayText: 'Booting up',
6471
+ percentComplete: 5,
6472
+ },
6473
+ tags: ['loading'],
6474
+ },
6475
+ [INITIALIZING]: {
6476
+ on: {
6477
+ [GLOBAL_INITIALIZING_SEND_CONFIG]: {
6478
+ actions: assign({
6479
+ endpoints: ({ event }) => event.endpoints,
6480
+ environment: ({ event }) => event.environment,
6481
+ addresses: ({ event }) => event.addresses,
6482
+ isInitialized: true,
6483
+ }),
6484
+ },
6485
+ [GLOBAL_INITIALIZING_INTERNAL_SERVICE_READY]: ADDING_MODELS_TO_DB,
6486
+ },
6487
+ invoke: {
6488
+ src: 'initialize',
6489
+ input: ({ event, context }) => ({ event, context }),
6490
+ meta: {
6491
+ displayText: 'Initializing Seed SDK',
6492
+ percentComplete: 10,
6493
+ },
6494
+ tags: ['loading'],
6495
+ },
6496
+ },
6497
+ [ADDING_MODELS_TO_DB]: {
6498
+ on: {
6499
+ [GLOBAL_ADDING_MODELS_TO_DB_SUCCESS]: {
6500
+ target: INITIALIZED,
6501
+ actions: assign({
6502
+ addedModelRecordsToDb: true,
6503
+ }),
6504
+ },
6505
+ },
6506
+ invoke: {
6507
+ src: 'addModelsToDb',
6508
+ input: ({ context }) => ({ context }),
6509
+ meta: {
6510
+ displayText: 'Adding models to database',
6511
+ },
6512
+ tags: ['loading'],
6513
+ },
6514
+ },
6515
+ [INITIALIZED]: {
6516
+ type: 'parallel',
6517
+ on: {
6518
+ getSeedClass: `.${GETTING_SEED_CLASS}`,
6519
+ getSchemaForModel: `.${GETTING_SCHEMA_FOR_MODEL}`,
6520
+ },
6521
+ meta: {
6522
+ displayText: 'Global service ready',
6523
+ percentComplete: 40,
6524
+ },
6525
+ tags: ['loading'],
6526
+ states: {
6527
+ [GETTING_SEED_CLASS]: {
6528
+ entry: [
6529
+ (_a) => __awaiter(void 0, [_a], void 0, function* ({ context }) {
6530
+ let SeedClass;
6531
+ if (context.environment === 'node') {
6532
+ const { SeedNode } = yield import('./seed-BJtzMyfP.js');
6533
+ SeedClass = SeedNode;
6534
+ }
6535
+ else {
6536
+ const { SeedBrowser } = yield import('./seed-Ch6JPrtQ.js');
6537
+ SeedClass = SeedBrowser;
6538
+ }
6539
+ return SeedClass;
6540
+ }),
6541
+ ],
6542
+ meta: {
6543
+ displayText: 'Getting SeedClass',
6544
+ },
6545
+ tags: ['loading'],
6546
+ },
6547
+ [GETTING_SCHEMA_FOR_MODEL]: {
6548
+ invoke: {
6549
+ src: 'getSchemaForModel',
6550
+ input: ({ event, context }) => ({ event, context }),
6551
+ meta: {
6552
+ displayText: 'Getting schema for model',
6553
+ },
6554
+ tags: ['loading'],
6555
+ },
6556
+ },
6557
+ },
6558
+ },
6559
+ },
6560
+ // on: {
6561
+ // '*': {
6562
+ // actions: emit(({ event }) => {
6563
+ // return event
6564
+ // }),
6565
+ // },
6566
+ // },
6567
+ });
6568
+ const globalService = createActor(globalMachine, {
6569
+ input: {},
6570
+ // inspect,
6571
+ inspect: (inspEvent) => {
6572
+ eventEmitter.emit('inspect.globalService', inspEvent);
6573
+ // console.log('[sdk] [service/index] inspEvent', inspEvent)
6574
+ // eventEmitter.emit('globalService', inspEvent)
6575
+ // let eventType: string = inspEvent.type
6576
+ // if (inspEvent.event && inspEvent.event.type) {
6577
+ // eventType = inspEvent.event.type
6578
+ // }
6579
+ //
6580
+ // if (typeof eventType === 'object') {
6581
+ // eventType = JSON.stringify(eventType)
6582
+ // }
6583
+ //
6584
+ // let srcId = inspEvent.actorRef.id
6585
+ //
6586
+ // if (!srcId.includes('seedSdk')) {
6587
+ // srcId = inspEvent.actorRef.logic.config.id
6588
+ // }
6589
+ //
6590
+ // if (inspEvent.type === '@xstate.snapshot') {
6591
+ // if (
6592
+ // inspEvent.event.type === CHILD_SNAPSHOT &&
6593
+ // inspEvent.snapshot &&
6594
+ // inspEvent.snapshot.machine.id === MachineIds.GLOBAL
6595
+ // ) {
6596
+ // return
6597
+ // }
6598
+ // if (inspEvent.snapshot && inspEvent.snapshot.value) {
6599
+ // if (typeof window !== 'undefined') {
6600
+ // eventEmitter.emit('globalService', {
6601
+ // type: eventType,
6602
+ // src: srcId,
6603
+ // snapshot: inspEvent.snapshot,
6604
+ // })
6605
+ // }
6606
+ // }
6607
+ // } else {
6608
+ // if (typeof window !== 'undefined') {
6609
+ // let snapshot
6610
+ //
6611
+ // try {
6612
+ // snapshot = inspEvent.actorRef.getSnapshot()
6613
+ // } catch (e) {
6614
+ // // This fails if the actor hasn't initialized yet, but that's OK I think
6615
+ // // console.log('[sdk] [service/index] ERROR', e)
6616
+ // }
6617
+ //
6618
+ // eventEmitter.emit('globalService', {
6619
+ // type: eventType,
6620
+ // src: srcId,
6621
+ // snapshot,
6622
+ // })
6623
+ // }
6624
+ // }
6625
+ },
6626
+ });
6627
+ globalService.start();
6628
+ const getGlobalService = () => globalService;
6519
6629
 
6520
6630
  const logger = debug('app:services:events');
6521
6631
  const handleServiceSaveState = (event) => {
@@ -6527,5 +6637,5 @@ const setupServicesEventHandlers = () => {
6527
6637
  eventEmitter.addListener('service.saveState.request', handleServiceSaveState);
6528
6638
  };
6529
6639
 
6530
- export { useDeleteItem as $, APP_DB_CONFIG as A, setupFsListeners as B, CHILD_SNAPSHOT as C, DB_NAME_SDK_CONFIG as D, setupAllItemsEventHandlers as E, setupServicesEventHandlers as F, GET_SCHEMAS as G, globalService as H, Item as I, Json as J, getModel as K, List as L, Model as M, getModels as N, getModelNames as O, Property as P, areFsListenersReady as Q, Relation as R, SCHEMA_NJK as S, Text as T, ItemProperty as U, useItems as V, useItem as W, useItemProperties as X, useCreateItem as Y, useItemProperty as Z, __awaiter as _, GET_SEEDS as a, getGlobalService as a0, getCorrectId as a1, 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, internalMachine as h, itemMachineSingle as i, isNode as j, isBrowser as k, isReactNative as l, __decorate as m, __metadata as n, models as o, SCHEMA_TS as p, SDK_DB_CONFIG as q, SEED_DB_CONFIG as r, addModelsToInternalDb as s, ImageSrc as t, createNewMetadataFromExistingRecord as u, generateId as v, eventEmitter as w, getDb as x, DB_NAME_APP as y, setModel as z };
6531
- //# sourceMappingURL=events-DbpQM9qG.js.map
6640
+ export { useDeleteItem as $, APP_DB_CONFIG as A, setupFsListeners as B, CHILD_SNAPSHOT as C, DB_NAME_SDK_CONFIG as D, setupAllItemsEventHandlers as E, setupServicesEventHandlers as F, GET_SCHEMAS as G, globalService as H, Item as I, Json as J, getModel as K, List as L, Model as M, getModels as N, getModelNames as O, Property as P, areFsListenersReady as Q, Relation as R, SCHEMA_NJK as S, Text as T, ItemProperty as U, useItems as V, useItem as W, useItemProperties as X, useCreateItem as Y, useItemProperty as Z, __awaiter as _, GET_SEEDS as a, useServices as a0, getGlobalService as a1, getCorrectId as a2, 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, internalMachine as h, itemMachineSingle as i, isNode as j, isBrowser as k, isReactNative as l, __decorate as m, __metadata as n, models as o, SCHEMA_TS as p, SDK_DB_CONFIG as q, SEED_DB_CONFIG as r, addModelsToInternalDb as s, ImageSrc as t, createNewMetadataFromExistingRecord as u, generateId as v, eventEmitter as w, getDb as x, DB_NAME_APP as y, setModel as z };
6641
+ //# sourceMappingURL=events-DY-qRoqO.js.map