@powerhousedao/reactor-browser 1.10.2 → 1.11.0

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 (108) hide show
  1. package/dist/package.json +47 -0
  2. package/dist/src/context/index.d.ts +1 -1
  3. package/dist/src/context/index.d.ts.map +1 -1
  4. package/dist/src/context/index.js +1 -0
  5. package/dist/src/context/read-mode.d.ts +3 -3
  6. package/dist/src/context/read-mode.d.ts.map +1 -1
  7. package/dist/src/context/read-mode.js +198 -0
  8. package/dist/src/crypto/browser.d.ts +1 -1
  9. package/dist/src/crypto/browser.d.ts.map +1 -1
  10. package/dist/src/crypto/browser.js +49 -0
  11. package/dist/src/crypto/index.js +121 -0
  12. package/dist/src/document-model.d.ts +3 -3
  13. package/dist/src/document-model.d.ts.map +1 -1
  14. package/dist/src/document-model.js +5 -0
  15. package/dist/src/hooks/index.d.ts +9 -5
  16. package/dist/src/hooks/index.d.ts.map +1 -1
  17. package/dist/src/hooks/index.js +9 -0
  18. package/dist/src/hooks/useAddDebouncedOperations.d.ts +3 -3
  19. package/dist/src/hooks/useAddDebouncedOperations.d.ts.map +1 -1
  20. package/dist/src/hooks/useAddDebouncedOperations.js +55 -0
  21. package/dist/src/hooks/useConnectCrypto.d.ts +1 -1
  22. package/dist/src/hooks/useConnectCrypto.d.ts.map +1 -1
  23. package/dist/src/hooks/useConnectCrypto.js +40 -0
  24. package/dist/src/hooks/useDocument.d.ts +3 -3
  25. package/dist/src/hooks/useDocument.d.ts.map +1 -1
  26. package/dist/src/hooks/useDocument.js +37 -0
  27. package/dist/src/hooks/useDocumentDispatch.d.ts +6 -10
  28. package/dist/src/hooks/useDocumentDispatch.d.ts.map +1 -1
  29. package/dist/src/hooks/useDocumentDispatch.js +41 -0
  30. package/dist/src/hooks/useDocumentDrives.d.ts +4 -3
  31. package/dist/src/hooks/useDocumentDrives.d.ts.map +1 -1
  32. package/dist/src/hooks/useDocumentDrives.js +84 -0
  33. package/dist/src/hooks/useDocumentEditor.d.ts +13 -13
  34. package/dist/src/hooks/useDocumentEditor.d.ts.map +1 -1
  35. package/dist/src/hooks/useDocumentEditor.js +30 -0
  36. package/dist/src/hooks/useDriveActions.d.ts +82 -0
  37. package/dist/src/hooks/useDriveActions.d.ts.map +1 -0
  38. package/dist/src/hooks/useDriveActions.js +125 -0
  39. package/dist/src/hooks/useDriveActionsWithUiNodes.d.ts +17 -0
  40. package/dist/src/hooks/useDriveActionsWithUiNodes.d.ts.map +1 -0
  41. package/dist/src/hooks/useDriveActionsWithUiNodes.js +71 -0
  42. package/dist/src/hooks/useDriveContext.d.ts +66 -0
  43. package/dist/src/hooks/useDriveContext.d.ts.map +1 -0
  44. package/dist/src/hooks/useDriveContext.js +25 -0
  45. package/dist/src/hooks/useUiNodesContext.d.ts +25 -0
  46. package/dist/src/hooks/useUiNodesContext.d.ts.map +1 -0
  47. package/dist/src/hooks/useUiNodesContext.js +167 -0
  48. package/dist/src/hooks/useUserPermissions.js +6 -0
  49. package/dist/src/index.d.ts +5 -5
  50. package/dist/src/index.d.ts.map +1 -1
  51. package/dist/src/index.js +4 -0
  52. package/dist/src/reactor.d.ts +3 -3
  53. package/dist/src/reactor.d.ts.map +1 -1
  54. package/dist/src/reactor.js +54 -0
  55. package/dist/src/renown/constants.js +39 -0
  56. package/dist/src/renown/types.d.ts +3 -3
  57. package/dist/src/renown/types.d.ts.map +1 -1
  58. package/dist/src/renown/types.js +1 -0
  59. package/dist/src/storage/index.d.ts +1 -1
  60. package/dist/src/storage/index.d.ts.map +1 -1
  61. package/dist/src/storage/index.js +1 -0
  62. package/dist/src/storage/types.js +1 -0
  63. package/dist/src/uiNodes/constants.d.ts +17 -0
  64. package/dist/src/uiNodes/constants.d.ts.map +1 -0
  65. package/dist/src/uiNodes/constants.js +23 -0
  66. package/dist/src/uiNodes/types.d.ts +61 -0
  67. package/dist/src/uiNodes/types.d.ts.map +1 -0
  68. package/dist/src/uiNodes/types.js +1 -0
  69. package/dist/src/utils/index.d.ts +3 -3
  70. package/dist/src/utils/index.d.ts.map +1 -1
  71. package/dist/src/utils/index.js +8 -0
  72. package/dist/src/utils/signature.d.ts +3 -3
  73. package/dist/src/utils/signature.d.ts.map +1 -1
  74. package/dist/src/utils/signature.js +39 -0
  75. package/dist/tsconfig.tsbuildinfo +1 -0
  76. package/package.json +15 -22
  77. package/dist/_virtual/__vite-browser-external.js +0 -5
  78. package/dist/_virtual/__vite-browser-external.js.map +0 -1
  79. package/dist/context/read-mode.js +0 -159
  80. package/dist/context/read-mode.js.map +0 -1
  81. package/dist/crypto/browser.js +0 -50
  82. package/dist/crypto/browser.js.map +0 -1
  83. package/dist/crypto/index.js +0 -109
  84. package/dist/crypto/index.js.map +0 -1
  85. package/dist/document-model.js +0 -11
  86. package/dist/document-model.js.map +0 -1
  87. package/dist/hooks/useAddDebouncedOperations.js +0 -54
  88. package/dist/hooks/useAddDebouncedOperations.js.map +0 -1
  89. package/dist/hooks/useConnectCrypto.js +0 -34
  90. package/dist/hooks/useConnectCrypto.js.map +0 -1
  91. package/dist/hooks/useDocument.js +0 -20
  92. package/dist/hooks/useDocument.js.map +0 -1
  93. package/dist/hooks/useDocumentDispatch.js +0 -30
  94. package/dist/hooks/useDocumentDispatch.js.map +0 -1
  95. package/dist/hooks/useDocumentDrives.js +0 -86
  96. package/dist/hooks/useDocumentDrives.js.map +0 -1
  97. package/dist/hooks/useDocumentEditor.js +0 -46
  98. package/dist/hooks/useDocumentEditor.js.map +0 -1
  99. package/dist/hooks/useUserPermissions.js +0 -10
  100. package/dist/hooks/useUserPermissions.js.map +0 -1
  101. package/dist/index.js +0 -26
  102. package/dist/index.js.map +0 -1
  103. package/dist/reactor.js +0 -59
  104. package/dist/reactor.js.map +0 -1
  105. package/dist/utils/index.js +0 -16
  106. package/dist/utils/index.js.map +0 -1
  107. package/dist/utils/signature.js +0 -35
  108. package/dist/utils/signature.js.map +0 -1
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@powerhousedao/reactor-browser",
3
+ "version": "1.10.2",
4
+ "license": "AGPL-3.0-only",
5
+ "type": "module",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "types": "./dist/src/index.d.ts",
13
+ "main": "./dist/src/index.js",
14
+ "exports": {
15
+ ".": "./dist/src/index.js",
16
+ "./*": "./dist/src/*.js"
17
+ },
18
+ "scripts": {
19
+ "build:tsc": "tsc --build",
20
+ "lint": "eslint .",
21
+ "lint:nx": "eslint . --fix --quiet",
22
+ "lint:fix": "eslint --fix",
23
+ "build": "tsc --build",
24
+ "build:watch": "tsc --build --watch",
25
+ "test": "vitest run --passWithNoTests",
26
+ "clean": "rimraf dist",
27
+ "clean:node_modules": "rimraf node_modules"
28
+ },
29
+ "keywords": [],
30
+ "author": "",
31
+ "devDependencies": {
32
+ "@types/react": "^18.3.1",
33
+ "@types/react-dom": "^18.3.1",
34
+ "react": "^18.3.1",
35
+ "react-dom": "^18.3.1"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^18.3.1",
39
+ "react-dom": "^18.3.1"
40
+ },
41
+ "dependencies": {
42
+ "document-drive": "workspace:*",
43
+ "document-model": "workspace:*",
44
+ "did-key-creator": "^1.2.0",
45
+ "jotai": "^2.10.3"
46
+ }
47
+ }
@@ -1,2 +1,2 @@
1
- export * from './read-mode';
1
+ export * from "./read-mode.js";
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/context/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1 @@
1
+ export * from "./read-mode.js";
@@ -1,10 +1,10 @@
1
- import { BaseDocumentDriveServer, IReadModeDriveServer, ReadDrive } from 'document-drive';
2
- import { FC, ReactNode } from 'react';
1
+ import { BaseDocumentDriveServer, IReadModeDriveServer, ReadDrive } from "document-drive";
2
+ import { FC, ReactNode } from "react";
3
3
  export interface IReadModeContext extends IReadModeDriveServer {
4
4
  readDrives: ReadDrive[];
5
5
  setDocumentDrive(documentDrive: IReadModeDriveServer): void;
6
6
  }
