@live-change/prosemirror-service 0.2.38

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 (4) hide show
  1. package/definition.js +11 -0
  2. package/index.js +120 -0
  3. package/model.js +121 -0
  4. package/package.json +32 -0
package/definition.js ADDED
@@ -0,0 +1,11 @@
1
+ const app = require("@live-change/framework").app()
2
+
3
+ const relationsPlugin = require('@live-change/relations-plugin')
4
+ const userService = require('@live-change/user-service')
5
+
6
+ const definition = app.createServiceDefinition({
7
+ name: "prosemirror",
8
+ use: [ relationsPlugin, userService ]
9
+ })
10
+
11
+ module.exports = definition
package/index.js ADDED
@@ -0,0 +1,120 @@
1
+ const App = require("@live-change/framework")
2
+ const app = App.app()
3
+
4
+ const definition = require('./definition.js')
5
+
6
+ const { Document, StepsBucket, schemas } = require("./model.js")
7
+
8
+ definition.view({
9
+ name: 'document',
10
+ properties: {
11
+ document: {
12
+ type: Document,
13
+ validation: ['nonEmpty']
14
+ }
15
+ },
16
+ returns: {
17
+ type: Document
18
+ },
19
+ daoPath({ document }, { client, context }) {
20
+ return Document.path( document )
21
+ }
22
+ })
23
+
24
+ definition.view({
25
+ name: 'steps',
26
+ properties: {
27
+ document: {
28
+ type: Document,
29
+ validation: ['nonEmpty']
30
+ },
31
+ ...App.rangeProperties
32
+ },
33
+ returns: {
34
+ type: Array,
35
+ of: {
36
+ type: StepsBucket
37
+ }
38
+ },
39
+ daoPath(props, { client, context }) {
40
+ const path = StepsBucket.rangePath([props.document], App.extractRange(props))
41
+ console.log("PATH", path)
42
+ return path
43
+ }
44
+ })
45
+
46
+ definition.action({
47
+ name: 'createDocument',
48
+ waitForEvents: true,
49
+ properties: {
50
+ document: {
51
+ type: String,
52
+ validation: ['nonEmpty']
53
+ },
54
+ type: {
55
+ type: String,
56
+ validation: ['nonEmpty']
57
+ },
58
+ purpose: {
59
+ type: String,
60
+ validation: ['nonEmpty']
61
+ },
62
+ content: {
63
+ type: Object
64
+ }
65
+ },
66
+ async execute({ document, type, purpose, content }, { client, service }, emit) {
67
+ if(!schemas[type]) throw new Error(`schema not found for document type ${type}`)
68
+ const documentData = await Document.get(document)
69
+ if(documentData) throw new Error('document already exists')
70
+ emit({
71
+ type: 'documentCreated',
72
+ document, documentType: type, purpose, content, lastModified: new Date(), created: new Date()
73
+ })
74
+ }
75
+ })
76
+
77
+ definition.action({
78
+ name: 'doSteps',
79
+ waitForEvents: true,
80
+ properties: {
81
+ document: {
82
+ type: String,
83
+ validation: ['nonEmpty']
84
+ },
85
+ type: {
86
+ type: String,
87
+ validation: ['nonEmpty']
88
+ },
89
+ version: {
90
+ type: Number
91
+ },
92
+ steps: {
93
+ type: Array,
94
+ validation: ['nonEmpty']
95
+ },
96
+ window: {
97
+ type: String,
98
+ validation: ['nonEmpty']
99
+ }
100
+ },
101
+ queuedBy: (command) => command.client.document,
102
+ async execute({ document, type, version, steps, window }, { client, service }, emit) {
103
+ if(!schemas[type]) throw new Error(`schema not found for document type ${type}`)
104
+ const documentData = await Document.get(document)
105
+ if(!documentData) throw new Error('document not found')
106
+ if(document.version > version) return 'ignored'
107
+ const [sessionOrUserType, sessionOrUser] =
108
+ client.user ? ['user_User', client.user] : ['session_Session', client.session]
109
+ emit({
110
+ type: 'documentEdited',
111
+ document, documentType: type, version, steps, window,
112
+ sessionOrUserType,
113
+ sessionOrUser,
114
+ timestamp: new Date()
115
+ })
116
+ return 'processed'
117
+ }
118
+ })
119
+
120
+ module.exports = definition
package/model.js ADDED
@@ -0,0 +1,121 @@
1
+ const App = require("@live-change/framework")
2
+ const app = App.app()
3
+ const definition = require('./definition.js')
4
+ const config = definition.config
5
+ const LRU = require('lru-cache')
6
+ const { Schema } = require('prosemirror-model')
7
+ const { Step } = require('prosemirror-transform')
8
+
9
+ const Document = definition.model({
10
+ name: 'Document',
11
+ properties: {
12
+ type: {
13
+ type: String
14
+ },
15
+ purpose: {
16
+ type: String
17
+ },
18
+ version: {
19
+ type: Number
20
+ },
21
+ content: {
22
+ type: Object
23
+ },
24
+ created: {
25
+ type: Date
26
+ },
27
+ lastModified: {
28
+ type: Date
29
+ }
30
+ }
31
+ })
32
+
33
+ const StepsBucket = definition.model({
34
+ name: 'StepsBucket',
35
+ properties: {
36
+ steps: {
37
+ type: Object
38
+ },
39
+ sessionOrUserType: {
40
+ type: String
41
+ },
42
+ sessionOrUser: {
43
+ type: String
44
+ },
45
+ window: {
46
+ type: String
47
+ },
48
+ timestamp: {
49
+ type: Date
50
+ }
51
+ }
52
+ })
53
+
54
+ const schemas = {}
55
+ for(const typeName in config.documentTypes) {
56
+ const spec = config.documentTypes[typeName]
57
+ schemas[typeName] = new Schema(spec)
58
+ }
59
+
60
+ const openDocuments = new LRU({
61
+ max: 500,
62
+ maxSize: 10e6,
63
+ sizeCalculation: (value, key) => value.content.nodeSize,
64
+ ttl: 1000 * 60 * 5,
65
+ })
66
+
67
+ async function getDocument(documentId, documentType) {
68
+ const schema = schemas[documentType]
69
+ if(!schema) throw new Error(`schema not found for document type ${documentType}`)
70
+ let document = openDocuments.get(documentId)
71
+ if(!document) {
72
+ const documentData = await Document.get(documentId)
73
+ if(!documentData) {
74
+ return null
75
+ }
76
+ document = {
77
+ type: documentData.type,
78
+ content: schema.nodeFromJSON(documentData.content),
79
+ version: documentData.version,
80
+ schema
81
+ }
82
+ openDocuments.set(documentId, document)
83
+ }
84
+ if(document.type != documentType) throw new Error("wrong document type!")
85
+ return document
86
+ }
87
+
88
+ definition.event({
89
+ name: "documentCreated",
90
+ async execute({ document, documentType, purpose, content, created, lastModified }) {
91
+ await Document.create({ id: document, type: documentType, purpose, content, created, lastModified, version: 0 })
92
+ }
93
+ })
94
+
95
+ definition.event({
96
+ name: "documentEdited",
97
+ async execute({ document, documentType, version, steps, window, sessionOrUserType, sessionOrUser, timestamp }) {
98
+ const openDocument = await getDocument(document, documentType)
99
+ if(!openDocument) throw new Error('critical error - document not found') /// impossible
100
+ if(openDocument.version != version) return // ignore, client will rebase
101
+ for(const stepJson of steps) {
102
+ const step = Step.fromJSON(openDocument.schema, stepJson)
103
+ openDocument.content = step.apply(openDocument.content).doc
104
+ openDocument.version ++
105
+ }
106
+ await Promise.all([
107
+ Document.update(document, {
108
+ content: openDocument.content.toJSON(),
109
+ version: openDocument.version,
110
+ lastModified: timestamp
111
+ }),
112
+ StepsBucket.create({
113
+ id: App.encodeIdentifier([document, openDocument.version.toFixed().padStart(10, '0')]),
114
+ window, sessionOrUserType, sessionOrUser, timestamp: new Date(),
115
+ steps
116
+ })
117
+ ])
118
+ }
119
+ })
120
+
121
+ module.exports = { Document, StepsBucket, schemas }
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@live-change/prosemirror-service",
3
+ "version": "0.2.38",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "NODE_ENV=test tape tests/*"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/live-change/live-change-services.git"
12
+ },
13
+ "license": "MIT",
14
+ "bugs": {
15
+ "url": "https://github.com/live-change/live-change-services/issues"
16
+ },
17
+ "homepage": "https://github.com/live-change/live-change-services",
18
+ "author": {
19
+ "email": "michal@laszczewski.pl",
20
+ "name": "Michał Łaszczewski",
21
+ "url": "https://www.viamage.com/"
22
+ },
23
+ "dependencies": {
24
+ "@live-change/framework": "0.6.5",
25
+ "@live-change/relations-plugin": "0.6.5",
26
+ "lru-cache": "^7.12.0",
27
+ "pluralize": "8.0.0",
28
+ "progress-stream": "^2.0.0",
29
+ "prosemirror-model": "^1.18.1"
30
+ },
31
+ "gitHead": "d30c93533192fb0d3b620929c61c5d04568beae0"
32
+ }