solid-logic 1.3.17-8a332867 → 1.3.17-a27c1702

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 (122) hide show
  1. package/jest.config.js +1 -1
  2. package/lib/acl/aclLogic.d.ts +12 -30
  3. package/lib/acl/aclLogic.d.ts.map +1 -1
  4. package/lib/acl/aclLogic.js +152 -119
  5. package/lib/acl/aclLogic.js.map +1 -1
  6. package/lib/authn/SolidAuthnLogic.d.ts.map +1 -1
  7. package/lib/authn/SolidAuthnLogic.js +2 -2
  8. package/lib/authn/SolidAuthnLogic.js.map +1 -1
  9. package/lib/chat/chatLogic.d.ts +16 -0
  10. package/lib/chat/chatLogic.d.ts.map +1 -0
  11. package/lib/chat/{ChatLogic.js → chatLogic.js} +82 -87
  12. package/lib/chat/chatLogic.js.map +1 -0
  13. package/lib/inbox/inboxLogic.d.ts +7 -0
  14. package/lib/inbox/inboxLogic.d.ts.map +1 -0
  15. package/lib/inbox/{InboxLogic.js → inboxLogic.js} +58 -64
  16. package/lib/inbox/inboxLogic.js.map +1 -0
  17. package/lib/index.d.ts +18 -9
  18. package/lib/index.d.ts.map +1 -1
  19. package/lib/index.js +86 -34
  20. package/lib/index.js.map +1 -1
  21. package/lib/logic/CustomError.d.ts +4 -0
  22. package/lib/logic/CustomError.d.ts.map +1 -1
  23. package/lib/logic/CustomError.js +17 -1
  24. package/lib/logic/CustomError.js.map +1 -1
  25. package/lib/logic/SolidLogic.d.ts +8 -34
  26. package/lib/logic/SolidLogic.d.ts.map +1 -1
  27. package/lib/logic/SolidLogic.js +16 -250
  28. package/lib/logic/SolidLogic.js.map +1 -1
  29. package/lib/logic/solidLogicSingleton.js +1 -1
  30. package/lib/logic/solidLogicSingleton.js.map +1 -1
  31. package/lib/logic/solidLogicSingletonNew.d.ts +80 -0
  32. package/lib/logic/solidLogicSingletonNew.d.ts.map +1 -0
  33. package/lib/logic/solidLogicSingletonNew.js +238 -0
  34. package/lib/logic/solidLogicSingletonNew.js.map +1 -0
  35. package/lib/profile/profileLogic.d.ts +13 -0
  36. package/lib/profile/profileLogic.d.ts.map +1 -0
  37. package/lib/profile/profileLogic.js +268 -0
  38. package/lib/profile/profileLogic.js.map +1 -0
  39. package/lib/typeIndex/typeIndexLogic.d.ts +31 -21
  40. package/lib/typeIndex/typeIndexLogic.d.ts.map +1 -1
  41. package/lib/typeIndex/typeIndexLogic.js +650 -295
  42. package/lib/typeIndex/typeIndexLogic.js.map +1 -1
  43. package/lib/types.d.ts +17 -0
  44. package/lib/types.d.ts.map +1 -1
  45. package/lib/util/containerLogic.d.ts +11 -0
  46. package/lib/util/containerLogic.d.ts.map +1 -0
  47. package/lib/{profile/ProfileLogic.js → util/containerLogic.js} +53 -44
  48. package/lib/util/containerLogic.js.map +1 -0
  49. package/lib/util/ns.d.ts +2 -0
  50. package/lib/util/ns.d.ts.map +1 -0
  51. package/lib/util/ns.js +34 -0
  52. package/lib/util/ns.js.map +1 -0
  53. package/lib/util/utilityLogic.d.ts +15 -0
  54. package/lib/util/utilityLogic.d.ts.map +1 -0
  55. package/lib/util/utilityLogic.js +272 -0
  56. package/lib/util/utilityLogic.js.map +1 -0
  57. package/lib/util/utils.d.ts +8 -0
  58. package/lib/util/utils.d.ts.map +1 -0
  59. package/lib/util/utils.js +48 -0
  60. package/lib/util/utils.js.map +1 -0
  61. package/package.json +3 -1
  62. package/src/acl/aclLogic.ts +136 -118
  63. package/src/authn/SolidAuthnLogic.ts +3 -2
  64. package/src/chat/chatLogic.ts +225 -0
  65. package/src/inbox/inboxLogic.ts +57 -0
  66. package/src/index.ts +139 -27
  67. package/src/logic/CustomError.ts +5 -1
  68. package/src/logic/SolidLogic.ts +30 -211
  69. package/src/logic/solidLogicSingleton.ts +1 -1
  70. package/src/logic/solidLogicSingletonNew.ts +239 -0
  71. package/src/profile/profileLogic.ts +134 -0
  72. package/src/typeIndex/typeIndexLogic.ts +417 -153
  73. package/src/types.ts +7 -3
  74. package/src/util/containerLogic.ts +54 -0
  75. package/src/util/ns.ts +5 -0
  76. package/src/util/utilityLogic.ts +155 -0
  77. package/src/util/utils.ts +52 -0
  78. package/test/aclLogic.test.ts +13 -4
  79. package/test/chatLogic.test.ts +70 -71
  80. package/test/container.test.ts +56 -0
  81. package/test/helpers/dataSetup.ts +134 -0
  82. package/test/helpers/setup.ts +1 -0
  83. package/test/inboxLogic.test.ts +39 -38
  84. package/test/logic.test.ts +10 -9
  85. package/test/profileLogic.test.ts +246 -0
  86. package/test/typeIndexLogic.test.ts +49 -22
  87. package/test/typeIndexLogicPart2.test.ts +485 -0
  88. package/test/utilityLogic.test.ts +172 -126
  89. package/test/utils.test.ts +32 -0
  90. package/lib/chat/ChatLogic.d.ts +0 -26
  91. package/lib/chat/ChatLogic.d.ts.map +0 -1
  92. package/lib/chat/ChatLogic.js.map +0 -1
  93. package/lib/chat/determineChatContainer.d.ts +0 -3
  94. package/lib/chat/determineChatContainer.d.ts.map +0 -1
  95. package/lib/chat/determineChatContainer.js +0 -12
  96. package/lib/chat/determineChatContainer.js.map +0 -1
  97. package/lib/discovery/discoveryLogic.d.ts +0 -40
  98. package/lib/discovery/discoveryLogic.d.ts.map +0 -1
  99. package/lib/discovery/discoveryLogic.js +0 -494
  100. package/lib/discovery/discoveryLogic.js.map +0 -1
  101. package/lib/inbox/InboxLogic.d.ts +0 -18
  102. package/lib/inbox/InboxLogic.d.ts.map +0 -1
  103. package/lib/inbox/InboxLogic.js.map +0 -1
  104. package/lib/profile/ProfileLogic.d.ts +0 -13
  105. package/lib/profile/ProfileLogic.d.ts.map +0 -1
  106. package/lib/profile/ProfileLogic.js.map +0 -1
  107. package/lib/util/UtilityLogic.d.ts +0 -33
  108. package/lib/util/UtilityLogic.d.ts.map +0 -1
  109. package/lib/util/UtilityLogic.js +0 -240
  110. package/lib/util/UtilityLogic.js.map +0 -1
  111. package/lib/util/uri.d.ts +0 -3
  112. package/lib/util/uri.d.ts.map +0 -1
  113. package/lib/util/uri.js +0 -9
  114. package/lib/util/uri.js.map +0 -1
  115. package/src/chat/ChatLogic.ts +0 -244
  116. package/src/chat/determineChatContainer.ts +0 -14
  117. package/src/discovery/discoveryLogic.ts +0 -310
  118. package/src/inbox/InboxLogic.ts +0 -66
  119. package/src/profile/ProfileLogic.ts +0 -44
  120. package/src/util/UtilityLogic.ts +0 -161
  121. package/src/util/uri.ts +0 -5
  122. package/test/discoveryLogic.test.ts +0 -740
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/util/utils.ts"],"names":[],"mappings":";;;AAAA,iCAAwC;AAExC,SAAgB,QAAQ,CAAC,GAAc;IACnC,OAAO,IAAA,YAAG,EAAC,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC;AAFD,4BAEC;AAED,SAAgB,WAAW,CAAE,GAAgB;IACzC,IAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,GAAG,EAAL,CAAK,CAAC,CAAA;IAChC,IAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAA;IACzB,IAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAC7B,IAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,IAAI,kBAAS,CAAC,CAAC,CAAC,EAAhB,CAAgB,CAAC,CAAA;IAC7C,OAAO,IAAI,CAAA,CAAC,4DAA4D;AAC5E,CAAC;AAND,kCAMC;AAED,SAAgB,aAAa,CAAC,OAAe,EAAE,IAAU;IACrD,IAAM,IAAI,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACnC,IAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,GAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,IAAM,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,IAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAE,CAAC,CAAE,CAAC;IACzC,OAAO,IAAI,GAAG,CAAC,oBAAa,IAAI,cAAI,KAAK,cAAI,GAAG,cAAI,QAAQ,CAAE,EAAE,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC;AACxF,CAAC;AAPD,sCAOC;AAED,SAAgB,eAAe,CAAC,GAAG;IAC/B,IAAI,CAAC,GAAG,EAAE;QACN,OAAO,IAAI,CAAC;KACf;IACD,OAAO,CACH,UAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,MAAG,KAAK,IAAI,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAC7D,CAAC;AACN,CAAC;AAPD,0CAOC;AAED,SAAgB,sBAAsB,CAAE,EAAY;IAChD,IAAM,QAAQ,GAAG,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;IAC1E,uFAAuF;IACvF,IAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,YAAY,CAAA;IAC1E,IAAM,OAAO,GAAG,SAAS,GAAG,iBAAiB,CAAA;IAC7C,OAAO,IAAA,YAAG,EAAC,OAAO,CAAC,CAAA;AACvB,CAAC;AAND,wDAMC;AAED,SAAgB,sBAAsB,CAClC,OAAkB,EAClB,OAAkB;IAElB,cAAc;IACd,mEAAmE;IACnE,IAAM,gBAAgB,GAAG,IAAI,GAAG,CAC5B,0BAAmB,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,MAAG,EACjD,OAAO,CAAC,KAAK,CAChB,CAAC,QAAQ,EAAE,CAAC;IACb,OAAO,IAAI,kBAAS,CAAC,gBAAgB,CAAC,CAAC;AAC3C,CAAC;AAXD,wDAWC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "solid-logic",
3
- "version": "1.3.17-8a332867",
3
+ "version": "1.3.17-a27c1702",
4
4
  "description": "Core business logic of Solid OS",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -8,6 +8,7 @@