7
- export declare const ReadModeContext: import('react').Context<IReadModeContext>;
7
+ export declare const ReadModeContext: import("react").Context<IReadModeContext>;
8
8
  export interface ReadModeContextProviderProps {
9
9
  children: ReactNode;
10
10
  reactorPromise: Promise<BaseDocumentDriveServer & IReadModeDriveServer>;
@@ -1 +1 @@
1
- {"version":3,"file":"read-mode.d.ts","sourceRoot":"","sources":["../../../src/context/read-mode.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,uBAAuB,EAKvB,oBAAoB,EAEpB,SAAS,EAOV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAEL,EAAE,EACF,SAAS,EAKV,MAAM,OAAO,CAAC;AAkBf,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,gBAAgB,CAAC,aAAa,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC7D;AAuID,eAAO,MAAM,eAAe,2CAG1B,CAAC;AAEH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC,uBAAuB,GAAG,oBAAoB,CAAC,CAAC;CACzE;AAcD,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,CAkFpE,CAAC;AACF,eAAO,MAAM,kBAAkB,wBAAoC,CAAC"}
1
+ {"version":3,"file":"read-mode.d.ts","sourceRoot":"","sources":["../../../src/context/read-mode.tsx"],"names":[],"mappings":"AAIA,OAAO,EACL,uBAAuB,EAEvB,oBAAoB,EAEpB,SAAS,EAOV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAEL,EAAE,EACF,SAAS,EAKV,MAAM,OAAO,CAAC;AAkBf,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,gBAAgB,CAAC,aAAa,EAAE,oBAAoB,GAAG,IAAI,CAAC;CAC7D;AA+HD,eAAO,MAAM,eAAe,2CAG1B,CAAC;AAEH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC,uBAAuB,GAAG,oBAAoB,CAAC,CAAC;CACzE;AAcD,eAAO,MAAM,uBAAuB,EAAE,EAAE,CAAC,4BAA4B,CAkFpE,CAAC;AACF,eAAO,MAAM,kBAAkB,wBAAoC,CAAC"}
@@ -0,0 +1,198 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ /* eslint-disable react/jsx-props-no-spreading */
9
+ /* eslint-disable @typescript-eslint/no-unnecessary-type-parameters */
10
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
11
+ import { ReadDriveNotFoundError, } from "document-drive";
12
+ import { createContext, useContext, useEffect, useMemo, useState, } from "react";
13
+ import { useUserPermissions } from "../hooks/useUserPermissions.js";
14
+ import { drivesToHash } from "../utils/index.js";
15
+ const logger = {
16
+ error: console.error,
17
+ };
18
+ // TODO: add export of this class from document-drive/src/server/error
19
+ class DocumentModelNotFoundError extends Error {
20
+ id;
21
+ constructor(id, cause) {
22
+ super(`Document model "${id}" not found`, { cause });
23
+ this.id = id;
24
+ }
25
+ }
26
+ // decorator method to ensure server is defined before calling it
27
+ function checkServer(target, propertyKey, descriptor) {
28
+ const originalMethod = descriptor.value;
29
+ descriptor.value = function (...args) {
30
+ if (!this.server) {
31
+ throw new Error("Read mode document drive not initialized.");
32
+ }
33
+ return originalMethod.apply(this, args);
34
+ };
35
+ }
36
+ function bindClassMethods(instance) {
37
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
38
+ const prototype = Object.getPrototypeOf(instance);
39
+ const propertyNames = Object.getOwnPropertyNames(prototype);
40
+ propertyNames.forEach((name) => {
41
+ const descriptor = Object.getOwnPropertyDescriptor(prototype, name);
42
+ if (descriptor &&
43
+ typeof descriptor.value === "function" &&
44
+ name !== "constructor") {
45
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
46
+ instance[name] = instance[name].bind(instance);
47
+ }
48
+ });
49
+ }
50
+ class ReadModeContextImpl {
51
+ server;
52
+ constructor(documentDrive) {
53
+ bindClassMethods(this);
54
+ this.server = documentDrive;
55
+ }
56
+ getServer() {
57
+ return this.server;
58
+ }
59
+ setDocumentDrive(documentDrive) {
60
+ this.server = documentDrive;
61
+ }
62
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
63
+ migrateReadDrive(id, options) {
64
+ return this.server.migrateReadDrive(id, options);
65
+ }
66
+ addReadDrive(url, options) {
67
+ return this.server.addReadDrive(url, options);
68
+ }
69
+ getReadDrives() {
70
+ return this.server.getReadDrives();
71
+ }
72
+ getReadDriveBySlug(slug) {
73
+ return this.server.getReadDriveBySlug(slug);
74
+ }
75
+ getReadDrive(id) {
76
+ return this.server.getReadDrive(id);
77
+ }
78
+ getReadDriveContext(id) {
79
+ return this.server.getReadDriveContext(id);
80
+ }
81
+ fetchDrive(id) {
82
+ return this.server.fetchDrive(id);
83
+ }
84
+ fetchDocument(driveId, documentId, documentType) {
85
+ return this.server.fetchDocument(driveId, documentId, documentType);
86
+ }
87
+ deleteReadDrive(id) {
88
+ return this.server.deleteReadDrive(id);
89
+ }
90
+ onReadDrivesUpdate(listener) {
91
+ return this.server.onReadDrivesUpdate(listener);
92
+ }
93
+ }
94
+ __decorate([
95
+ checkServer
96
+ ], ReadModeContextImpl.prototype, "migrateReadDrive", null);
97
+ __decorate([
98
+ checkServer
99
+ ], ReadModeContextImpl.prototype, "addReadDrive", null);
100
+ __decorate([
101
+ checkServer
102
+ ], ReadModeContextImpl.prototype, "getReadDrives", null);
103
+ __decorate([
104
+ checkServer
105
+ ], ReadModeContextImpl.prototype, "getReadDriveBySlug", null);
106
+ __decorate([
107
+ checkServer
108
+ ], ReadModeContextImpl.prototype, "getReadDrive", null);
109
+ __decorate([
110
+ checkServer
111
+ ], ReadModeContextImpl.prototype, "getReadDriveContext", null);
112
+ __decorate([
113
+ checkServer
114
+ ], ReadModeContextImpl.prototype, "fetchDrive", null);
115
+ __decorate([
116
+ checkServer
117
+ ], ReadModeContextImpl.prototype, "fetchDocument", null);
118
+ __decorate([
119
+ checkServer
120
+ ], ReadModeContextImpl.prototype, "deleteReadDrive", null);
121
+ __decorate([
122
+ checkServer
123
+ ], ReadModeContextImpl.prototype, "onReadDrivesUpdate", null);
124
+ const ReadModeInstance = new ReadModeContextImpl();
125
+ export const ReadModeContext = createContext({
126
+ ...ReadModeInstance,
127
+ readDrives: [],
128
+ });
129
+ async function getReadDrives(instance) {
130
+ const driveIds = await instance.getReadDrives();
131
+ const drives = await Promise.all(driveIds.map((id) => instance.getReadDrive(id)));
132
+ return drives.filter((drive) => !(drive instanceof ReadDriveNotFoundError));
133
+ }
134
+ export const ReadModeContextProvider = (props) => {
135
+ const { reactorPromise, ...restProps } = props;
136
+ const [readDrives, setReadDrives] = useState([]);
137
+ const userPermissions = useUserPermissions();
138
+ const [ready, setReady] = useState(false);
139
+ useEffect(() => {
140
+ reactorPromise
141
+ .then((reactor) => {
142
+ ReadModeInstance.setDocumentDrive(reactor);
143
+ setReady(true);
144
+ })
145
+ .catch(logger.error);
146
+ }, [reactorPromise]);
147
+ // updates drive access level when user permissions change
148
+ const readMode = userPermissions === undefined
149
+ ? undefined
150
+ : !(userPermissions.isAllowedToCreateDocuments ||
151
+ userPermissions.isAllowedToEditDocuments);
152
+ useMemo(() => {
153
+ // wait for user initial load
154
+ if (!ready || readMode === undefined) {
155
+ return;
156
+ }
157
+ const accessLevel = readMode ? "READ" : "WRITE";
158
+ const server = ReadModeInstance.getServer();
159
+ if (server &&
160
+ typeof server.setAllDefaultDrivesAccessLevel ===
161
+ "function") {
162
+ server
163
+ .setAllDefaultDrivesAccessLevel(accessLevel)
164
+ .catch(logger.error);
165
+ }
166
+ }, [readMode, ready]);
167
+ useEffect(() => {
168
+ if (!ready) {
169
+ return;
170
+ }
171
+ getReadDrives(ReadModeInstance)
172
+ .then((drives) => setReadDrives(drives))
173
+ .catch(logger.error);
174
+ const unsubscribe = ReadModeInstance.onReadDrivesUpdate((newDrives) => {
175
+ setReadDrives((readDrives) => readDrives.length !== newDrives.length ||
176
+ drivesToHash(readDrives) !== drivesToHash(newDrives)
177
+ ? newDrives
178
+ : readDrives);
179
+ }).catch(logger.error);
180
+ return () => {
181
+ unsubscribe
182
+ .then((unsub) => {
183
+ if (typeof unsub === "function") {
184
+ unsub();
185
+ }
186
+ })
187
+ .catch(logger.error);
188
+ };
189
+ }, [ready]);
190
+ const context = useMemo(() => {
191
+ return {
192
+ ...ReadModeInstance,
193
+ readDrives,
194
+ };
195
+ }, [readDrives]);
196
+ return _jsx(ReadModeContext.Provider, { ...restProps, value: context });
197
+ };
198
+ export const useReadModeContext = () => useContext(ReadModeContext);
@@ -1,4 +1,4 @@
1
- import { JsonWebKeyPairStorage, JwkKeyPair } from './';
1
+ import { JsonWebKeyPairStorage, JwkKeyPair } from "./index.js";
2
2
  export declare class BrowserKeyStorage implements JsonWebKeyPairStorage {
3
3
  #private;
4
4
  constructor();
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/crypto/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEvD,qBAAa,iBAAkB,YAAW,qBAAqB;;;IA2BvD,WAAW,CAAC,OAAO,EAAE,UAAU;IAa/B,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;CAgBrD"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/crypto/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,iBAAkB,YAAW,qBAAqB;;;IA2BvD,WAAW,CAAC,OAAO,EAAE,UAAU;IAa/B,WAAW,IAAI,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC;CAgBrD"}
@@ -0,0 +1,49 @@
1
+ export class BrowserKeyStorage {
2
+ static #DB_NAME = "browserKeyDB";
3
+ static #STORE_NAME = "keyPairs";
4
+ static #KEY = "keyPair";
5
+ #db;
6
+ constructor() {
7
+ this.#db = new Promise((resolve, reject) => {
8
+ const req = indexedDB.open(BrowserKeyStorage.#DB_NAME, 1);
9
+ req.onupgradeneeded = () => {
10
+ req.result.createObjectStore(BrowserKeyStorage.#STORE_NAME);
11
+ };
12
+ req.onsuccess = () => resolve(req.result);
13
+ req.onerror = () => reject(req.error);
14
+ });
15
+ }
16
+ async #useStore(mode = "readwrite") {
17
+ const database = await this.#db;
18
+ const transaction = database.transaction(BrowserKeyStorage.#STORE_NAME, mode);
19
+ const store = transaction.objectStore(BrowserKeyStorage.#STORE_NAME);
20
+ return store;
21
+ }
22
+ async saveKeyPair(keyPair) {
23
+ const store = await this.#useStore();
24
+ const request = store.put(keyPair, BrowserKeyStorage.#KEY);
25
+ return new Promise((resolve, reject) => {
26
+ request.onsuccess = () => {
27
+ resolve();
28
+ };
29
+ request.onerror = () => {
30
+ reject(new Error("Failed to save key pair"));
31
+ };
32
+ });
33
+ }
34
+ async loadKeyPair() {
35
+ const store = await this.#useStore("readonly");
36
+ const request = store.getAll();
37
+ return new Promise((resolve, reject) => {
38
+ request.onsuccess = () => {
39
+ const keyPair = request.result.length
40
+ ? request.result[0]
41
+ : undefined;
42
+ resolve(keyPair);
43
+ };
44
+ request.onerror = () => {
45
+ reject(new Error("Failed to load key pair"));
46
+ };
47
+ });
48
+ }
49
+ }
@@ -0,0 +1,121 @@
1
+ import { compressedKeyInHexfromRaw, encodeDIDfromHexString, rawKeyInHexfromUncompressed, } from "did-key-creator";
2
+ function ab2hex(ab) {
3
+ return Array.prototype.map
4
+ .call(new Uint8Array(ab), (x) => ("00" + x.toString(16)).slice(-2))
5
+ .join("");
6
+ }
7
+ export class ConnectCrypto {
8
+ #subtleCrypto;
9
+ #keyPair;
10
+ #keyPairStorage;
11
+ #did;
12
+ static algorithm = {
13
+ name: "ECDSA",
14
+ namedCurve: "P-256",
15
+ };
16
+ static signAlgorithm = {
17
+ name: "ECDSA",
18
+ namedCurve: "P-256",
19
+ hash: "SHA-256",
20
+ };
21
+ constructor(keyPairStorage) {
22
+ this.#keyPairStorage = keyPairStorage;
23
+ // Initializes the subtleCrypto module according to the host environment
24
+ this.#subtleCrypto = this.#initCrypto();
25
+ this.#did = this.#initialize();
26
+ }
27
+ #initCrypto() {
28
+ return new Promise((resolve, reject) => {
29
+ if (typeof window === "undefined") {
30
+ import("node:crypto")
31
+ .then((module) => {
32
+ resolve(module.webcrypto.subtle);
33
+ })
34
+ .catch(reject);
35
+ }
36
+ else {
37
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
38
+ if (!window.crypto?.subtle) {
39
+ reject(new Error("Crypto module not available"));
40
+ }
41
+ resolve(window.crypto.subtle);
42
+ }
43
+ });
44
+ }
45
+ // loads the key pair from storage or generates a new one if none is stored
46
+ async #initialize() {
47
+ const loadedKeyPair = await this.#keyPairStorage.loadKeyPair();
48
+ if (loadedKeyPair) {
49
+ this.#keyPair = await this.#importKeyPair(loadedKeyPair);
50
+ console.log("Found key pair");
51
+ }
52
+ else {
53
+ this.#keyPair = await this.#generateECDSAKeyPair();
54
+ console.log("Created key pair");
55
+ await this.#keyPairStorage.saveKeyPair(await this.#exportKeyPair());
56
+ }
57
+ const did = await this.#parseDid();
58
+ console.log("Connect DID:", did);
59
+ return did;
60
+ }
61
+ did() {
62
+ return this.#did;
63
+ }
64
+ async regenerateDid() {
65
+ this.#keyPair = await this.#generateECDSAKeyPair();
66
+ await this.#keyPairStorage.saveKeyPair(await this.#exportKeyPair());
67
+ }
68
+ async #parseDid() {
69
+ if (!this.#keyPair) {
70
+ throw new Error("No key pair available");
71
+ }
72
+ const subtleCrypto = await this.#subtleCrypto;
73
+ const publicKeyRaw = await subtleCrypto.exportKey("raw", this.#keyPair.publicKey);
74
+ const multicodecName = "p256-pub";
75
+ const rawKey = rawKeyInHexfromUncompressed(ab2hex(publicKeyRaw));
76
+ const compressedKey = compressedKeyInHexfromRaw(rawKey);
77
+ const did = encodeDIDfromHexString(multicodecName, compressedKey);
78
+ return did;
79
+ }
80
+ async #generateECDSAKeyPair() {
81
+ const subtleCrypto = await this.#subtleCrypto;
82
+ const keyPair = await subtleCrypto.generateKey(ConnectCrypto.algorithm, true, ["sign", "verify"]);
83
+ return keyPair;
84
+ }
85
+ async #exportKeyPair() {
86
+ if (!this.#keyPair) {
87
+ throw new Error("No key pair available");
88
+ }
89
+ const subtleCrypto = await this.#subtleCrypto;
90
+ const jwkKeyPair = {
91
+ publicKey: await subtleCrypto.exportKey("jwk", this.#keyPair.publicKey),
92
+ privateKey: await subtleCrypto.exportKey("jwk", this.#keyPair.privateKey),
93
+ };
94
+ return jwkKeyPair;
95
+ }
96
+ async #importKeyPair(jwkKeyPair) {
97
+ const subtleCrypto = await this.#subtleCrypto;
98
+ return {
99
+ publicKey: await subtleCrypto.importKey("jwk", jwkKeyPair.publicKey, ConnectCrypto.algorithm, true, ["verify"]),
100
+ privateKey: await subtleCrypto.importKey("jwk", jwkKeyPair.privateKey, ConnectCrypto.algorithm, true, ["sign"]),
101
+ };
102
+ }
103
+ // eslint-disable-next-line no-unused-private-class-members
104
+ #sign = async (...args) => {
105
+ return (await this.#subtleCrypto).sign(...args);
106
+ };
107
+ // eslint-disable-next-line no-unused-private-class-members
108
+ #verify = async (...args) => {
109
+ return (await this.#subtleCrypto).verify(...args);
110
+ };
111
+ async sign(data) {
112
+ if (this.#keyPair?.privateKey) {
113
+ const subtleCrypto = await this.#subtleCrypto;
114
+ const arrayBuffer = await subtleCrypto.sign(ConnectCrypto.signAlgorithm, this.#keyPair.privateKey, data.buffer);
115
+ return new Uint8Array(arrayBuffer);
116
+ }
117
+ else {
118
+ throw new Error("No private key available");
119
+ }
120
+ }
121
+ }
@@ -1,4 +1,4 @@
1
- import { DocumentModel } from 'document-model/document';
2
- export declare const baseDocumentModelsMap: Record<string, DocumentModel>;
3
- export declare const baseDocumentModels: DocumentModel[];
1
+ import { DocumentModelModule } from "document-model";
2
+ export declare const baseDocumentModelsMap: Record<string, DocumentModelModule>;
3
+ export declare const baseDocumentModels: DocumentModelModule[];
4
4
  //# sourceMappingURL=document-model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"document-model.d.ts","sourceRoot":"","sources":["../../src/document-model.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAG/D,CAAC;AAEF,eAAO,MAAM,kBAAkB,iBAAuC,CAAC"}
1
+ {"version":3,"file":"document-model.d.ts","sourceRoot":"","sources":["../../src/document-model.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EACpB,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAErE,CAAC;AAEF,eAAO,MAAM,kBAAkB,uBAAuC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { documentModelDocumentModelModule, } from "document-model";
2
+ export const baseDocumentModelsMap = {
3
+ DocumentModel: documentModelDocumentModelModule,
4
+ };
5
+ export const baseDocumentModels = Object.values(baseDocumentModelsMap);
@@ -1,6 +1,10 @@
1
- export * from './useUserPermissions';
2
- export * from './useDocumentEditor';
3
- export * from './useDocumentDrives';
4
- export * from './useDocument';
5
- export * from './useConnectCrypto';
1
+ export * from "./useConnectCrypto.js";
2
+ export * from "./useDocument.js";
3
+ export * from "./useDocumentDrives.js";
4
+ export * from "./useDocumentEditor.js";
5
+ export * from "./useDriveActions.js";
6
+ export * from "./useDriveActionsWithUiNodes.js";
7
+ export * from "./useDriveContext.js";
8
+ export * from "./useUiNodesContext.js";
9
+ export * from "./useUserPermissions.js";
6
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,iCAAiC,CAAC;AAChD,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export * from "./useConnectCrypto.js";
2
+ export * from "./useDocument.js";
3
+ export * from "./useDocumentDrives.js";
4
+ export * from "./useDocumentEditor.js";
5
+ export * from "./useDriveActions.js";
6
+ export * from "./useDriveActionsWithUiNodes.js";
7
+ export * from "./useDriveContext.js";
8
+ export * from "./useUiNodesContext.js";
9
+ export * from "./useUserPermissions.js";
@@ -1,8 +1,8 @@
1
- import { Document, Operation } from 'document-model/document';
2
- import { IDocumentDriveServer } from 'document-drive';
1
+ import { Operation, PHDocument } from "document-model";
2
+ import { IDocumentDriveServer } from "document-drive";
3
3
  export type UseAddDebouncedOperationsProps = {
4
4
  driveId: string;
5
5
  documentId: string;
6
6
  };
7
- export declare function useAddDebouncedOperations(reactor: IDocumentDriveServer | undefined, props: UseAddDebouncedOperationsProps): (operation: Operation) => Promise<Document | undefined>;
7
+ export declare function useAddDebouncedOperations(reactor: IDocumentDriveServer | undefined, props: UseAddDebouncedOperationsProps): (operation: Operation) => Promise<PHDocument | undefined>;
8
8
  //# sourceMappingURL=useAddDebouncedOperations.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAddDebouncedOperations.d.ts","sourceRoot":"","sources":["../../../src/hooks/useAddDebouncedOperations.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAI9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAyCtD,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EACzC,KAAK,EAAE,8BAA8B,eAxClB,SAAS,mCAoF7B"}
1
+ {"version":3,"file":"useAddDebouncedOperations.d.ts","sourceRoot":"","sources":["../../../src/hooks/useAddDebouncedOperations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AA2CtD,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,oBAAoB,GAAG,SAAS,EACzC,KAAK,EAAE,8BAA8B,eAxClB,SAAS,qCAoF7B"}
@@ -0,0 +1,55 @@
1
+ import { useCallback, useMemo } from "react";
2
+ import { useDocumentDrives } from "./useDocumentDrives.js";
3
+ import { useUserPermissions } from "./useUserPermissions.js";
4
+ function debounceOperations(callback, timeout = 50) {
5
+ let timer;
6
+ const operations = [];
7
+ return (operation) => {
8
+ if (timer) {
9
+ clearTimeout(timer);
10
+ }
11
+ const index = operations.findIndex((op) => op.scope === operation.scope && op.index === operation.index);
12
+ if (index > -1) {
13
+ const oldOperation = operations[index];
14
+ if (!(oldOperation.type === operation.type &&
15
+ JSON.stringify(operation.input) === JSON.stringify(oldOperation.input))) {
16
+ console.warn("Two conflicting operations were dispatched:", oldOperation, operation);
17
+ }
18
+ operations[index] = operation;
19
+ }
20
+ else {
21
+ operations.push(operation);
22
+ }
23
+ return new Promise((resolve, reject) => {
24
+ timer = setTimeout(() => {
25
+ callback(operations).then(resolve).catch(reject);
26
+ }, timeout);
27
+ });
28
+ };
29
+ }
30
+ export function useAddDebouncedOperations(reactor, props) {
31
+ const { driveId, documentId } = props;
32
+ const [documentDrives] = useDocumentDrives(reactor);
33
+ const { isAllowedToEditDocuments } = useUserPermissions() || {
34
+ isAllowedToCreateDocuments: false,
35
+ isAllowedToEditDocuments: false,
36
+ };
37
+ const addOperations = useCallback(async (driveId, id, operations) => {
38
+ if (!isAllowedToEditDocuments) {
39
+ throw new Error("User is not allowed to edit documents");
40
+ }
41
+ if (!reactor) {
42
+ throw new Error("Reactor is not loaded");
43
+ }
44
+ const drive = documentDrives.find((drive) => drive.state.global.id === driveId);
45
+ if (!drive) {
46
+ throw new Error(`Drive with id ${driveId} not found`);
47
+ }
48
+ const newDocument = await reactor.queueOperations(driveId, id, operations);
49
+ return newDocument.document;
50
+ }, [documentDrives, isAllowedToEditDocuments, reactor]);
51
+ const addDebouncedOperations = useMemo(() => {
52
+ return debounceOperations((operations) => addOperations(driveId, documentId, operations));
53
+ }, [addOperations, driveId, documentId]);
54
+ return addDebouncedOperations;
55
+ }
@@ -1,4 +1,4 @@
1
- import { DID, IConnectCrypto } from '../crypto';
1
+ import { DID, IConnectCrypto } from "../crypto/index.js";
2
2
  export declare function useConnectCrypto(): IConnectCrypto;
3
3
  export declare function useConnectDid(): DID | undefined;
4
4
  //# sourceMappingURL=useConnectCrypto.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useConnectCrypto.d.ts","sourceRoot":"","sources":["../../../src/hooks/useConnectCrypto.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAiB,MAAM,WAAW,CAAC;AAS/D,wBAAgB,gBAAgB,IAAI,cAAc,CAkBjD;AAID,wBAAgB,aAAa,IAAI,GAAG,GAAG,SAAS,CAc/C"}
1
+ {"version":3,"file":"useConnectCrypto.d.ts","sourceRoot":"","sources":["../../../src/hooks/useConnectCrypto.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,EAAE,cAAc,EAAiB,MAAM,oBAAoB,CAAC;AASxE,wBAAgB,gBAAgB,IAAI,cAAc,CAkBjD;AAID,wBAAgB,aAAa,IAAI,GAAG,GAAG,SAAS,CAc/C"}
@@ -0,0 +1,40 @@
1
+ /* eslint-disable @typescript-eslint/no-floating-promises */
2
+ import { atom, useAtom } from "jotai";
3
+ import { useEffect, useMemo } from "react";
4
+ import { ConnectCrypto } from "../crypto/index.js";
5
+ import { BrowserKeyStorage } from "../crypto/browser.js";
6
+ const connectCrypto = (async () => {
7
+ const connectCrypto = new ConnectCrypto(new BrowserKeyStorage());
8
+ await connectCrypto.did();
9
+ return connectCrypto;
10
+ })();
11
+ export function useConnectCrypto() {
12
+ return useMemo(() => ({
13
+ async regenerateDid() {
14
+ const crypto = await connectCrypto;
15
+ return crypto.regenerateDid();
16
+ },
17
+ async did() {
18
+ const crypto = await connectCrypto;
19
+ return crypto.did();
20
+ },
21
+ sign: async (data) => {
22
+ const crypto = await connectCrypto;
23
+ return await crypto.sign(data);
24
+ },
25
+ }), []);
26
+ }
27
+ const didAtom = atom(undefined);
28
+ export function useConnectDid() {
29
+ const [did, setDid] = useAtom(didAtom);
30
+ useEffect(() => {
31
+ if (did) {
32
+ return;
33
+ }
34
+ connectCrypto
35
+ .then((c) => c.did())
36
+ .then((did) => setDid(did))
37
+ .catch(console.error);
38
+ });
39
+ return did;
40
+ }
@@ -1,9 +1,9 @@
1
- import { Document } from 'document-model/document';
2
- import { IDocumentDriveServer } from 'document-drive/server';
1
+ import { IDocumentDriveServer } from "document-drive";
2
+ import { PHDocument } from "document-model";
3
3
  export type DocumentMeta = {
4
4
  driveId?: string;
5
5
  documentId?: string;
6
6
  documentType?: string;
7
7
  };
8
- export declare function useDocument(reactor: IDocumentDriveServer | undefined, documentMeta?: DocumentMeta): Document | undefined;
8
+ export declare function useDocument(reactor: IDocumentDriveServer | undefined, documentMeta?: DocumentMeta): PHDocument | undefined;
9
9
  //# sourceMappingURL=useDocument.d.ts.map