@powerhousedao/reactor-browser 1.10.2 → 1.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +47 -0
- package/dist/src/context/index.d.ts +1 -1
- package/dist/src/context/index.d.ts.map +1 -1
- package/dist/src/context/index.js +1 -0
- package/dist/src/context/read-mode.d.ts +3 -3
- package/dist/src/context/read-mode.d.ts.map +1 -1
- package/dist/src/context/read-mode.js +198 -0
- package/dist/src/crypto/browser.d.ts +1 -1
- package/dist/src/crypto/browser.d.ts.map +1 -1
- package/dist/src/crypto/browser.js +49 -0
- package/dist/src/crypto/index.js +121 -0
- package/dist/src/document-model.d.ts +3 -3
- package/dist/src/document-model.d.ts.map +1 -1
- package/dist/src/document-model.js +5 -0
- package/dist/src/hooks/index.d.ts +9 -5
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +9 -0
- package/dist/src/hooks/useAddDebouncedOperations.d.ts +3 -3
- package/dist/src/hooks/useAddDebouncedOperations.d.ts.map +1 -1
- package/dist/src/hooks/useAddDebouncedOperations.js +55 -0
- package/dist/src/hooks/useConnectCrypto.d.ts +1 -1
- package/dist/src/hooks/useConnectCrypto.d.ts.map +1 -1
- package/dist/src/hooks/useConnectCrypto.js +40 -0
- package/dist/src/hooks/useDocument.d.ts +3 -3
- package/dist/src/hooks/useDocument.d.ts.map +1 -1
- package/dist/src/hooks/useDocument.js +37 -0
- package/dist/src/hooks/useDocumentDispatch.d.ts +6 -10
- package/dist/src/hooks/useDocumentDispatch.d.ts.map +1 -1
- package/dist/src/hooks/useDocumentDispatch.js +41 -0
- package/dist/src/hooks/useDocumentDrives.d.ts +4 -3
- package/dist/src/hooks/useDocumentDrives.d.ts.map +1 -1
- package/dist/src/hooks/useDocumentDrives.js +84 -0
- package/dist/src/hooks/useDocumentEditor.d.ts +13 -13
- package/dist/src/hooks/useDocumentEditor.d.ts.map +1 -1
- package/dist/src/hooks/useDocumentEditor.js +30 -0
- package/dist/src/hooks/useDriveActions.d.ts +82 -0
- package/dist/src/hooks/useDriveActions.d.ts.map +1 -0
- package/dist/src/hooks/useDriveActions.js +125 -0
- package/dist/src/hooks/useDriveActionsWithUiNodes.d.ts +17 -0
- package/dist/src/hooks/useDriveActionsWithUiNodes.d.ts.map +1 -0
- package/dist/src/hooks/useDriveActionsWithUiNodes.js +71 -0
- package/dist/src/hooks/useDriveContext.d.ts +66 -0
- package/dist/src/hooks/useDriveContext.d.ts.map +1 -0
- package/dist/src/hooks/useDriveContext.js +25 -0
- package/dist/src/hooks/useUiNodesContext.d.ts +25 -0
- package/dist/src/hooks/useUiNodesContext.d.ts.map +1 -0
- package/dist/src/hooks/useUiNodesContext.js +167 -0
- package/dist/src/hooks/useUserPermissions.js +6 -0
- package/dist/src/index.d.ts +5 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/reactor.d.ts +3 -3
- package/dist/src/reactor.d.ts.map +1 -1
- package/dist/src/reactor.js +54 -0
- package/dist/src/renown/constants.js +39 -0
- package/dist/src/renown/types.d.ts +3 -3
- package/dist/src/renown/types.d.ts.map +1 -1
- package/dist/src/renown/types.js +1 -0
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.d.ts.map +1 -1
- package/dist/src/storage/index.js +1 -0
- package/dist/src/storage/types.js +1 -0
- package/dist/src/uiNodes/constants.d.ts +17 -0
- package/dist/src/uiNodes/constants.d.ts.map +1 -0
- package/dist/src/uiNodes/constants.js +23 -0
- package/dist/src/uiNodes/types.d.ts +61 -0
- package/dist/src/uiNodes/types.d.ts.map +1 -0
- package/dist/src/uiNodes/types.js +1 -0
- package/dist/src/utils/index.d.ts +3 -3
- package/dist/src/utils/index.d.ts.map +1 -1
- package/dist/src/utils/index.js +8 -0
- package/dist/src/utils/signature.d.ts +3 -3
- package/dist/src/utils/signature.d.ts.map +1 -1
- package/dist/src/utils/signature.js +39 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +15 -22
- package/dist/_virtual/__vite-browser-external.js +0 -5
- package/dist/_virtual/__vite-browser-external.js.map +0 -1
- package/dist/context/read-mode.js +0 -159
- package/dist/context/read-mode.js.map +0 -1
- package/dist/crypto/browser.js +0 -50
- package/dist/crypto/browser.js.map +0 -1
- package/dist/crypto/index.js +0 -109
- package/dist/crypto/index.js.map +0 -1
- package/dist/document-model.js +0 -11
- package/dist/document-model.js.map +0 -1
- package/dist/hooks/useAddDebouncedOperations.js +0 -54
- package/dist/hooks/useAddDebouncedOperations.js.map +0 -1
- package/dist/hooks/useConnectCrypto.js +0 -34
- package/dist/hooks/useConnectCrypto.js.map +0 -1
- package/dist/hooks/useDocument.js +0 -20
- package/dist/hooks/useDocument.js.map +0 -1
- package/dist/hooks/useDocumentDispatch.js +0 -30
- package/dist/hooks/useDocumentDispatch.js.map +0 -1
- package/dist/hooks/useDocumentDrives.js +0 -86
- package/dist/hooks/useDocumentDrives.js.map +0 -1
- package/dist/hooks/useDocumentEditor.js +0 -46
- package/dist/hooks/useDocumentEditor.js.map +0 -1
- package/dist/hooks/useUserPermissions.js +0 -10
- package/dist/hooks/useUserPermissions.js.map +0 -1
- package/dist/index.js +0 -26
- package/dist/index.js.map +0 -1
- package/dist/reactor.js +0 -59
- package/dist/reactor.js.map +0 -1
- package/dist/utils/index.js +0 -16
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/signature.js +0 -35
- package/dist/utils/signature.js.map +0 -1
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@powerhousedao/reactor-browser",
|
|
3
|
+
"version": "1.11.0",
|
|
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
|
|
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,
|
|
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
|
|
2
|
-
import { FC, ReactNode } from
|
|
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(
|
|
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,
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/crypto/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,
|
|
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 {
|
|
2
|
-
export declare const baseDocumentModelsMap: Record<string,
|
|
3
|
-
export declare const baseDocumentModels:
|
|
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":"
|
|
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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
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,
|
|
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 {
|
|
2
|
-
import { IDocumentDriveServer } from
|
|
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<
|
|
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":"
|
|
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
|
|
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,
|
|
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 {
|
|
2
|
-
import {
|
|
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):
|
|
8
|
+
export declare function useDocument(reactor: IDocumentDriveServer | undefined, documentMeta?: DocumentMeta): PHDocument | undefined;
|
|
9
9
|
//# sourceMappingURL=useDocument.d.ts.map
|