8
8
  "clean": "rm -rf lib",
9
9
  "lint": "eslint ./src",
10
10
  "test": "jest",
11
+ "test-debug": "node --inspect-brk ./node_modules/.bin/jest -i --env jest-environment-node-debug",
11
12
  "preversion": "npm test",
12
13
  "postversion": "git push --follow-tags",
13
14
  "ignore:prepublishOnly": "npm run build",
@@ -35,6 +36,7 @@
35
36
  "@typescript-eslint/parser": "^5.19.0",
36
37
  "eslint": "^8.13.0",
37
38
  "jest": "^27.5.1",
39
+ "jest-environment-node-debug": "^2.0.0",
38
40
  "jest-fetch-mock": "^3.0.3",
39
41
  "typescript": "^4.6.3"
40
42
  },
@@ -1,137 +1,155 @@
1
- /**
2
- * Simple Access Control
3
- *
4
- * This function sets up a simple default ACL for a resource, with
5
- * RWC for the owner, and a specified access (default none) for the public.
6
- * In all cases owner has read write control.
7
- * Parameter lists modes allowed to public
8
- *
9
- * @param options
10
- * @param options.public eg ['Read', 'Write']
11
- *
12
- * @returns Resolves with aclDoc uri on successful write
13
- */
1
+ import { graph, NamedNode, Namespace, serialize, sym } from "rdflib"
2
+ import { ns as namespace } from '../util/ns'
14
3
 
15
- import { graph, NamedNode, Namespace, serialize } from "rdflib"
16
- import solidNamespace from 'solid-namespace'
17
- import * as $rdf from 'rdflib'
18
- import { solidLogicSingleton } from "../logic/solidLogicSingleton"
19
- import { ACL_LINK } from "../util/UtilityLogic"
20
4
 
21
- export const ns = solidNamespace($rdf)
5
+ export const ACL_LINK = sym(
6
+ "http://www.iana.org/assignments/link-relations/acl"
7
+ );
22
8
 
23
- export function setACLUserPublic (
24
- docURI: string,
25
- me: NamedNode,
26
- options: {
27
- defaultForNew?: boolean,
28
- public?: []
29
- }
30
- ): Promise<NamedNode> {
31
- const aclDoc = solidLogicSingleton.store.any(
32
- solidLogicSingleton.store.sym(docURI),
33
- ACL_LINK
34
- )
9
+ export function createAclLogic(store) {
35
10
 
36
- return Promise.resolve()
37
- .then(() => {
38
- if (aclDoc) {
39
- return aclDoc as NamedNode
11
+ const ns = namespace
12
+
13
+ async function findAclDocUrl(url: string) {
14
+ const doc = store.sym(url);
15
+ await store.fetcher.load(doc);
16
+ const docNode = store.any(doc, ACL_LINK);
17
+ if (!docNode) {
18
+ throw new Error(`No ACL link discovered for ${url}`);
19
+ }
20
+ return docNode.value;
40
21
  }
41
-
42
- return fetchACLRel(docURI).catch(err => {
43
- throw new Error(`Error fetching rel=ACL header for ${docURI}: ${err}`)
44
- })
45
- })
46
- .then(aclDoc => {
47
- const aclText = genACLText(docURI, me, aclDoc.uri, options)
48
- if (!solidLogicSingleton.store.fetcher) {
49
- throw new Error('Cannot PUT this, store has no fetcher')
22
+ /**
23
+ * Simple Access Control
24
+ *
25
+ * This function sets up a simple default ACL for a resource, with
26
+ * RWC for the owner, and a specified access (default none) for the public.
27
+ * In all cases owner has read write control.
28
+ * Parameter lists modes allowed to public
29
+ *
30
+ * @param options
31
+ * @param options.public eg ['Read', 'Write']
32
+ *
33
+ * @returns Resolves with aclDoc uri on successful write
34
+ */
35
+ function setACLUserPublic (
36
+ docURI: string,
37
+ me: NamedNode,
38
+ options: {
39
+ defaultForNew?: boolean,
40
+ public?: []
50
41
  }
51
- return solidLogicSingleton.store.fetcher
52
- .webOperation('PUT', aclDoc.uri, {
53
- data: aclText,
54
- contentType: 'text/turtle'
55
- })
56
- .then(result => {
57
- if (!result.ok) {
58
- throw new Error('Error writing ACL text: ' + result.error)
42
+ ): Promise<NamedNode> {
43
+ const aclDoc = store.any(
44
+ store.sym(docURI),
45
+ ACL_LINK
46
+ )
47
+
48
+ return Promise.resolve()
49
+ .then(() => {
50
+ if (aclDoc) {
51
+ return aclDoc as NamedNode
59
52
  }
60
53
 
61
- return aclDoc
54
+ return fetchACLRel(docURI).catch(err => {
55
+ throw new Error(`Error fetching rel=ACL header for ${docURI}: ${err}`)
56
+ })
62
57
  })
63
- })
64
- }
58
+ .then(aclDoc => {
59
+ const aclText = genACLText(docURI, me, aclDoc.uri, options)
60
+ if (!store.fetcher) {
61
+ throw new Error('Cannot PUT this, store has no fetcher')
62
+ }
63
+ return store.fetcher
64
+ .webOperation('PUT', aclDoc.uri, {
65
+ data: aclText,
66
+ contentType: 'text/turtle'
67
+ })
68
+ .then(result => {
69
+ if (!result.ok) {
70
+ throw new Error('Error writing ACL text: ' + result.error)
71
+ }
65
72
 
66
- /**
67
- * @param docURI
68
- * @returns
69
- */
70
- function fetchACLRel (docURI: string): Promise<NamedNode> {
71
- const fetcher = solidLogicSingleton.store.fetcher
72
- if (!fetcher) {
73
- throw new Error('Cannot fetch ACL rel, store has no fetcher')
73
+ return aclDoc
74
+ })
75
+ })
74
76
  }
75
77
 
76
- return fetcher.load(docURI).then(result => {
77
- if (!result.ok) {
78
- throw new Error('fetchACLRel: While loading:' + (result as any).error)
78
+ /**
79
+ * @param docURI
80
+ * @returns
81
+ */
82
+ function fetchACLRel (docURI: string): Promise<NamedNode> {
83
+ const fetcher = store.fetcher
84
+ if (!fetcher) {
85
+ throw new Error('Cannot fetch ACL rel, store has no fetcher')
79
86
  }
80
87
 
81
- const aclDoc = solidLogicSingleton.store.any(
82
- solidLogicSingleton.store.sym(docURI),
83
- ACL_LINK
84
- )
88
+ return fetcher.load(docURI).then(result => {
89
+ if (!result.ok) {
90
+ throw new Error('fetchACLRel: While loading:' + (result as any).error)
91
+ }
85
92
 
86
- if (!aclDoc) {
87
- throw new Error('fetchACLRel: No Link rel=ACL header for ' + docURI)
88
- }
93
+ const aclDoc = store.any(
94
+ store.sym(docURI),
95
+ ACL_LINK
96
+ )
89
97
 
90
- return aclDoc as NamedNode
91
- })
92
- }
98
+ if (!aclDoc) {
99
+ throw new Error('fetchACLRel: No Link rel=ACL header for ' + docURI)
100
+ }
101
+
102
+ return aclDoc as NamedNode
103
+ })
104
+ }
93
105
 
94
- /**
95
- * @param docURI
96
- * @param me
97
- * @param aclURI
98
- * @param options
99
- *
100
- * @returns Serialized ACL
101
- */
102
- export function genACLText (
103
- docURI: string,
104
- me: NamedNode,
105
- aclURI: string,
106
- options: {
107
- defaultForNew?: boolean,
108
- public?: []
109
- } = {}
110
- ): string | undefined {
111
- const optPublic = options.public || []
112
- const g = graph()
113
- const auth = Namespace('http://www.w3.org/ns/auth/acl#')
114
- let a = g.sym(`${aclURI}#a1`)
115
- const acl = g.sym(aclURI)
116
- const doc = g.sym(docURI)
117
- g.add(a, ns.rdf('type'), auth('Authorization'), acl)
118
- g.add(a, auth('accessTo'), doc, acl)
119
- if (options.defaultForNew) {
120
- g.add(a, auth('default'), doc, acl)
121
- }
122
- g.add(a, auth('agent'), me, acl)
123
- g.add(a, auth('mode'), auth('Read'), acl)
124
- g.add(a, auth('mode'), auth('Write'), acl)
125
- g.add(a, auth('mode'), auth('Control'), acl)
106
+ /**
107
+ * @param docURI
108
+ * @param me
109
+ * @param aclURI
110
+ * @param options
111
+ *
112
+ * @returns Serialized ACL
113
+ */
114
+ function genACLText (
115
+ docURI: string,
116
+ me: NamedNode,
117
+ aclURI: string,
118
+ options: {
119
+ defaultForNew?: boolean,
120
+ public?: []
121
+ } = {}
122
+ ): string | undefined {
123
+ const optPublic = options.public || []
124
+ const g = graph()
125
+ const auth = Namespace('http://www.w3.org/ns/auth/acl#')
126
+ let a = g.sym(`${aclURI}#a1`)
127
+ const acl = g.sym(aclURI)
128
+ const doc = g.sym(docURI)
129
+ g.add(a, ns.rdf('type'), auth('Authorization'), acl)
130
+ g.add(a, auth('accessTo'), doc, acl)
131
+ if (options.defaultForNew) {
132
+ g.add(a, auth('default'), doc, acl)
133
+ }
134
+ g.add(a, auth('agent'), me, acl)
135
+ g.add(a, auth('mode'), auth('Read'), acl)
136
+ g.add(a, auth('mode'), auth('Write'), acl)
137
+ g.add(a, auth('mode'), auth('Control'), acl)
126
138
 
127
- if (optPublic.length) {
128
- a = g.sym(`${aclURI}#a2`)
129
- g.add(a, ns.rdf('type'), auth('Authorization'), acl)
130
- g.add(a, auth('accessTo'), doc, acl)
131
- g.add(a, auth('agentClass'), ns.foaf('Agent'), acl)
132
- for (let p = 0; p < optPublic.length; p++) {
133
- g.add(a, auth('mode'), auth(optPublic[p]), acl) // Like 'Read' etc
139
+ if (optPublic.length) {
140
+ a = g.sym(`${aclURI}#a2`)
141
+ g.add(a, ns.rdf('type'), auth('Authorization'), acl)
142
+ g.add(a, auth('accessTo'), doc, acl)
143
+ g.add(a, auth('agentClass'), ns.foaf('Agent'), acl)
144
+ for (let p = 0; p < optPublic.length; p++) {
145
+ g.add(a, auth('mode'), auth(optPublic[p]), acl) // Like 'Read' etc
146
+ }
147
+ }
148
+ return serialize(acl, g, aclURI)
149
+ }
150
+ return {
151
+ findAclDocUrl,
152
+ setACLUserPublic,
153
+ genACLText
134
154
  }
135
- }
136
- return serialize(acl, g, aclURI)
137
- }
155
+ }
@@ -3,6 +3,7 @@ import { appContext, offlineTestID } from "./authUtil";
3
3
  import * as debug from '../util/debug'
4
4
  import { Session } from "@inrupt/solid-client-authn-browser";
5
5
  import { AuthenticationContext, AuthnLogic } from "../types";
6
+
6
7
  export class SolidAuthnLogic implements AuthnLogic {
7
8
  private session: Session;
8
9
 
@@ -58,10 +59,10 @@ export class SolidAuthnLogic implements AuthnLogic {
58
59
  const curUrl = new URL(window.location.href)
59
60
  if (curUrl.hash !== postLoginRedirectHash) {
60
61
  if (history.pushState) {
61
- // console.log('Setting window.location.has using pushState')
62
+ // debug.log('Setting window.location.has using pushState')
62
63
  history.pushState(null, document.title, postLoginRedirectHash)
63
64
  } else {
64
- // console.warn('Setting window.location.has using location.hash')
65
+ // debug.warn('Setting window.location.has using location.hash')
65
66
  location.hash = postLoginRedirectHash
66
67
  }
67
68
  curUrl.hash = postLoginRedirectHash
@@ -0,0 +1,225 @@
1
+ import { NamedNode, Node, st, term } from "rdflib"
2
+ import { CreatedPaneOptions, NewPaneOptions } from "../types"
3
+ import { determineChatContainer, newThing } from "../util/utils"
4
+ import { ns as namespace } from '../util/ns'
5
+
6
+ const CHAT_LOCATION_IN_CONTAINER = "index.ttl#this";
7
+
8
+ export function createChatLogic(store, profileLogic) {
9
+ const ns = namespace
10
+
11
+ async function setAcl(
12
+ chatContainer: NamedNode,
13
+ me: NamedNode,
14
+ invitee: NamedNode
15
+ ): Promise<void> {
16
+ // Some servers don't present a Link http response header
17
+ // if the container doesn't exist yet, so refetch the container
18
+ // now that it has been created:
19
+ await store.fetcher.load(chatContainer);
20
+
21
+ // FIXME: check the Why value on this quad:
22
+ const chatAclDoc = store.any(
23
+ chatContainer,
24
+ new NamedNode("http://www.iana.org/assignments/link-relations/acl")
25
+ );
26
+ if (!chatAclDoc) {
27
+ throw new Error("Chat ACL doc not found!");
28
+ }
29
+
30
+ const aclBody = `
31
+ @prefix acl: <http://www.w3.org/ns/auth/acl#>.
32
+ <#owner>
33
+ a acl:Authorization;
34
+ acl:agent <${me.value}>;
35
+ acl:accessTo <.>;
36
+ acl:default <.>;
37
+ acl:mode
38
+ acl:Read, acl:Write, acl:Control.
39
+ <#invitee>
40
+ a acl:Authorization;
41
+ acl:agent <${invitee.value}>;
42
+ acl:accessTo <.>;
43
+ acl:default <.>;
44
+ acl:mode
45
+ acl:Read, acl:Append.
46
+ `;
47
+ await store.fetcher.webOperation("PUT", chatAclDoc.value, {
48
+ data: aclBody,
49
+ contentType: "text/turtle",
50
+ });
51
+ }
52
+
53
+ async function addToPrivateTypeIndex(chatThing, me) {
54
+ // Add to private type index
55
+ const privateTypeIndex = store.any(
56
+ me,
57
+ ns.solid("privateTypeIndex")
58
+ ) as NamedNode | null;
59
+ if (!privateTypeIndex) {
60
+ throw new Error("Private type index not found!");
61
+ }
62
+ await store.fetcher.load(privateTypeIndex);
63
+ const reg = newThing(privateTypeIndex);
64
+ const ins = [
65
+ st(
66
+ reg,
67
+ ns.rdf("type"),
68
+ ns.solid("TypeRegistration"),
69
+ privateTypeIndex.doc()
70
+ ),
71
+ st(
72
+ reg,
73
+ ns.solid("forClass"),
74
+ ns.meeting("LongChat"),
75
+ privateTypeIndex.doc()
76
+ ),
77
+ st(reg, ns.solid("instance"), chatThing, privateTypeIndex.doc()),
78
+ ];
79
+ await new Promise((resolve, reject) => {
80
+ store.updater.update([], ins, function (_uri, ok, errm) {
81
+ if (!ok) {
82
+ reject(new Error(errm));
83
+ } else {
84
+ resolve(null);
85
+ }
86
+ });
87
+ });
88
+ }
89
+
90
+ async function findChat(invitee: NamedNode) {
91
+ const me = await profileLogic.loadMe();
92
+ const podRoot = await profileLogic.getPodRoot(me);
93
+ const chatContainer = determineChatContainer(invitee, podRoot);
94
+ let exists = true;
95
+ try {
96
+ await store.fetcher.load(
97
+ new NamedNode(chatContainer.value + "index.ttl#this")
98
+ );
99
+ } catch (e) {
100
+ exists = false;
101
+ }
102
+ return { me, chatContainer, exists };
103
+ }
104
+
105
+ async function createChatThing(
106
+ chatContainer: NamedNode,
107
+ me: NamedNode
108
+ ): Promise<NamedNode> {
109
+ const created = await mintNew({
110
+ me,
111
+ newBase: chatContainer.value,
112
+ });
113
+ return created.newInstance;
114
+ }
115
+
116
+ function mintNew(newPaneOptions: NewPaneOptions): Promise<CreatedPaneOptions> {
117
+ const kb = store;
118
+ const updater = kb.updater;
119
+ if (newPaneOptions.me && !newPaneOptions.me.uri) {
120
+ throw new Error("chat mintNew: Invalid userid " + newPaneOptions.me);
121
+ }
122
+
123
+ const newInstance = (newPaneOptions.newInstance =
124
+ newPaneOptions.newInstance ||
125
+ kb.sym(newPaneOptions.newBase + CHAT_LOCATION_IN_CONTAINER));
126
+ const newChatDoc = newInstance.doc();
127
+
128
+ kb.add(
129
+ newInstance,
130
+ ns.rdf("type"),
131
+ ns.meeting("LongChat"),
132
+ newChatDoc
133
+ );
134
+ kb.add(newInstance, ns.dc("title"), "Chat channel", newChatDoc);
135
+ kb.add(
136
+ newInstance,
137
+ ns.dc("created"),
138
+ term<Node>(new Date(Date.now())),
139
+ newChatDoc
140
+ );
141
+ if (newPaneOptions.me) {
142
+ kb.add(newInstance, ns.dc("author"), newPaneOptions.me, newChatDoc);
143
+ }
144
+
145
+ return new Promise(function (resolve, reject) {
146
+ updater?.put(
147
+ newChatDoc,
148
+ kb.statementsMatching(undefined, undefined, undefined, newChatDoc),
149
+ "text/turtle",
150
+ function (uri2, ok, message) {
151
+ if (ok) {
152
+ resolve({
153
+ ...newPaneOptions,
154
+ newInstance,
155
+ });
156
+ } else {
157
+ reject(
158
+ new Error(
159
+ "FAILED to save new chat channel at: " + uri2 + " : " + message
160
+ )
161
+ );
162
+ }
163
+ }
164
+ );
165
+ });
166
+ }
167
+
168
+ /**
169
+ * Find (and optionally create) an individual chat between the current user and the given invitee
170
+ * @param invitee - The person to chat with
171
+ * @param createIfMissing - Whether the chat should be created, if missing
172
+ * @returns null if missing, or a node referring to an already existing chat, or the newly created chat
173
+ */
174
+ async function getChat(
175
+ invitee: NamedNode,
176
+ createIfMissing = true
177
+ ): Promise<NamedNode | null> {
178
+ const { me, chatContainer, exists } = await findChat(invitee);
179
+ if (exists) {
180
+ return new NamedNode(chatContainer.value + CHAT_LOCATION_IN_CONTAINER);
181
+ }
182
+
183
+ if (createIfMissing) {
184
+ const chatThing = await createChatThing(chatContainer, me);
185
+ await sendInvite(invitee, chatThing);
186
+ await setAcl(chatContainer, me, invitee);
187
+ await addToPrivateTypeIndex(chatThing, me);
188
+ return chatThing;
189
+ }
190
+ return null;
191
+ }
192
+
193
+ async function sendInvite(invitee: NamedNode, chatThing: NamedNode) {
194
+ await store.fetcher.load(invitee.doc());
195
+ const inviteeInbox = store.any(
196
+ invitee,
197
+ ns.ldp("inbox"),
198
+ undefined,
199
+ invitee.doc()
200
+ );
201
+ if (!inviteeInbox) {
202
+ throw new Error(`Invitee inbox not found! ${invitee.value}`);
203
+ }
204
+ const inviteBody = `
205
+ <> a <http://www.w3.org/ns/pim/meeting#LongChatInvite> ;
206
+ ${ns.rdf("seeAlso")} <${chatThing.value}> .
207
+ `;
208
+
209
+ const inviteResponse = await store.fetcher.webOperation(
210
+ "POST",
211
+ inviteeInbox.value,
212
+ {
213
+ data: inviteBody,
214
+ contentType: "text/turtle",
215
+ }
216
+ );
217
+ const locationStr = inviteResponse?.headers.get("location");
218
+ if (!locationStr) {
219
+ throw new Error(`Invite sending returned a ${inviteResponse?.status}`);
220
+ }
221
+ }
222
+ return {
223
+ setAcl, addToPrivateTypeIndex, findChat, createChatThing, getChat, sendInvite, mintNew
224
+ }
225
+ }
@@ -0,0 +1,57 @@
1
+ import { NamedNode } from "rdflib";
2
+ import { getArchiveUrl } from "../util/utils";
3
+
4
+ export function createInboxLogic(store, profileLogic, utilityLogic, containerLogic, aclLogic) {
5
+
6
+ async function createInboxFor(peerWebId: string, nick: string) {
7
+ const myWebId: NamedNode = await profileLogic.loadMe();
8
+ const podRoot: NamedNode = await profileLogic.getPodRoot(myWebId);
9
+ const ourInbox = `${podRoot.value}p2p-inboxes/${encodeURIComponent(nick)}/`;
10
+ await containerLogic.createContainer(ourInbox);
11
+ const aclDocUrl = await aclLogic.findAclDocUrl(ourInbox);
12
+ await utilityLogic.setSinglePeerAccess({
13
+ ownerWebId: myWebId.value,
14
+ peerWebId,
15
+ accessToModes: 'acl:Append',
16
+ target: ourInbox
17
+ });
18
+ return ourInbox;
19
+ }
20
+
21
+ async function getNewMessages(
22
+ user?: NamedNode
23
+ ): Promise<string[]> {
24
+ if (!user) {
25
+ user = await profileLogic.loadMe();
26
+ }
27
+ const inbox = await profileLogic.getMainInbox(user);
28
+ const urls = await containerLogic.getContainerMembers(inbox.value);
29
+ return urls.filter(url => !containerLogic.isContainer(url));
30
+ }
31
+
32
+ async function markAsRead(url: string, date: Date) {
33
+ const downloaded = await store.fetcher._fetch(url);
34
+ if (downloaded.status !== 200) {
35
+ throw new Error(`Not OK! ${url}`);
36
+ }
37
+ const archiveUrl = getArchiveUrl(url, date);
38
+ const options = {
39
+ method: 'PUT',
40
+ body: await downloaded.text(),
41
+ headers: [
42
+ ['Content-Type', downloaded.headers.get('Content-Type') || 'application/octet-stream']
43
+ ]
44
+ };
45
+ const uploaded = await store.fetcher._fetch(archiveUrl, options);
46
+ if (uploaded.status.toString()[0] === '2') {
47
+ await store.fetcher._fetch(url, {
48
+ method: 'DELETE'
49
+ });
50
+ }
51
+ }
52
+ return {
53
+ createInboxFor,
54
+ getNewMessages,
55
+ markAsRead
56
+ }
57
+ }