solid-logic 6.0.1-1 → 6.0.1-4

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 (103) hide show
  1. package/dist/acl/accessControlSubjects.cjs.js +1 -1
  2. package/dist/acl/accessControlSubjects.cjs.js.map +1 -1
  3. package/dist/acl/accessControlSubjects.d.ts.map +1 -1
  4. package/dist/acl/accessControlSubjects.esm.js +38 -37
  5. package/dist/acl/accessControlSubjects.esm.js.map +1 -1
  6. package/dist/acl/aclLogic.cjs.js +1 -1
  7. package/dist/acl/aclLogic.cjs.js.map +1 -1
  8. package/dist/acl/aclLogic.d.ts +23 -1
  9. package/dist/acl/aclLogic.d.ts.map +1 -1
  10. package/dist/acl/aclLogic.esm.js +341 -69
  11. package/dist/acl/aclLogic.esm.js.map +1 -1
  12. package/dist/authSession/authSession.cjs.js.map +1 -1
  13. package/dist/authSession/authSession.esm.js.map +1 -1
  14. package/dist/authSession/events.cjs.js.map +1 -1
  15. package/dist/authSession/events.esm.js.map +1 -1
  16. package/dist/authSession/flagAuthorizationOnTransitions.cjs.js.map +1 -1
  17. package/dist/authSession/flagAuthorizationOnTransitions.esm.js.map +1 -1
  18. package/dist/authSession/identityState.cjs.js +1 -1
  19. package/dist/authSession/identityState.cjs.js.map +1 -1
  20. package/dist/authSession/identityState.esm.js +3 -17
  21. package/dist/authSession/identityState.esm.js.map +1 -1
  22. package/dist/authSession/issuer.cjs.js.map +1 -1
  23. package/dist/authSession/issuer.esm.js.map +1 -1
  24. package/dist/authSession/session.cjs.js.map +1 -1
  25. package/dist/authSession/session.esm.js.map +1 -1
  26. package/dist/authn/SolidAuthnLogic.cjs.js.map +1 -1
  27. package/dist/authn/SolidAuthnLogic.esm.js.map +1 -1
  28. package/dist/authn/authUtil.cjs.js.map +1 -1
  29. package/dist/authn/authUtil.esm.js.map +1 -1
  30. package/dist/authn/serverLogout.cjs.js.map +1 -1
  31. package/dist/authn/serverLogout.esm.js.map +1 -1
  32. package/dist/chat/chatLogic.cjs.js.map +1 -1
  33. package/dist/chat/chatLogic.esm.js.map +1 -1
  34. package/dist/directory/catalogDirectory.cjs.js.map +1 -1
  35. package/dist/directory/catalogDirectory.esm.js.map +1 -1
  36. package/dist/directory/contactsDirectory.cjs.js.map +1 -1
  37. package/dist/directory/contactsDirectory.esm.js.map +1 -1
  38. package/dist/directory/directoryHelpers.cjs.js.map +1 -1
  39. package/dist/directory/directoryHelpers.esm.js.map +1 -1
  40. package/dist/directory/directoryLogic.cjs.js.map +1 -1
  41. package/dist/directory/directoryLogic.esm.js.map +1 -1
  42. package/dist/directory/friendsDirectory.cjs.js.map +1 -1
  43. package/dist/directory/friendsDirectory.esm.js.map +1 -1
  44. package/dist/inbox/inboxLogic.cjs.js.map +1 -1
  45. package/dist/inbox/inboxLogic.esm.js.map +1 -1
  46. package/dist/index.cjs.js +1 -1
  47. package/dist/index.cjs.js.map +1 -1
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.esm.js +10 -10
  51. package/dist/index.esm.js.map +1 -1
  52. package/dist/issuer/issuerLogic.cjs.js.map +1 -1
  53. package/dist/issuer/issuerLogic.esm.js.map +1 -1
  54. package/dist/logic/CustomError.cjs.js.map +1 -1
  55. package/dist/logic/CustomError.esm.js.map +1 -1
  56. package/dist/logic/solidLogic.cjs.js.map +1 -1
  57. package/dist/logic/solidLogic.esm.js.map +1 -1
  58. package/dist/logic/solidLogicSingleton.cjs.js +1 -1
  59. package/dist/logic/solidLogicSingleton.cjs.js.map +1 -1
  60. package/dist/logic/solidLogicSingleton.esm.js +1 -1
  61. package/dist/logic/solidLogicSingleton.esm.js.map +1 -1
  62. package/dist/profile/profileAclDocuments.cjs.js.map +1 -1
  63. package/dist/profile/profileAclDocuments.esm.js.map +1 -1
  64. package/dist/profile/profileDocuments.cjs.js.map +1 -1
  65. package/dist/profile/profileDocuments.esm.js.map +1 -1
  66. package/dist/profile/profileLogic.cjs.js.map +1 -1
  67. package/dist/profile/profileLogic.esm.js.map +1 -1
  68. package/dist/resource/resourceHttp.cjs.js.map +1 -1
  69. package/dist/resource/resourceHttp.esm.js.map +1 -1
  70. package/dist/resource/resourceLogic.cjs.js +1 -1
  71. package/dist/resource/resourceLogic.cjs.js.map +1 -1
  72. package/dist/resource/resourceLogic.d.ts.map +1 -1
  73. package/dist/resource/resourceLogic.esm.js +80 -34
  74. package/dist/resource/resourceLogic.esm.js.map +1 -1
  75. package/dist/resource/resourceMetadata.cjs.js +1 -1
  76. package/dist/resource/resourceMetadata.cjs.js.map +1 -1
  77. package/dist/resource/resourceMetadata.d.ts +2 -0
  78. package/dist/resource/resourceMetadata.d.ts.map +1 -1
  79. package/dist/resource/resourceMetadata.esm.js +6 -2
  80. package/dist/resource/resourceMetadata.esm.js.map +1 -1
  81. package/dist/typeIndex/typeIndexAclDocuments.cjs.js.map +1 -1
  82. package/dist/typeIndex/typeIndexAclDocuments.esm.js.map +1 -1
  83. package/dist/typeIndex/typeIndexDocuments.cjs.js.map +1 -1
  84. package/dist/typeIndex/typeIndexDocuments.esm.js.map +1 -1
  85. package/dist/typeIndex/typeIndexLogic.cjs.js +1 -1
  86. package/dist/typeIndex/typeIndexLogic.cjs.js.map +1 -1
  87. package/dist/typeIndex/typeIndexLogic.esm.js +5 -10
  88. package/dist/typeIndex/typeIndexLogic.esm.js.map +1 -1
  89. package/dist/types.d.ts +21 -1
  90. package/dist/types.d.ts.map +1 -1
  91. package/dist/util/containerLogic.cjs.js.map +1 -1
  92. package/dist/util/containerLogic.esm.js.map +1 -1
  93. package/dist/util/debug.cjs.js +1 -1
  94. package/dist/util/debug.cjs.js.map +1 -1
  95. package/dist/util/debug.esm.js +4 -1
  96. package/dist/util/debug.esm.js.map +1 -1
  97. package/dist/util/ns.cjs.js.map +1 -1
  98. package/dist/util/ns.esm.js.map +1 -1
  99. package/dist/util/utilityLogic.cjs.js.map +1 -1
  100. package/dist/util/utilityLogic.esm.js.map +1 -1
  101. package/dist/util/utils.cjs.js.map +1 -1
  102. package/dist/util/utils.esm.js.map +1 -1
  103. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chatLogic.cjs.js","names":[],"sources":["../../src/chat/chatLogic.ts"],"sourcesContent":["import { NamedNode, Node, st, term } from 'rdflib'\nimport { ChatLogic, CreatedPaneOptions, NewPaneOptions, Chat } from '../types'\nimport { ns as namespace } from '../util/ns'\nimport { determineChatContainer, newThing } from '../util/utils'\n\nconst CHAT_LOCATION_IN_CONTAINER = 'index.ttl#this'\n\nexport function createChatLogic(store, profileLogic): ChatLogic {\n const ns = namespace\n\n async function setAcl(\n chatContainer: NamedNode,\n me: NamedNode,\n invitee: NamedNode\n ): Promise<void> {\n // Some servers don't present a Link http response header\n // if the container doesn't exist yet, so refetch the container\n // now that it has been created:\n await store.fetcher.load(chatContainer)\n\n // FIXME: check the Why value on this quad:\n const chatAclDoc = store.any(\n chatContainer,\n new NamedNode('http://www.iana.org/assignments/link-relations/acl')\n )\n if (!chatAclDoc) {\n throw new Error('Chat ACL doc not found!')\n }\n\n const aclBody = `\n @prefix acl: <http://www.w3.org/ns/auth/acl#>.\n <#owner>\n a acl:Authorization;\n acl:agent <${me.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Write, acl:Control.\n <#invitee>\n a acl:Authorization;\n acl:agent <${invitee.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Append.\n `\n await store.fetcher.webOperation('PUT', chatAclDoc.value, {\n data: aclBody,\n contentType: 'text/turtle',\n })\n }\n\n async function addToPrivateTypeIndex(chatThing, me) {\n // Add to private type index\n const privateTypeIndex = store.any(\n me,\n ns.solid('privateTypeIndex')\n ) as NamedNode | null\n if (!privateTypeIndex) {\n throw new Error('Private type index not found!')\n }\n await store.fetcher.load(privateTypeIndex)\n const reg = newThing(privateTypeIndex)\n const ins = [\n st(\n reg,\n ns.rdf('type'),\n ns.solid('TypeRegistration'),\n privateTypeIndex.doc()\n ),\n st(\n reg,\n ns.solid('forClass'),\n ns.meeting('LongChat'),\n privateTypeIndex.doc()\n ),\n st(reg, ns.solid('instance'), chatThing, privateTypeIndex.doc()),\n ]\n await new Promise((resolve, reject) => {\n store.updater.update([], ins, function (_uri, ok, errm) {\n if (!ok) {\n reject(new Error(errm))\n } else {\n resolve(null)\n }\n })\n })\n }\n\n async function findChat(invitee: NamedNode): Promise<Chat> {\n const me = await profileLogic.loadMe()\n const podRoot = await profileLogic.getPodRoot(me)\n const chatContainer = determineChatContainer(invitee, podRoot)\n let exists = true\n try {\n await store.fetcher.load(\n new NamedNode(chatContainer.value + 'index.ttl#this')\n )\n } catch (e) {\n exists = false\n }\n return { me, chatContainer, exists }\n }\n\n async function createChatThing(\n chatContainer: NamedNode,\n me: NamedNode\n ): Promise<NamedNode> {\n const created = await mintNew({\n me,\n newBase: chatContainer.value,\n })\n return created.newInstance\n }\n\n function mintNew(newPaneOptions: NewPaneOptions): Promise<CreatedPaneOptions> {\n const kb = store\n const updater = kb.updater\n if (newPaneOptions.me && !newPaneOptions.me.uri) {\n throw new Error('chat mintNew: Invalid userid ' + newPaneOptions.me)\n }\n\n const newInstance = (newPaneOptions.newInstance =\n newPaneOptions.newInstance ||\n kb.sym(newPaneOptions.newBase + CHAT_LOCATION_IN_CONTAINER))\n const newChatDoc = newInstance.doc()\n\n kb.add(\n newInstance,\n ns.rdf('type'),\n ns.meeting('LongChat'),\n newChatDoc\n )\n kb.add(newInstance, ns.dc('title'), 'Chat channel', newChatDoc)\n kb.add(\n newInstance,\n ns.dc('created'),\n term<Node>(new Date(Date.now())),\n newChatDoc\n )\n if (newPaneOptions.me) {\n kb.add(newInstance, ns.dc('author'), newPaneOptions.me, newChatDoc)\n }\n\n return new Promise(function (resolve, reject) {\n updater?.put(\n newChatDoc,\n kb.statementsMatching(undefined, undefined, undefined, newChatDoc),\n 'text/turtle',\n function (uri2, ok, message) {\n if (ok) {\n resolve({\n ...newPaneOptions,\n newInstance,\n })\n } else {\n reject(\n new Error(\n 'FAILED to save new chat channel at: ' + uri2 + ' : ' + message\n )\n )\n }\n }\n )\n })\n }\n\n /**\n * Find (and optionally create) an individual chat between the current user and the given invitee\n * @param invitee - The person to chat with\n * @param createIfMissing - Whether the chat should be created, if missing\n * @returns null if missing, or a node referring to an already existing chat, or the newly created chat\n */\n async function getChat(\n invitee: NamedNode,\n createIfMissing = true\n ): Promise<NamedNode | null> {\n const { me, chatContainer, exists } = await findChat(invitee)\n if (exists) {\n return new NamedNode(chatContainer.value + CHAT_LOCATION_IN_CONTAINER)\n }\n\n if (createIfMissing) {\n const chatThing = await createChatThing(chatContainer, me)\n await sendInvite(invitee, chatThing)\n await setAcl(chatContainer, me, invitee)\n await addToPrivateTypeIndex(chatThing, me)\n return chatThing\n }\n return null\n }\n\n async function sendInvite(invitee: NamedNode, chatThing: NamedNode) {\n await store.fetcher.load(invitee.doc())\n const inviteeInbox = store.any(\n invitee,\n ns.ldp('inbox'),\n undefined,\n invitee.doc()\n )\n if (!inviteeInbox) {\n throw new Error(`Invitee inbox not found! ${invitee.value}`)\n }\n const inviteBody = `\n <> a <http://www.w3.org/ns/pim/meeting#LongChatInvite> ;\n ${ns.rdf('seeAlso')} <${chatThing.value}> .\n `\n\n const inviteResponse = await store.fetcher?.webOperation(\n 'POST',\n inviteeInbox.value,\n {\n data: inviteBody,\n contentType: 'text/turtle',\n }\n )\n const locationStr = inviteResponse?.headers.get('location')\n if (!locationStr) {\n throw new Error(`Invite sending returned a ${inviteResponse?.status}`)\n }\n }\n return {\n setAcl, addToPrivateTypeIndex, findChat, createChatThing, getChat, sendInvite, mintNew\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chatLogic.cjs.js","names":["ns","namespace","NamedNode","newThing","st","determineChatContainer","term","require_ns","require_utils","rdflib","CHAT_LOCATION_IN_CONTAINER","createChatLogic","ns$1","setAcl","store","chatContainer","chatAclDoc","aclBody","me","invitee","addToPrivateTypeIndex","privateTypeIndex","reg","ins","chatThing","ok","resolve","reject","errm","findChat","profileLogic","podRoot","exists","createChatThing","mintNew","kb","updater","newPaneOptions","newInstance","newChatDoc","uri2","message","getChat","createIfMissing","sendInvite","inviteeInbox","inviteBody","inviteResponse"],"sources":["../../src/chat/chatLogic.ts"],"sourcesContent":["import { NamedNode, Node, st, term } from 'rdflib'\nimport { ChatLogic, CreatedPaneOptions, NewPaneOptions, Chat } from '../types'\nimport { ns as namespace } from '../util/ns'\nimport { determineChatContainer, newThing } from '../util/utils'\n\nconst CHAT_LOCATION_IN_CONTAINER = 'index.ttl#this'\n\nexport function createChatLogic(store, profileLogic): ChatLogic {\n const ns = namespace\n\n async function setAcl(\n chatContainer: NamedNode,\n me: NamedNode,\n invitee: NamedNode\n ): Promise<void> {\n // Some servers don't present a Link http response header\n // if the container doesn't exist yet, so refetch the container\n // now that it has been created:\n await store.fetcher.load(chatContainer)\n\n // FIXME: check the Why value on this quad:\n const chatAclDoc = store.any(\n chatContainer,\n new NamedNode('http://www.iana.org/assignments/link-relations/acl')\n )\n if (!chatAclDoc) {\n throw new Error('Chat ACL doc not found!')\n }\n\n const aclBody = `\n @prefix acl: <http://www.w3.org/ns/auth/acl#>.\n <#owner>\n a acl:Authorization;\n acl:agent <${me.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Write, acl:Control.\n <#invitee>\n a acl:Authorization;\n acl:agent <${invitee.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Append.\n `\n await store.fetcher.webOperation('PUT', chatAclDoc.value, {\n data: aclBody,\n contentType: 'text/turtle',\n })\n }\n\n async function addToPrivateTypeIndex(chatThing, me) {\n // Add to private type index\n const privateTypeIndex = store.any(\n me,\n ns.solid('privateTypeIndex')\n ) as NamedNode | null\n if (!privateTypeIndex) {\n throw new Error('Private type index not found!')\n }\n await store.fetcher.load(privateTypeIndex)\n const reg = newThing(privateTypeIndex)\n const ins = [\n st(\n reg,\n ns.rdf('type'),\n ns.solid('TypeRegistration'),\n privateTypeIndex.doc()\n ),\n st(\n reg,\n ns.solid('forClass'),\n ns.meeting('LongChat'),\n privateTypeIndex.doc()\n ),\n st(reg, ns.solid('instance'), chatThing, privateTypeIndex.doc()),\n ]\n await new Promise((resolve, reject) => {\n store.updater.update([], ins, function (_uri, ok, errm) {\n if (!ok) {\n reject(new Error(errm))\n } else {\n resolve(null)\n }\n })\n })\n }\n\n async function findChat(invitee: NamedNode): Promise<Chat> {\n const me = await profileLogic.loadMe()\n const podRoot = await profileLogic.getPodRoot(me)\n const chatContainer = determineChatContainer(invitee, podRoot)\n let exists = true\n try {\n await store.fetcher.load(\n new NamedNode(chatContainer.value + 'index.ttl#this')\n )\n } catch (e) {\n exists = false\n }\n return { me, chatContainer, exists }\n }\n\n async function createChatThing(\n chatContainer: NamedNode,\n me: NamedNode\n ): Promise<NamedNode> {\n const created = await mintNew({\n me,\n newBase: chatContainer.value,\n })\n return created.newInstance\n }\n\n function mintNew(newPaneOptions: NewPaneOptions): Promise<CreatedPaneOptions> {\n const kb = store\n const updater = kb.updater\n if (newPaneOptions.me && !newPaneOptions.me.uri) {\n throw new Error('chat mintNew: Invalid userid ' + newPaneOptions.me)\n }\n\n const newInstance = (newPaneOptions.newInstance =\n newPaneOptions.newInstance ||\n kb.sym(newPaneOptions.newBase + CHAT_LOCATION_IN_CONTAINER))\n const newChatDoc = newInstance.doc()\n\n kb.add(\n newInstance,\n ns.rdf('type'),\n ns.meeting('LongChat'),\n newChatDoc\n )\n kb.add(newInstance, ns.dc('title'), 'Chat channel', newChatDoc)\n kb.add(\n newInstance,\n ns.dc('created'),\n term<Node>(new Date(Date.now())),\n newChatDoc\n )\n if (newPaneOptions.me) {\n kb.add(newInstance, ns.dc('author'), newPaneOptions.me, newChatDoc)\n }\n\n return new Promise(function (resolve, reject) {\n updater?.put(\n newChatDoc,\n kb.statementsMatching(undefined, undefined, undefined, newChatDoc),\n 'text/turtle',\n function (uri2, ok, message) {\n if (ok) {\n resolve({\n ...newPaneOptions,\n newInstance,\n })\n } else {\n reject(\n new Error(\n 'FAILED to save new chat channel at: ' + uri2 + ' : ' + message\n )\n )\n }\n }\n )\n })\n }\n\n /**\n * Find (and optionally create) an individual chat between the current user and the given invitee\n * @param invitee - The person to chat with\n * @param createIfMissing - Whether the chat should be created, if missing\n * @returns null if missing, or a node referring to an already existing chat, or the newly created chat\n */\n async function getChat(\n invitee: NamedNode,\n createIfMissing = true\n ): Promise<NamedNode | null> {\n const { me, chatContainer, exists } = await findChat(invitee)\n if (exists) {\n return new NamedNode(chatContainer.value + CHAT_LOCATION_IN_CONTAINER)\n }\n\n if (createIfMissing) {\n const chatThing = await createChatThing(chatContainer, me)\n await sendInvite(invitee, chatThing)\n await setAcl(chatContainer, me, invitee)\n await addToPrivateTypeIndex(chatThing, me)\n return chatThing\n }\n return null\n }\n\n async function sendInvite(invitee: NamedNode, chatThing: NamedNode) {\n await store.fetcher.load(invitee.doc())\n const inviteeInbox = store.any(\n invitee,\n ns.ldp('inbox'),\n undefined,\n invitee.doc()\n )\n if (!inviteeInbox) {\n throw new Error(`Invitee inbox not found! ${invitee.value}`)\n }\n const inviteBody = `\n <> a <http://www.w3.org/ns/pim/meeting#LongChatInvite> ;\n ${ns.rdf('seeAlso')} <${chatThing.value}> .\n `\n\n const inviteResponse = await store.fetcher?.webOperation(\n 'POST',\n inviteeInbox.value,\n {\n data: inviteBody,\n contentType: 'text/turtle',\n }\n )\n const locationStr = inviteResponse?.headers.get('location')\n if (!locationStr) {\n throw new Error(`Invite sending returned a ${inviteResponse?.status}`)\n }\n }\n return {\n setAcl, addToPrivateTypeIndex, findChat, createChatThing, getChat, sendInvite, mintNew\n }\n}\n"],"mappings":"+FAKA,IAAMU,EAA6B,iBAEnC,SAAgBC,EAAgB,EAAO,EAAyB,CAC5D,IAAMX,EAAKC,EAAAA,GAEX,eAAeY,EACX,EACA,EACA,EACa,CAIb,MAAMC,EAAM,QAAQ,KAAKC,CAAa,EAGtC,IAAMC,EAAaF,EAAM,IACrBC,EACA,IAAIb,EAAAA,UAAU,oDAAoD,CACtE,EACA,GAAI,CAACc,EACD,MAAU,MAAM,yBAAyB,EAG7C,IAAMC,EAAU;;;;yBAICC,EAAG,MAAM;;;;;;;yBAOTC,EAAQ,MAAM;;;;;cAM/B,MAAML,EAAM,QAAQ,aAAa,MAAOE,EAAW,MAAO,CACtD,KAAMC,EACN,YAAa,aACjB,CAAC,CACL,CAEA,eAAeG,EAAsB,EAAW,EAAI,CAEhD,IAAMC,EAAmBP,EAAM,IAC3BI,EACAlB,EAAG,MAAM,kBAAkB,CAC/B,EACA,GAAI,CAACqB,EACD,MAAU,MAAM,+BAA+B,EAEnD,MAAMP,EAAM,QAAQ,KAAKO,CAAgB,EACzC,IAAMC,EAAMnB,EAAAA,SAASkB,CAAgB,EAC/BE,EAAM,EACRnB,EAAAA,EAAAA,GAAAA,CACIkB,EACAtB,EAAG,IAAI,MAAM,EACbA,EAAG,MAAM,kBAAkB,EAC3BqB,EAAiB,IAAI,CACzB,GACAjB,EAAAA,EAAAA,GAAAA,CACIkB,EACAtB,EAAG,MAAM,UAAU,EACnBA,EAAG,QAAQ,UAAU,EACrBqB,EAAiB,IAAI,CACzB,GACAjB,EAAAA,EAAAA,GAAAA,CAAGkB,EAAKtB,EAAG,MAAM,UAAU,EAAGwB,EAAWH,EAAiB,IAAI,CAAC,CACnE,EACA,MAAM,IAAI,SAAS,EAAS,IAAW,CACnCP,EAAM,QAAQ,OAAO,CAAC,EAAGS,EAAK,SAAU,EAAM,EAAI,EAAM,CAC/CE,EAGDC,EAAQ,IAAI,EAFZC,EAAW,MAAMC,CAAI,CAAC,CAI9B,CAAC,CACL,CAAC,CACL,CAEA,eAAeC,EAAS,EAAmC,CACvD,IAAMX,EAAK,MAAMY,EAAa,OAAO,EAC/BC,EAAU,MAAMD,EAAa,WAAWZ,CAAE,EAC1CH,EAAgBV,EAAAA,uBAAuBc,EAASY,CAAO,EACzDC,EAAS,GACb,GAAI,CACA,MAAMlB,EAAM,QAAQ,KAChB,IAAIZ,EAAAA,UAAUa,EAAc,MAAQ,gBAAgB,CACxD,CACJ,MAAY,CACR,EAAS,EACb,CACA,MAAO,CAAE,KAAI,gBAAe,QAAO,CACvC,CAEA,eAAekB,EACX,EACA,EACkB,CAKlB,OAAO,MAJeC,EAAQ,CAC1B,KACA,QAASnB,EAAc,KAC3B,CAAC,EAAA,CACc,WACnB,CAEA,SAASmB,EAAQ,EAA6D,CAC1E,IAAMC,EAAKrB,EACLsB,EAAUD,EAAG,QACnB,GAAIE,EAAe,IAAM,CAACA,EAAe,GAAG,IACxC,MAAU,MAAM,iCAAmCA,EAAe,EAAE,EAGxE,IAAMC,EAAe,EAAe,YAChCD,EAAe,aACfF,EAAG,IAAIE,EAAe,QAAU3B,CAA0B,EACxD6B,EAAaD,EAAY,IAAI,EAmBnC,OAjBAH,EAAG,IACCG,EACAtC,EAAG,IAAI,MAAM,EACbA,EAAG,QAAQ,UAAU,EACrBuC,CACJ,EACAJ,EAAG,IAAIG,EAAatC,EAAG,GAAG,OAAO,EAAG,eAAgBuC,CAAU,EAC9DJ,EAAG,IACCG,EACAtC,EAAG,GAAG,SAAS,GAAA,EACfM,EAAAA,KAAAA,CAAW,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,EAC/BiC,CACJ,EACIF,EAAe,IACfF,EAAG,IAAIG,EAAatC,EAAG,GAAG,QAAQ,EAAGqC,EAAe,GAAIE,CAAU,EAG/D,IAAI,QAAQ,SAAU,EAAS,EAAQ,CAC1CH,GAAS,IACLG,EACAJ,EAAG,mBAAmB,IAAA,GAAW,IAAA,GAAW,IAAA,GAAWI,CAAU,EACjE,cACA,SAAU,EAAM,EAAI,EAAS,CACrBd,EACAC,EAAQ,CACJ,GAAGW,EACH,aACJ,CAAC,EAEDV,EACQ,MACA,uCAAyCa,EAAO,MAAQC,CAC5D,CACJ,CAER,CACJ,CACJ,CAAC,CACL,CAQA,eAAeC,EACX,EACA,EAAkB,GACO,CACzB,GAAM,CAAE,KAAI,gBAAe,UAAW,MAAMb,EAASV,CAAO,EAC5D,GAAIa,EACA,OAAO,IAAI9B,EAAAA,UAAUa,EAAc,MAAQL,CAA0B,EAGzE,GAAIiC,EAAiB,CACjB,IAAMnB,EAAY,MAAMS,EAAgBlB,EAAeG,CAAE,EAIzD,OAHA,MAAM0B,EAAWzB,EAASK,CAAS,EACnC,MAAMX,EAAOE,EAAeG,EAAIC,CAAO,EACvC,MAAMC,EAAsBI,EAAWN,CAAE,EAClCM,CACX,CACA,OAAO,IACX,CAEA,eAAeoB,EAAW,EAAoB,EAAsB,CAChE,MAAM9B,EAAM,QAAQ,KAAKK,EAAQ,IAAI,CAAC,EACtC,IAAM0B,EAAe/B,EAAM,IACvBK,EACAnB,EAAG,IAAI,OAAO,EACd,IAAA,GACAmB,EAAQ,IAAI,CAChB,EACA,GAAI,CAAC0B,EACD,MAAU,MAAM,4BAA4B1B,EAAQ,OAAO,EAE/D,IAAM2B,EAAa;;UAEjB9C,EAAG,IAAI,SAAS,EAAE,IAAIwB,EAAU,MAAM;UAGlCuB,EAAiB,MAAMjC,EAAM,SAAS,aACxC,OACA+B,EAAa,MACb,CACI,KAAMC,EACN,YAAa,aACjB,CACJ,EAEA,GAAI,CADgBC,GAAgB,QAAQ,IAAI,UAAU,EAEtD,MAAU,MAAM,6BAA6BA,GAAgB,QAAQ,CAE7E,CACA,MAAO,CACH,SAAQ,wBAAuB,WAAU,kBAAiB,UAAS,aAAY,SACnF,CACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"chatLogic.esm.js","names":[],"sources":["../../src/chat/chatLogic.ts"],"sourcesContent":["import { NamedNode, Node, st, term } from 'rdflib'\nimport { ChatLogic, CreatedPaneOptions, NewPaneOptions, Chat } from '../types'\nimport { ns as namespace } from '../util/ns'\nimport { determineChatContainer, newThing } from '../util/utils'\n\nconst CHAT_LOCATION_IN_CONTAINER = 'index.ttl#this'\n\nexport function createChatLogic(store, profileLogic): ChatLogic {\n const ns = namespace\n\n async function setAcl(\n chatContainer: NamedNode,\n me: NamedNode,\n invitee: NamedNode\n ): Promise<void> {\n // Some servers don't present a Link http response header\n // if the container doesn't exist yet, so refetch the container\n // now that it has been created:\n await store.fetcher.load(chatContainer)\n\n // FIXME: check the Why value on this quad:\n const chatAclDoc = store.any(\n chatContainer,\n new NamedNode('http://www.iana.org/assignments/link-relations/acl')\n )\n if (!chatAclDoc) {\n throw new Error('Chat ACL doc not found!')\n }\n\n const aclBody = `\n @prefix acl: <http://www.w3.org/ns/auth/acl#>.\n <#owner>\n a acl:Authorization;\n acl:agent <${me.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Write, acl:Control.\n <#invitee>\n a acl:Authorization;\n acl:agent <${invitee.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Append.\n `\n await store.fetcher.webOperation('PUT', chatAclDoc.value, {\n data: aclBody,\n contentType: 'text/turtle',\n })\n }\n\n async function addToPrivateTypeIndex(chatThing, me) {\n // Add to private type index\n const privateTypeIndex = store.any(\n me,\n ns.solid('privateTypeIndex')\n ) as NamedNode | null\n if (!privateTypeIndex) {\n throw new Error('Private type index not found!')\n }\n await store.fetcher.load(privateTypeIndex)\n const reg = newThing(privateTypeIndex)\n const ins = [\n st(\n reg,\n ns.rdf('type'),\n ns.solid('TypeRegistration'),\n privateTypeIndex.doc()\n ),\n st(\n reg,\n ns.solid('forClass'),\n ns.meeting('LongChat'),\n privateTypeIndex.doc()\n ),\n st(reg, ns.solid('instance'), chatThing, privateTypeIndex.doc()),\n ]\n await new Promise((resolve, reject) => {\n store.updater.update([], ins, function (_uri, ok, errm) {\n if (!ok) {\n reject(new Error(errm))\n } else {\n resolve(null)\n }\n })\n })\n }\n\n async function findChat(invitee: NamedNode): Promise<Chat> {\n const me = await profileLogic.loadMe()\n const podRoot = await profileLogic.getPodRoot(me)\n const chatContainer = determineChatContainer(invitee, podRoot)\n let exists = true\n try {\n await store.fetcher.load(\n new NamedNode(chatContainer.value + 'index.ttl#this')\n )\n } catch (e) {\n exists = false\n }\n return { me, chatContainer, exists }\n }\n\n async function createChatThing(\n chatContainer: NamedNode,\n me: NamedNode\n ): Promise<NamedNode> {\n const created = await mintNew({\n me,\n newBase: chatContainer.value,\n })\n return created.newInstance\n }\n\n function mintNew(newPaneOptions: NewPaneOptions): Promise<CreatedPaneOptions> {\n const kb = store\n const updater = kb.updater\n if (newPaneOptions.me && !newPaneOptions.me.uri) {\n throw new Error('chat mintNew: Invalid userid ' + newPaneOptions.me)\n }\n\n const newInstance = (newPaneOptions.newInstance =\n newPaneOptions.newInstance ||\n kb.sym(newPaneOptions.newBase + CHAT_LOCATION_IN_CONTAINER))\n const newChatDoc = newInstance.doc()\n\n kb.add(\n newInstance,\n ns.rdf('type'),\n ns.meeting('LongChat'),\n newChatDoc\n )\n kb.add(newInstance, ns.dc('title'), 'Chat channel', newChatDoc)\n kb.add(\n newInstance,\n ns.dc('created'),\n term<Node>(new Date(Date.now())),\n newChatDoc\n )\n if (newPaneOptions.me) {\n kb.add(newInstance, ns.dc('author'), newPaneOptions.me, newChatDoc)\n }\n\n return new Promise(function (resolve, reject) {\n updater?.put(\n newChatDoc,\n kb.statementsMatching(undefined, undefined, undefined, newChatDoc),\n 'text/turtle',\n function (uri2, ok, message) {\n if (ok) {\n resolve({\n ...newPaneOptions,\n newInstance,\n })\n } else {\n reject(\n new Error(\n 'FAILED to save new chat channel at: ' + uri2 + ' : ' + message\n )\n )\n }\n }\n )\n })\n }\n\n /**\n * Find (and optionally create) an individual chat between the current user and the given invitee\n * @param invitee - The person to chat with\n * @param createIfMissing - Whether the chat should be created, if missing\n * @returns null if missing, or a node referring to an already existing chat, or the newly created chat\n */\n async function getChat(\n invitee: NamedNode,\n createIfMissing = true\n ): Promise<NamedNode | null> {\n const { me, chatContainer, exists } = await findChat(invitee)\n if (exists) {\n return new NamedNode(chatContainer.value + CHAT_LOCATION_IN_CONTAINER)\n }\n\n if (createIfMissing) {\n const chatThing = await createChatThing(chatContainer, me)\n await sendInvite(invitee, chatThing)\n await setAcl(chatContainer, me, invitee)\n await addToPrivateTypeIndex(chatThing, me)\n return chatThing\n }\n return null\n }\n\n async function sendInvite(invitee: NamedNode, chatThing: NamedNode) {\n await store.fetcher.load(invitee.doc())\n const inviteeInbox = store.any(\n invitee,\n ns.ldp('inbox'),\n undefined,\n invitee.doc()\n )\n if (!inviteeInbox) {\n throw new Error(`Invitee inbox not found! ${invitee.value}`)\n }\n const inviteBody = `\n <> a <http://www.w3.org/ns/pim/meeting#LongChatInvite> ;\n ${ns.rdf('seeAlso')} <${chatThing.value}> .\n `\n\n const inviteResponse = await store.fetcher?.webOperation(\n 'POST',\n inviteeInbox.value,\n {\n data: inviteBody,\n contentType: 'text/turtle',\n }\n )\n const locationStr = inviteResponse?.headers.get('location')\n if (!locationStr) {\n throw new Error(`Invite sending returned a ${inviteResponse?.status}`)\n }\n }\n return {\n setAcl, addToPrivateTypeIndex, findChat, createChatThing, getChat, sendInvite, mintNew\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"chatLogic.esm.js","names":["ns","namespace","CHAT_LOCATION_IN_CONTAINER","createChatLogic","ns$1","ns","setAcl","store","chatContainer","chatAclDoc","NamedNode","aclBody","me","invitee","addToPrivateTypeIndex","privateTypeIndex","reg","newThing","ins","st","chatThing","ok","resolve","reject","errm","findChat","profileLogic","podRoot","determineChatContainer","exists","createChatThing","mintNew","kb","updater","newPaneOptions","newInstance","newChatDoc","term","uri2","message","getChat","createIfMissing","sendInvite","inviteeInbox","inviteBody","inviteResponse"],"sources":["../../src/chat/chatLogic.ts"],"sourcesContent":["import { NamedNode, Node, st, term } from 'rdflib'\nimport { ChatLogic, CreatedPaneOptions, NewPaneOptions, Chat } from '../types'\nimport { ns as namespace } from '../util/ns'\nimport { determineChatContainer, newThing } from '../util/utils'\n\nconst CHAT_LOCATION_IN_CONTAINER = 'index.ttl#this'\n\nexport function createChatLogic(store, profileLogic): ChatLogic {\n const ns = namespace\n\n async function setAcl(\n chatContainer: NamedNode,\n me: NamedNode,\n invitee: NamedNode\n ): Promise<void> {\n // Some servers don't present a Link http response header\n // if the container doesn't exist yet, so refetch the container\n // now that it has been created:\n await store.fetcher.load(chatContainer)\n\n // FIXME: check the Why value on this quad:\n const chatAclDoc = store.any(\n chatContainer,\n new NamedNode('http://www.iana.org/assignments/link-relations/acl')\n )\n if (!chatAclDoc) {\n throw new Error('Chat ACL doc not found!')\n }\n\n const aclBody = `\n @prefix acl: <http://www.w3.org/ns/auth/acl#>.\n <#owner>\n a acl:Authorization;\n acl:agent <${me.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Write, acl:Control.\n <#invitee>\n a acl:Authorization;\n acl:agent <${invitee.value}>;\n acl:accessTo <.>;\n acl:default <.>;\n acl:mode\n acl:Read, acl:Append.\n `\n await store.fetcher.webOperation('PUT', chatAclDoc.value, {\n data: aclBody,\n contentType: 'text/turtle',\n })\n }\n\n async function addToPrivateTypeIndex(chatThing, me) {\n // Add to private type index\n const privateTypeIndex = store.any(\n me,\n ns.solid('privateTypeIndex')\n ) as NamedNode | null\n if (!privateTypeIndex) {\n throw new Error('Private type index not found!')\n }\n await store.fetcher.load(privateTypeIndex)\n const reg = newThing(privateTypeIndex)\n const ins = [\n st(\n reg,\n ns.rdf('type'),\n ns.solid('TypeRegistration'),\n privateTypeIndex.doc()\n ),\n st(\n reg,\n ns.solid('forClass'),\n ns.meeting('LongChat'),\n privateTypeIndex.doc()\n ),\n st(reg, ns.solid('instance'), chatThing, privateTypeIndex.doc()),\n ]\n await new Promise((resolve, reject) => {\n store.updater.update([], ins, function (_uri, ok, errm) {\n if (!ok) {\n reject(new Error(errm))\n } else {\n resolve(null)\n }\n })\n })\n }\n\n async function findChat(invitee: NamedNode): Promise<Chat> {\n const me = await profileLogic.loadMe()\n const podRoot = await profileLogic.getPodRoot(me)\n const chatContainer = determineChatContainer(invitee, podRoot)\n let exists = true\n try {\n await store.fetcher.load(\n new NamedNode(chatContainer.value + 'index.ttl#this')\n )\n } catch (e) {\n exists = false\n }\n return { me, chatContainer, exists }\n }\n\n async function createChatThing(\n chatContainer: NamedNode,\n me: NamedNode\n ): Promise<NamedNode> {\n const created = await mintNew({\n me,\n newBase: chatContainer.value,\n })\n return created.newInstance\n }\n\n function mintNew(newPaneOptions: NewPaneOptions): Promise<CreatedPaneOptions> {\n const kb = store\n const updater = kb.updater\n if (newPaneOptions.me && !newPaneOptions.me.uri) {\n throw new Error('chat mintNew: Invalid userid ' + newPaneOptions.me)\n }\n\n const newInstance = (newPaneOptions.newInstance =\n newPaneOptions.newInstance ||\n kb.sym(newPaneOptions.newBase + CHAT_LOCATION_IN_CONTAINER))\n const newChatDoc = newInstance.doc()\n\n kb.add(\n newInstance,\n ns.rdf('type'),\n ns.meeting('LongChat'),\n newChatDoc\n )\n kb.add(newInstance, ns.dc('title'), 'Chat channel', newChatDoc)\n kb.add(\n newInstance,\n ns.dc('created'),\n term<Node>(new Date(Date.now())),\n newChatDoc\n )\n if (newPaneOptions.me) {\n kb.add(newInstance, ns.dc('author'), newPaneOptions.me, newChatDoc)\n }\n\n return new Promise(function (resolve, reject) {\n updater?.put(\n newChatDoc,\n kb.statementsMatching(undefined, undefined, undefined, newChatDoc),\n 'text/turtle',\n function (uri2, ok, message) {\n if (ok) {\n resolve({\n ...newPaneOptions,\n newInstance,\n })\n } else {\n reject(\n new Error(\n 'FAILED to save new chat channel at: ' + uri2 + ' : ' + message\n )\n )\n }\n }\n )\n })\n }\n\n /**\n * Find (and optionally create) an individual chat between the current user and the given invitee\n * @param invitee - The person to chat with\n * @param createIfMissing - Whether the chat should be created, if missing\n * @returns null if missing, or a node referring to an already existing chat, or the newly created chat\n */\n async function getChat(\n invitee: NamedNode,\n createIfMissing = true\n ): Promise<NamedNode | null> {\n const { me, chatContainer, exists } = await findChat(invitee)\n if (exists) {\n return new NamedNode(chatContainer.value + CHAT_LOCATION_IN_CONTAINER)\n }\n\n if (createIfMissing) {\n const chatThing = await createChatThing(chatContainer, me)\n await sendInvite(invitee, chatThing)\n await setAcl(chatContainer, me, invitee)\n await addToPrivateTypeIndex(chatThing, me)\n return chatThing\n }\n return null\n }\n\n async function sendInvite(invitee: NamedNode, chatThing: NamedNode) {\n await store.fetcher.load(invitee.doc())\n const inviteeInbox = store.any(\n invitee,\n ns.ldp('inbox'),\n undefined,\n invitee.doc()\n )\n if (!inviteeInbox) {\n throw new Error(`Invitee inbox not found! ${invitee.value}`)\n }\n const inviteBody = `\n <> a <http://www.w3.org/ns/pim/meeting#LongChatInvite> ;\n ${ns.rdf('seeAlso')} <${chatThing.value}> .\n `\n\n const inviteResponse = await store.fetcher?.webOperation(\n 'POST',\n inviteeInbox.value,\n {\n data: inviteBody,\n contentType: 'text/turtle',\n }\n )\n const locationStr = inviteResponse?.headers.get('location')\n if (!locationStr) {\n throw new Error(`Invite sending returned a ${inviteResponse?.status}`)\n }\n }\n return {\n setAcl, addToPrivateTypeIndex, findChat, createChatThing, getChat, sendInvite, mintNew\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalogDirectory.cjs.js","names":[],"sources":["../../src/directory/catalogDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { graph, type LiveStore, NamedNode, parse } from 'rdflib'\nimport { ns } from '../util/ns'\nimport * as debug from '../util/debug'\nimport { isHttpUri } from './directoryHelpers'\n\nconst CATALOG_VOCAB = 'http://example.org#'\n\nexport function createCatalogDirectoryDiscovery () {\n const catalogEntriesCache = new Map<string, Promise<DirectoryEntry[]>>()\n\n async function discoverCatalogEntries (\n catalogUrl: string,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const entries = await fetchCatalogEntries(catalogUrl)\n for (const entry of entries) {\n await onEntry(entry)\n }\n }\n\n async function fetchCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n const cached = catalogEntriesCache.get(catalogUrl)\n if (cached) {\n return cached\n }\n\n const promise = loadCatalogEntries(catalogUrl).catch(error => {\n catalogEntriesCache.delete(catalogUrl)\n throw error\n })\n\n catalogEntriesCache.set(catalogUrl, promise)\n try {\n return await promise\n } catch (error) {\n debug.warn('[Directory] Error fetching directory catalog:', error)\n return []\n }\n }\n\n async function loadCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n if (typeof fetch !== 'function') {\n throw new Error('Fetch API is unavailable')\n }\n\n const response = await fetch(catalogUrl, {\n headers: { accept: 'text/turtle' }\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${catalogUrl}: ${response.status}`)\n }\n\n const turtle = await response.text()\n const catalogStore = graph() as LiveStore\n parse(turtle, catalogStore, catalogUrl, 'text/turtle')\n\n const personType = new NamedNode(`${CATALOG_VOCAB}Person`)\n const webIdPredicate = new NamedNode(`${CATALOG_VOCAB}webid`)\n const namePredicate = new NamedNode(`${CATALOG_VOCAB}name`)\n const catalogPeople = new Map<string, DirectoryEntry>()\n\n const statements = catalogStore.statementsMatching(undefined, ns.rdf('type'), personType)\n for (const statement of statements) {\n const subject = statement.subject\n const webIdNode = catalogStore.any(subject, webIdPredicate)\n if (webIdNode && webIdNode.termType === 'NamedNode') {\n const webId = webIdNode.value\n const personName = catalogStore.anyValue(subject, namePredicate)\n if (isHttpUri(webId) && personName) {\n catalogPeople.set(webId, {\n kind: 'person',\n uri: webId,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: 'People',\n sources: ['catalog']\n })\n }\n }\n }\n\n return Array.from(catalogPeople.values())\n }\n\n return {\n discoverCatalogEntries\n }\n}\n"],"mappings":"sIAMA,IAAM,EAAgB,sBAEtB,SAAgB,GAAmC,CACjD,IAAM,EAAsB,IAAI,IAEhC,eAAe,EACb,EACA,EACe,CACf,IAAM,EAAU,MAAM,EAAoB,CAAU,EACpD,IAAK,IAAM,KAAS,EAClB,MAAM,EAAQ,CAAK,CAEvB,CAEA,eAAe,EAAqB,EAA+C,CACjF,IAAM,EAAS,EAAoB,IAAI,CAAU,EACjD,GAAI,EACF,OAAO,EAGT,IAAM,EAAU,EAAmB,CAAU,CAAC,CAAC,MAAM,GAAS,CAE5D,MADA,EAAoB,OAAO,CAAU,EAC/B,CACR,CAAC,EAED,EAAoB,IAAI,EAAY,CAAO,EAC3C,GAAI,CACF,OAAO,MAAM,CACf,OAAS,EAAO,CAEd,OADA,EAAA,KAAW,gDAAiD,CAAK,EAC1D,CAAC,CACV,CACF,CAEA,eAAe,EAAoB,EAA+C,CAChF,GAAI,OAAO,OAAU,WACnB,MAAU,MAAM,0BAA0B,EAG5C,IAAM,EAAW,MAAM,MAAM,EAAY,CACvC,QAAS,CAAE,OAAQ,aAAc,CACnC,CAAC,EAED,GAAI,CAAC,EAAS,GACZ,MAAU,MAAM,mBAAmB,EAAW,IAAI,EAAS,QAAQ,EAGrE,IAAM,EAAS,MAAM,EAAS,KAAK,EAC7B,GAAA,EAAe,EAAA,MAAA,CAAM,GAC3B,EAAA,EAAA,MAAA,CAAM,EAAQ,EAAc,EAAY,aAAa,EAErD,IAAM,EAAa,IAAI,EAAA,UAAU,GAAG,EAAc,OAAO,EACnD,EAAiB,IAAI,EAAA,UAAU,GAAG,EAAc,MAAM,EACtD,EAAgB,IAAI,EAAA,UAAU,GAAG,EAAc,KAAK,EACpD,EAAgB,IAAI,IAEpB,EAAa,EAAa,mBAAmB,IAAA,GAAW,EAAA,GAAG,IAAI,MAAM,EAAG,CAAU,EACxF,IAAK,IAAM,KAAa,EAAY,CAClC,IAAM,EAAU,EAAU,QACpB,EAAY,EAAa,IAAI,EAAS,CAAc,EAC1D,GAAI,GAAa,EAAU,WAAa,YAAa,CACnD,IAAM,EAAQ,EAAU,MAClB,EAAa,EAAa,SAAS,EAAS,CAAa,EAC3D,EAAA,UAAU,CAAK,GAAK,GACtB,EAAc,IAAI,EAAO,CACvB,KAAM,SACN,IAAK,EACL,MAAO,EACP,YAAa,QACb,kBAAmB,SACnB,QAAS,CAAC,SAAS,CACrB,CAAC,CAEL,CACF,CAEA,OAAO,MAAM,KAAK,EAAc,OAAO,CAAC,CAC1C,CAEA,MAAO,CACL,wBACF,CACF"}
1
+ {"version":3,"file":"catalogDirectory.cjs.js","names":["graph","NamedNode","ns","isHttpUri","require_debug","require_ns","require_directoryHelpers","rdflib","CATALOG_VOCAB","createCatalogDirectoryDiscovery","catalogEntriesCache","discoverCatalogEntries","entries","fetchCatalogEntries","catalogUrl","entry","onEntry","cached","promise","loadCatalogEntries","error","response","turtle","catalogStore","personType","webIdPredicate","namePredicate","catalogPeople","statements","statement","subject","webIdNode","webId","personName"],"sources":["../../src/directory/catalogDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { graph, type LiveStore, NamedNode, parse } from 'rdflib'\nimport { ns } from '../util/ns'\nimport * as debug from '../util/debug'\nimport { isHttpUri } from './directoryHelpers'\n\nconst CATALOG_VOCAB = 'http://example.org#'\n\nexport function createCatalogDirectoryDiscovery () {\n const catalogEntriesCache = new Map<string, Promise<DirectoryEntry[]>>()\n\n async function discoverCatalogEntries (\n catalogUrl: string,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const entries = await fetchCatalogEntries(catalogUrl)\n for (const entry of entries) {\n await onEntry(entry)\n }\n }\n\n async function fetchCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n const cached = catalogEntriesCache.get(catalogUrl)\n if (cached) {\n return cached\n }\n\n const promise = loadCatalogEntries(catalogUrl).catch(error => {\n catalogEntriesCache.delete(catalogUrl)\n throw error\n })\n\n catalogEntriesCache.set(catalogUrl, promise)\n try {\n return await promise\n } catch (error) {\n debug.warn('[Directory] Error fetching directory catalog:', error)\n return []\n }\n }\n\n async function loadCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n if (typeof fetch !== 'function') {\n throw new Error('Fetch API is unavailable')\n }\n\n const response = await fetch(catalogUrl, {\n headers: { accept: 'text/turtle' }\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${catalogUrl}: ${response.status}`)\n }\n\n const turtle = await response.text()\n const catalogStore = graph() as LiveStore\n parse(turtle, catalogStore, catalogUrl, 'text/turtle')\n\n const personType = new NamedNode(`${CATALOG_VOCAB}Person`)\n const webIdPredicate = new NamedNode(`${CATALOG_VOCAB}webid`)\n const namePredicate = new NamedNode(`${CATALOG_VOCAB}name`)\n const catalogPeople = new Map<string, DirectoryEntry>()\n\n const statements = catalogStore.statementsMatching(undefined, ns.rdf('type'), personType)\n for (const statement of statements) {\n const subject = statement.subject\n const webIdNode = catalogStore.any(subject, webIdPredicate)\n if (webIdNode && webIdNode.termType === 'NamedNode') {\n const webId = webIdNode.value\n const personName = catalogStore.anyValue(subject, namePredicate)\n if (isHttpUri(webId) && personName) {\n catalogPeople.set(webId, {\n kind: 'person',\n uri: webId,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: 'People',\n sources: ['catalog']\n })\n }\n }\n }\n\n return Array.from(catalogPeople.values())\n }\n\n return {\n discoverCatalogEntries\n }\n}\n"],"mappings":"sIAMA,IAAMQ,EAAgB,sBAEtB,SAAgBC,GAAmC,CACjD,IAAMC,EAAsB,IAAI,IAEhC,eAAeC,EACb,EACA,EACe,CACf,IAAMC,EAAU,MAAMC,EAAoBC,CAAU,EACpD,IAAK,IAAMC,KAASH,EAClB,MAAMI,EAAQD,CAAK,CAEvB,CAEA,eAAeF,EAAqB,EAA+C,CACjF,IAAMI,EAASP,EAAoB,IAAII,CAAU,EACjD,GAAIG,EACF,OAAOA,EAGT,IAAMC,EAAUC,EAAmBL,CAAU,CAAC,CAAC,MAAM,GAAS,CAE5D,MADAJ,EAAoB,OAAOI,CAAU,EAC/BM,CACR,CAAC,EAEDV,EAAoB,IAAII,EAAYI,CAAO,EAC3C,GAAI,CACF,OAAO,MAAMA,CACf,OAASE,EAAO,CAEd,OADAhB,EAAA,KAAW,gDAAiDgB,CAAK,EAC1D,CAAC,CACV,CACF,CAEA,eAAeD,EAAoB,EAA+C,CAChF,GAAI,OAAO,OAAU,WACnB,MAAU,MAAM,0BAA0B,EAG5C,IAAME,EAAW,MAAM,MAAMP,EAAY,CACvC,QAAS,CAAE,OAAQ,aAAc,CACnC,CAAC,EAED,GAAI,CAACO,EAAS,GACZ,MAAU,MAAM,mBAAmBP,EAAW,IAAIO,EAAS,QAAQ,EAGrE,IAAMC,EAAS,MAAMD,EAAS,KAAK,EAC7BE,GAAA,EAAevB,EAAAA,MAAAA,CAAM,GAC3B,EAAAO,EAAA,MAAA,CAAMe,EAAQC,EAAcT,EAAY,aAAa,EAErD,IAAMU,EAAa,IAAIvB,EAAAA,UAAU,GAAGO,EAAc,OAAO,EACnDiB,EAAiB,IAAIxB,EAAAA,UAAU,GAAGO,EAAc,MAAM,EACtDkB,EAAgB,IAAIzB,EAAAA,UAAU,GAAGO,EAAc,KAAK,EACpDmB,EAAgB,IAAI,IAEpBC,EAAaL,EAAa,mBAAmB,IAAA,GAAWrB,EAAAA,GAAG,IAAI,MAAM,EAAGsB,CAAU,EACxF,IAAK,IAAMK,KAAaD,EAAY,CAClC,IAAME,EAAUD,EAAU,QACpBE,EAAYR,EAAa,IAAIO,EAASL,CAAc,EAC1D,GAAIM,GAAaA,EAAU,WAAa,YAAa,CACnD,IAAMC,EAAQD,EAAU,MAClBE,EAAaV,EAAa,SAASO,EAASJ,CAAa,EAC3DvB,EAAAA,UAAU6B,CAAK,GAAKC,GACtBN,EAAc,IAAIK,EAAO,CACvB,KAAM,SACN,IAAKA,EACL,MAAOC,EACP,YAAa,QACb,kBAAmB,SACnB,QAAS,CAAC,SAAS,CACrB,CAAC,CAEL,CACF,CAEA,OAAO,MAAM,KAAKN,EAAc,OAAO,CAAC,CAC1C,CAEA,MAAO,CACL,wBACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"catalogDirectory.esm.js","names":[],"sources":["../../src/directory/catalogDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { graph, type LiveStore, NamedNode, parse } from 'rdflib'\nimport { ns } from '../util/ns'\nimport * as debug from '../util/debug'\nimport { isHttpUri } from './directoryHelpers'\n\nconst CATALOG_VOCAB = 'http://example.org#'\n\nexport function createCatalogDirectoryDiscovery () {\n const catalogEntriesCache = new Map<string, Promise<DirectoryEntry[]>>()\n\n async function discoverCatalogEntries (\n catalogUrl: string,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const entries = await fetchCatalogEntries(catalogUrl)\n for (const entry of entries) {\n await onEntry(entry)\n }\n }\n\n async function fetchCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n const cached = catalogEntriesCache.get(catalogUrl)\n if (cached) {\n return cached\n }\n\n const promise = loadCatalogEntries(catalogUrl).catch(error => {\n catalogEntriesCache.delete(catalogUrl)\n throw error\n })\n\n catalogEntriesCache.set(catalogUrl, promise)\n try {\n return await promise\n } catch (error) {\n debug.warn('[Directory] Error fetching directory catalog:', error)\n return []\n }\n }\n\n async function loadCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n if (typeof fetch !== 'function') {\n throw new Error('Fetch API is unavailable')\n }\n\n const response = await fetch(catalogUrl, {\n headers: { accept: 'text/turtle' }\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${catalogUrl}: ${response.status}`)\n }\n\n const turtle = await response.text()\n const catalogStore = graph() as LiveStore\n parse(turtle, catalogStore, catalogUrl, 'text/turtle')\n\n const personType = new NamedNode(`${CATALOG_VOCAB}Person`)\n const webIdPredicate = new NamedNode(`${CATALOG_VOCAB}webid`)\n const namePredicate = new NamedNode(`${CATALOG_VOCAB}name`)\n const catalogPeople = new Map<string, DirectoryEntry>()\n\n const statements = catalogStore.statementsMatching(undefined, ns.rdf('type'), personType)\n for (const statement of statements) {\n const subject = statement.subject\n const webIdNode = catalogStore.any(subject, webIdPredicate)\n if (webIdNode && webIdNode.termType === 'NamedNode') {\n const webId = webIdNode.value\n const personName = catalogStore.anyValue(subject, namePredicate)\n if (isHttpUri(webId) && personName) {\n catalogPeople.set(webId, {\n kind: 'person',\n uri: webId,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: 'People',\n sources: ['catalog']\n })\n }\n }\n }\n\n return Array.from(catalogPeople.values())\n }\n\n return {\n discoverCatalogEntries\n }\n}\n"],"mappings":";;;;;AAMA,IAAM,IAAgB;AAEtB,SAAgB,IAAmC;CACjD,IAAM,oBAAsB,IAAI,IAAuC;CAEvE,eAAe,EACb,GACA,GACe;EACf,IAAM,IAAU,MAAM,EAAoB,CAAU;EACpD,KAAK,IAAM,KAAS,GAClB,MAAM,EAAQ,CAAK;CAEvB;CAEA,eAAe,EAAqB,GAA+C;EACjF,IAAM,IAAS,EAAoB,IAAI,CAAU;EACjD,IAAI,GACF,OAAO;EAGT,IAAM,IAAU,EAAmB,CAAU,CAAC,CAAC,OAAM,MAAS;GAE5D,MADA,EAAoB,OAAO,CAAU,GAC/B;EACR,CAAC;EAED,EAAoB,IAAI,GAAY,CAAO;EAC3C,IAAI;GACF,OAAO,MAAM;EACf,SAAS,GAAO;GAEd,OADA,EAAW,iDAAiD,CAAK,GAC1D,CAAC;EACV;CACF;CAEA,eAAe,EAAoB,GAA+C;EAChF,IAAI,OAAO,SAAU,YACnB,MAAU,MAAM,0BAA0B;EAG5C,IAAM,IAAW,MAAM,MAAM,GAAY,EACvC,SAAS,EAAE,QAAQ,cAAc,EACnC,CAAC;EAED,IAAI,CAAC,EAAS,IACZ,MAAU,MAAM,mBAAmB,EAAW,IAAI,EAAS,QAAQ;EAGrE,IAAM,IAAS,MAAM,EAAS,KAAK,GAC7B,IAAe,EAAM;EAC3B,EAAM,GAAQ,GAAc,GAAY,aAAa;EAErD,IAAM,IAAa,IAAI,EAAU,GAAG,EAAc,OAAO,GACnD,IAAiB,IAAI,EAAU,GAAG,EAAc,MAAM,GACtD,IAAgB,IAAI,EAAU,GAAG,EAAc,KAAK,GACpD,oBAAgB,IAAI,IAA4B,GAEhD,IAAa,EAAa,mBAAmB,KAAA,GAAW,EAAG,IAAI,MAAM,GAAG,CAAU;EACxF,KAAK,IAAM,KAAa,GAAY;GAClC,IAAM,IAAU,EAAU,SACpB,IAAY,EAAa,IAAI,GAAS,CAAc;GAC1D,IAAI,KAAa,EAAU,aAAa,aAAa;IACnD,IAAM,IAAQ,EAAU,OAClB,IAAa,EAAa,SAAS,GAAS,CAAa;IAC/D,AAAI,EAAU,CAAK,KAAK,KACtB,EAAc,IAAI,GAAO;KACvB,MAAM;KACN,KAAK;KACL,OAAO;KACP,aAAa;KACb,mBAAmB;KACnB,SAAS,CAAC,SAAS;IACrB,CAAC;GAEL;EACF;EAEA,OAAO,MAAM,KAAK,EAAc,OAAO,CAAC;CAC1C;CAEA,OAAO,EACL,0BACF;AACF"}
1
+ {"version":3,"file":"catalogDirectory.esm.js","names":["CATALOG_VOCAB","createCatalogDirectoryDiscovery","catalogEntriesCache","discoverCatalogEntries","entries","fetchCatalogEntries","catalogUrl","entry","onEntry","cached","promise","loadCatalogEntries","error","warn","response","turtle","catalogStore","graph","personType","NamedNode","webIdPredicate","namePredicate","catalogPeople","statements","ns","statement","subject","webIdNode","webId","personName","isHttpUri"],"sources":["../../src/directory/catalogDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { graph, type LiveStore, NamedNode, parse } from 'rdflib'\nimport { ns } from '../util/ns'\nimport * as debug from '../util/debug'\nimport { isHttpUri } from './directoryHelpers'\n\nconst CATALOG_VOCAB = 'http://example.org#'\n\nexport function createCatalogDirectoryDiscovery () {\n const catalogEntriesCache = new Map<string, Promise<DirectoryEntry[]>>()\n\n async function discoverCatalogEntries (\n catalogUrl: string,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const entries = await fetchCatalogEntries(catalogUrl)\n for (const entry of entries) {\n await onEntry(entry)\n }\n }\n\n async function fetchCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n const cached = catalogEntriesCache.get(catalogUrl)\n if (cached) {\n return cached\n }\n\n const promise = loadCatalogEntries(catalogUrl).catch(error => {\n catalogEntriesCache.delete(catalogUrl)\n throw error\n })\n\n catalogEntriesCache.set(catalogUrl, promise)\n try {\n return await promise\n } catch (error) {\n debug.warn('[Directory] Error fetching directory catalog:', error)\n return []\n }\n }\n\n async function loadCatalogEntries (catalogUrl: string): Promise<DirectoryEntry[]> {\n if (typeof fetch !== 'function') {\n throw new Error('Fetch API is unavailable')\n }\n\n const response = await fetch(catalogUrl, {\n headers: { accept: 'text/turtle' }\n })\n\n if (!response.ok) {\n throw new Error(`Failed to fetch ${catalogUrl}: ${response.status}`)\n }\n\n const turtle = await response.text()\n const catalogStore = graph() as LiveStore\n parse(turtle, catalogStore, catalogUrl, 'text/turtle')\n\n const personType = new NamedNode(`${CATALOG_VOCAB}Person`)\n const webIdPredicate = new NamedNode(`${CATALOG_VOCAB}webid`)\n const namePredicate = new NamedNode(`${CATALOG_VOCAB}name`)\n const catalogPeople = new Map<string, DirectoryEntry>()\n\n const statements = catalogStore.statementsMatching(undefined, ns.rdf('type'), personType)\n for (const statement of statements) {\n const subject = statement.subject\n const webIdNode = catalogStore.any(subject, webIdPredicate)\n if (webIdNode && webIdNode.termType === 'NamedNode') {\n const webId = webIdNode.value\n const personName = catalogStore.anyValue(subject, namePredicate)\n if (isHttpUri(webId) && personName) {\n catalogPeople.set(webId, {\n kind: 'person',\n uri: webId,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: 'People',\n sources: ['catalog']\n })\n }\n }\n }\n\n return Array.from(catalogPeople.values())\n }\n\n return {\n discoverCatalogEntries\n }\n}\n"],"mappings":";;;;;AAMA,IAAMA,IAAgB;AAEtB,SAAgBC,IAAmC;CACjD,IAAMC,oBAAsB,IAAI,IAAuC;CAEvE,eAAeC,EACb,GACA,GACe;EACf,IAAMC,IAAU,MAAMC,EAAoBC,CAAU;EACpD,KAAK,IAAMC,KAASH,GAClB,MAAMI,EAAQD,CAAK;CAEvB;CAEA,eAAeF,EAAqB,GAA+C;EACjF,IAAMI,IAASP,EAAoB,IAAII,CAAU;EACjD,IAAIG,GACF,OAAOA;EAGT,IAAMC,IAAUC,EAAmBL,CAAU,CAAC,CAAC,OAAM,MAAS;GAE5D,MADAJ,EAAoB,OAAOI,CAAU,GAC/BM;EACR,CAAC;EAED,EAAoB,IAAIN,GAAYI,CAAO;EAC3C,IAAI;GACF,OAAO,MAAMA;EACf,SAASE,GAAO;GAEd,OADAC,EAAW,iDAAiDD,CAAK,GAC1D,CAAC;EACV;CACF;CAEA,eAAeD,EAAoB,GAA+C;EAChF,IAAI,OAAO,SAAU,YACnB,MAAU,MAAM,0BAA0B;EAG5C,IAAMG,IAAW,MAAM,MAAMR,GAAY,EACvC,SAAS,EAAE,QAAQ,cAAc,EACnC,CAAC;EAED,IAAI,CAACQ,EAAS,IACZ,MAAU,MAAM,mBAAmBR,EAAW,IAAIQ,EAAS,QAAQ;EAGrE,IAAMC,IAAS,MAAMD,EAAS,KAAK,GAC7BE,IAAeC,EAAM;EAC3B,EAAMF,GAAQC,GAAcV,GAAY,aAAa;EAErD,IAAMY,IAAa,IAAIC,EAAU,GAAGnB,EAAc,OAAO,GACnDoB,IAAiB,IAAID,EAAU,GAAGnB,EAAc,MAAM,GACtDqB,IAAgB,IAAIF,EAAU,GAAGnB,EAAc,KAAK,GACpDsB,oBAAgB,IAAI,IAA4B,GAEhDC,IAAaP,EAAa,mBAAmB,KAAA,GAAWQ,EAAG,IAAI,MAAM,GAAGN,CAAU;EACxF,KAAK,IAAMO,KAAaF,GAAY;GAClC,IAAMG,IAAUD,EAAU,SACpBE,IAAYX,EAAa,IAAIU,GAASN,CAAc;GAC1D,IAAIO,KAAaA,EAAU,aAAa,aAAa;IACnD,IAAMC,IAAQD,EAAU,OAClBE,IAAab,EAAa,SAASU,GAASL,CAAa;IAC/D,AAAIS,EAAUF,CAAK,KAAKC,KACtBP,EAAc,IAAIM,GAAO;KACvB,MAAM;KACN,KAAKA;KACL,OAAOC;KACP,aAAa;KACb,mBAAmB;KACnB,SAAS,CAAC,SAAS;IACrB,CAAC;GAEL;EACF;EAEA,OAAO,MAAM,KAAKP,EAAc,OAAO,CAAC;CAC1C;CAEA,OAAO,EACL,0BACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"contactsDirectory.cjs.js","names":[],"sources":["../../src/directory/contactsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { isHttpUri, labelForNode, loadDocumentSilently, uniqueNamedNodes } from './directoryHelpers'\n\nconst CONTACT_CARD_CONCURRENCY = 8\n\nexport function createContactsDirectoryDiscovery (\n store: LiveStore,\n typeIndexLogic: TypeIndexLogic\n) {\n const personalAddressBooksCache = new Map<string, Promise<NamedNode[]>>()\n const contactWebIdCache = new Map<string, Promise<string | null>>()\n\n async function loadPersonalAddressBooks (user: NamedNode): Promise<NamedNode[]> {\n const cached = personalAddressBooksCache.get(user.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n const scopes = await typeIndexLogic.loadTypeIndexesFor(user)\n let scopedApps = [] as Awaited<ReturnType<TypeIndexLogic['getScopedAppsFromIndex']>>\n\n for (const scope of scopes) {\n const apps = await typeIndexLogic.getScopedAppsFromIndex(scope, ns.vcard('AddressBook'))\n scopedApps = scopedApps.concat(apps)\n }\n\n return uniqueNamedNodes(scopedApps.map(app => app.instance))\n })().catch(error => {\n personalAddressBooksCache.delete(user.value)\n throw error\n })\n\n personalAddressBooksCache.set(user.value, promise)\n return promise\n }\n\n async function webIdForAddressBookContact (contact: NamedNode): Promise<string | null> {\n const cached = contactWebIdCache.get(contact.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n if (!await loadDocumentSilently(store, contact)) {\n return null\n }\n\n const urlNodes = store.each(contact, ns.vcard('url'), null, contact.doc()) as NamedNode[]\n for (const urlNode of urlNodes) {\n const webId = resolveWebIdFromAddressBookUrlNode(urlNode, contact.doc())\n if (webId) {\n return webId\n }\n }\n\n return null\n })().catch(error => {\n contactWebIdCache.delete(contact.value)\n throw error\n })\n\n contactWebIdCache.set(contact.value, promise)\n return promise\n }\n\n function resolveWebIdFromAddressBookUrlNode (urlNode: NamedNode, doc: NamedNode): string | null {\n if (!store.holds(urlNode, ns.rdf('type'), ns.vcard('WebID'), doc)) {\n return null\n }\n\n const valueNode = store.any(urlNode, ns.vcard('value'), null, doc)\n const webId = valueNode?.value || ''\n return isHttpUri(webId) ? webId : null\n }\n\n async function discoverAddressBookContacts (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const nameEmailIndex = store.any(book, ns.vcard('nameEmailIndex'), null, book.doc()) as NamedNode | null\n if (nameEmailIndex) {\n if (await loadDocumentSilently(store, nameEmailIndex)) {\n const contacts = store.each(undefined, ns.vcard('inAddressBook'), book, nameEmailIndex) as NamedNode[]\n for (let index = 0; index < contacts.length; index += CONTACT_CARD_CONCURRENCY) {\n const batch = contacts.slice(index, index + CONTACT_CARD_CONCURRENCY)\n const entries = await Promise.all(batch.map(async contact => {\n const webId = await webIdForAddressBookContact(contact)\n if (!webId) {\n return null\n }\n\n return {\n kind: 'person' as const,\n uri: webId,\n label: store.anyValue(contact, ns.vcard('fn'), null, nameEmailIndex) || labelForNode(store, contact),\n subjectType: 'agent' as const,\n relationshipLabel: 'Contact' as const,\n sources: ['contacts'] as DirectorySource[]\n }\n }))\n\n for (const entry of entries.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))) {\n await onEntry(entry)\n }\n }\n }\n }\n }\n }\n }\n\n async function discoverAddressBookGroups (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const groupIndex = store.any(book, ns.vcard('groupIndex'), null, book.doc()) as NamedNode | null\n if (groupIndex) {\n if (await loadDocumentSilently(store, groupIndex)) {\n const groups = uniqueNamedNodes([\n ...(store.each(book, ns.vcard('includesGroup'), null, groupIndex) as NamedNode[]),\n ...(store.each(book, ns.vcard('includesGroup'), null, book.doc()) as NamedNode[])\n ])\n\n for (const group of groups) {\n await loadDocumentSilently(store, group)\n\n await onEntry({\n kind: 'group',\n uri: group.value,\n label: labelForNode(store, group),\n subjectType: 'agentGroup',\n relationshipLabel: 'Group',\n sources: ['groups']\n })\n }\n }\n }\n }\n }\n }\n\n return {\n discoverAddressBookContacts,\n discoverAddressBookGroups\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"contactsDirectory.cjs.js","names":["ns","uniqueNamedNodes","loadDocumentSilently","isHttpUri","labelForNode","require_ns","require_directoryHelpers","CONTACT_CARD_CONCURRENCY","createContactsDirectoryDiscovery","personalAddressBooksCache","contactWebIdCache","loadPersonalAddressBooks","cached","user","promise","scopes","typeIndexLogic","scopedApps","scope","apps","app","error","webIdForAddressBookContact","contact","store","urlNodes","urlNode","webId","resolveWebIdFromAddressBookUrlNode","doc","discoverAddressBookContacts","books","book","nameEmailIndex","contacts","index","batch","entries","entry","onEntry","discoverAddressBookGroups","groupIndex","groups","group"],"sources":["../../src/directory/contactsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { isHttpUri, labelForNode, loadDocumentSilently, uniqueNamedNodes } from './directoryHelpers'\n\nconst CONTACT_CARD_CONCURRENCY = 8\n\nexport function createContactsDirectoryDiscovery (\n store: LiveStore,\n typeIndexLogic: TypeIndexLogic\n) {\n const personalAddressBooksCache = new Map<string, Promise<NamedNode[]>>()\n const contactWebIdCache = new Map<string, Promise<string | null>>()\n\n async function loadPersonalAddressBooks (user: NamedNode): Promise<NamedNode[]> {\n const cached = personalAddressBooksCache.get(user.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n const scopes = await typeIndexLogic.loadTypeIndexesFor(user)\n let scopedApps = [] as Awaited<ReturnType<TypeIndexLogic['getScopedAppsFromIndex']>>\n\n for (const scope of scopes) {\n const apps = await typeIndexLogic.getScopedAppsFromIndex(scope, ns.vcard('AddressBook'))\n scopedApps = scopedApps.concat(apps)\n }\n\n return uniqueNamedNodes(scopedApps.map(app => app.instance))\n })().catch(error => {\n personalAddressBooksCache.delete(user.value)\n throw error\n })\n\n personalAddressBooksCache.set(user.value, promise)\n return promise\n }\n\n async function webIdForAddressBookContact (contact: NamedNode): Promise<string | null> {\n const cached = contactWebIdCache.get(contact.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n if (!await loadDocumentSilently(store, contact)) {\n return null\n }\n\n const urlNodes = store.each(contact, ns.vcard('url'), null, contact.doc()) as NamedNode[]\n for (const urlNode of urlNodes) {\n const webId = resolveWebIdFromAddressBookUrlNode(urlNode, contact.doc())\n if (webId) {\n return webId\n }\n }\n\n return null\n })().catch(error => {\n contactWebIdCache.delete(contact.value)\n throw error\n })\n\n contactWebIdCache.set(contact.value, promise)\n return promise\n }\n\n function resolveWebIdFromAddressBookUrlNode (urlNode: NamedNode, doc: NamedNode): string | null {\n if (!store.holds(urlNode, ns.rdf('type'), ns.vcard('WebID'), doc)) {\n return null\n }\n\n const valueNode = store.any(urlNode, ns.vcard('value'), null, doc)\n const webId = valueNode?.value || ''\n return isHttpUri(webId) ? webId : null\n }\n\n async function discoverAddressBookContacts (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const nameEmailIndex = store.any(book, ns.vcard('nameEmailIndex'), null, book.doc()) as NamedNode | null\n if (nameEmailIndex) {\n if (await loadDocumentSilently(store, nameEmailIndex)) {\n const contacts = store.each(undefined, ns.vcard('inAddressBook'), book, nameEmailIndex) as NamedNode[]\n for (let index = 0; index < contacts.length; index += CONTACT_CARD_CONCURRENCY) {\n const batch = contacts.slice(index, index + CONTACT_CARD_CONCURRENCY)\n const entries = await Promise.all(batch.map(async contact => {\n const webId = await webIdForAddressBookContact(contact)\n if (!webId) {\n return null\n }\n\n return {\n kind: 'person' as const,\n uri: webId,\n label: store.anyValue(contact, ns.vcard('fn'), null, nameEmailIndex) || labelForNode(store, contact),\n subjectType: 'agent' as const,\n relationshipLabel: 'Contact' as const,\n sources: ['contacts'] as DirectorySource[]\n }\n }))\n\n for (const entry of entries.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))) {\n await onEntry(entry)\n }\n }\n }\n }\n }\n }\n }\n\n async function discoverAddressBookGroups (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const groupIndex = store.any(book, ns.vcard('groupIndex'), null, book.doc()) as NamedNode | null\n if (groupIndex) {\n if (await loadDocumentSilently(store, groupIndex)) {\n const groups = uniqueNamedNodes([\n ...(store.each(book, ns.vcard('includesGroup'), null, groupIndex) as NamedNode[]),\n ...(store.each(book, ns.vcard('includesGroup'), null, book.doc()) as NamedNode[])\n ])\n\n for (const group of groups) {\n await loadDocumentSilently(store, group)\n\n await onEntry({\n kind: 'group',\n uri: group.value,\n label: labelForNode(store, group),\n subjectType: 'agentGroup',\n relationshipLabel: 'Group',\n sources: ['groups']\n })\n }\n }\n }\n }\n }\n }\n\n return {\n discoverAddressBookContacts,\n discoverAddressBookGroups\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"contactsDirectory.esm.js","names":[],"sources":["../../src/directory/contactsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { isHttpUri, labelForNode, loadDocumentSilently, uniqueNamedNodes } from './directoryHelpers'\n\nconst CONTACT_CARD_CONCURRENCY = 8\n\nexport function createContactsDirectoryDiscovery (\n store: LiveStore,\n typeIndexLogic: TypeIndexLogic\n) {\n const personalAddressBooksCache = new Map<string, Promise<NamedNode[]>>()\n const contactWebIdCache = new Map<string, Promise<string | null>>()\n\n async function loadPersonalAddressBooks (user: NamedNode): Promise<NamedNode[]> {\n const cached = personalAddressBooksCache.get(user.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n const scopes = await typeIndexLogic.loadTypeIndexesFor(user)\n let scopedApps = [] as Awaited<ReturnType<TypeIndexLogic['getScopedAppsFromIndex']>>\n\n for (const scope of scopes) {\n const apps = await typeIndexLogic.getScopedAppsFromIndex(scope, ns.vcard('AddressBook'))\n scopedApps = scopedApps.concat(apps)\n }\n\n return uniqueNamedNodes(scopedApps.map(app => app.instance))\n })().catch(error => {\n personalAddressBooksCache.delete(user.value)\n throw error\n })\n\n personalAddressBooksCache.set(user.value, promise)\n return promise\n }\n\n async function webIdForAddressBookContact (contact: NamedNode): Promise<string | null> {\n const cached = contactWebIdCache.get(contact.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n if (!await loadDocumentSilently(store, contact)) {\n return null\n }\n\n const urlNodes = store.each(contact, ns.vcard('url'), null, contact.doc()) as NamedNode[]\n for (const urlNode of urlNodes) {\n const webId = resolveWebIdFromAddressBookUrlNode(urlNode, contact.doc())\n if (webId) {\n return webId\n }\n }\n\n return null\n })().catch(error => {\n contactWebIdCache.delete(contact.value)\n throw error\n })\n\n contactWebIdCache.set(contact.value, promise)\n return promise\n }\n\n function resolveWebIdFromAddressBookUrlNode (urlNode: NamedNode, doc: NamedNode): string | null {\n if (!store.holds(urlNode, ns.rdf('type'), ns.vcard('WebID'), doc)) {\n return null\n }\n\n const valueNode = store.any(urlNode, ns.vcard('value'), null, doc)\n const webId = valueNode?.value || ''\n return isHttpUri(webId) ? webId : null\n }\n\n async function discoverAddressBookContacts (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const nameEmailIndex = store.any(book, ns.vcard('nameEmailIndex'), null, book.doc()) as NamedNode | null\n if (nameEmailIndex) {\n if (await loadDocumentSilently(store, nameEmailIndex)) {\n const contacts = store.each(undefined, ns.vcard('inAddressBook'), book, nameEmailIndex) as NamedNode[]\n for (let index = 0; index < contacts.length; index += CONTACT_CARD_CONCURRENCY) {\n const batch = contacts.slice(index, index + CONTACT_CARD_CONCURRENCY)\n const entries = await Promise.all(batch.map(async contact => {\n const webId = await webIdForAddressBookContact(contact)\n if (!webId) {\n return null\n }\n\n return {\n kind: 'person' as const,\n uri: webId,\n label: store.anyValue(contact, ns.vcard('fn'), null, nameEmailIndex) || labelForNode(store, contact),\n subjectType: 'agent' as const,\n relationshipLabel: 'Contact' as const,\n sources: ['contacts'] as DirectorySource[]\n }\n }))\n\n for (const entry of entries.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))) {\n await onEntry(entry)\n }\n }\n }\n }\n }\n }\n }\n\n async function discoverAddressBookGroups (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const groupIndex = store.any(book, ns.vcard('groupIndex'), null, book.doc()) as NamedNode | null\n if (groupIndex) {\n if (await loadDocumentSilently(store, groupIndex)) {\n const groups = uniqueNamedNodes([\n ...(store.each(book, ns.vcard('includesGroup'), null, groupIndex) as NamedNode[]),\n ...(store.each(book, ns.vcard('includesGroup'), null, book.doc()) as NamedNode[])\n ])\n\n for (const group of groups) {\n await loadDocumentSilently(store, group)\n\n await onEntry({\n kind: 'group',\n uri: group.value,\n label: labelForNode(store, group),\n subjectType: 'agentGroup',\n relationshipLabel: 'Group',\n sources: ['groups']\n })\n }\n }\n }\n }\n }\n }\n\n return {\n discoverAddressBookContacts,\n discoverAddressBookGroups\n }\n}\n"],"mappings":";;;AAKA,IAAM,IAA2B;AAEjC,SAAgB,EACd,GACA,GACA;CACA,IAAM,oBAA4B,IAAI,IAAkC,GAClE,oBAAoB,IAAI,IAAoC;CAElE,eAAe,EAA0B,GAAuC;EAC9E,IAAM,IAAS,EAA0B,IAAI,EAAK,KAAK;EACvD,IAAI,GACF,OAAO;EAGT,IAAM,KAAW,YAAY;GAC3B,IAAM,IAAS,MAAM,EAAe,mBAAmB,CAAI,GACvD,IAAa,CAAC;GAElB,KAAK,IAAM,KAAS,GAAQ;IAC1B,IAAM,IAAO,MAAM,EAAe,uBAAuB,GAAO,EAAG,MAAM,aAAa,CAAC;IACvF,IAAa,EAAW,OAAO,CAAI;GACrC;GAEA,OAAO,EAAiB,EAAW,KAAI,MAAO,EAAI,QAAQ,CAAC;EAC7D,EAAA,CAAG,CAAC,CAAC,OAAM,MAAS;GAElB,MADA,EAA0B,OAAO,EAAK,KAAK,GACrC;EACR,CAAC;EAGD,OADA,EAA0B,IAAI,EAAK,OAAO,CAAO,GAC1C;CACT;CAEA,eAAe,EAA4B,GAA4C;EACrF,IAAM,IAAS,EAAkB,IAAI,EAAQ,KAAK;EAClD,IAAI,GACF,OAAO;EAGT,IAAM,KAAW,YAAY;GAC3B,IAAI,CAAC,MAAM,EAAqB,GAAO,CAAO,GAC5C,OAAO;GAGT,IAAM,IAAW,EAAM,KAAK,GAAS,EAAG,MAAM,KAAK,GAAG,MAAM,EAAQ,IAAI,CAAC;GACzE,KAAK,IAAM,KAAW,GAAU;IAC9B,IAAM,IAAQ,EAAmC,GAAS,EAAQ,IAAI,CAAC;IACvE,IAAI,GACF,OAAO;GAEX;GAEA,OAAO;EACT,EAAA,CAAG,CAAC,CAAC,OAAM,MAAS;GAElB,MADA,EAAkB,OAAO,EAAQ,KAAK,GAChC;EACR,CAAC;EAGD,OADA,EAAkB,IAAI,EAAQ,OAAO,CAAO,GACrC;CACT;CAEA,SAAS,EAAoC,GAAoB,GAA+B;EAC9F,IAAI,CAAC,EAAM,MAAM,GAAS,EAAG,IAAI,MAAM,GAAG,EAAG,MAAM,OAAO,GAAG,CAAG,GAC9D,OAAO;EAIT,IAAM,IADY,EAAM,IAAI,GAAS,EAAG,MAAM,OAAO,GAAG,MAAM,CAChD,CAAA,EAAW,SAAS;EAClC,OAAO,EAAU,CAAK,IAAI,IAAQ;CACpC;CAEA,eAAe,EACb,GACA,GACe;EACf,IAAM,IAAQ,MAAM,EAAyB,CAAI;EAEjD,KAAK,IAAM,KAAQ,GACjB,IAAI,MAAM,EAAqB,GAAO,CAAI,GAAG;GAC3C,IAAM,IAAiB,EAAM,IAAI,GAAM,EAAG,MAAM,gBAAgB,GAAG,MAAM,EAAK,IAAI,CAAC;GACnF,IAAI,KACE,MAAM,EAAqB,GAAO,CAAc,GAAG;IACrD,IAAM,IAAW,EAAM,KAAK,KAAA,GAAW,EAAG,MAAM,eAAe,GAAG,GAAM,CAAc;IACtF,KAAK,IAAI,IAAQ,GAAG,IAAQ,EAAS,QAAQ,KAAS,GAA0B;KAC9E,IAAM,IAAQ,EAAS,MAAM,GAAO,IAAQ,CAAwB,GAC9D,IAAU,MAAM,QAAQ,IAAI,EAAM,IAAI,OAAM,MAAW;MAC3D,IAAM,IAAQ,MAAM,EAA2B,CAAO;MAKtD,OAJK,IAIE;OACL,MAAM;OACN,KAAK;OACL,OAAO,EAAM,SAAS,GAAS,EAAG,MAAM,IAAI,GAAG,MAAM,CAAc,KAAK,EAAa,GAAO,CAAO;OACnG,aAAa;OACb,mBAAmB;OACnB,SAAS,CAAC,UAAU;MACtB,IAVS;KAWX,CAAC,CAAC;KAEF,KAAK,IAAM,KAAS,EAAQ,QAAQ,MAA8C,EAAQ,CAAM,GAC9F,MAAM,EAAQ,CAAK;IAEvB;GACF;EAEJ;CAEJ;CAEA,eAAe,EACb,GACA,GACe;EACf,IAAM,IAAQ,MAAM,EAAyB,CAAI;EAEjD,KAAK,IAAM,KAAQ,GACjB,IAAI,MAAM,EAAqB,GAAO,CAAI,GAAG;GAC3C,IAAM,IAAa,EAAM,IAAI,GAAM,EAAG,MAAM,YAAY,GAAG,MAAM,EAAK,IAAI,CAAC;GAC3E,IAAI,KACE,MAAM,EAAqB,GAAO,CAAU,GAAG;IACjD,IAAM,IAAS,EAAiB,CAC9B,GAAI,EAAM,KAAK,GAAM,EAAG,MAAM,eAAe,GAAG,MAAM,CAAU,GAChE,GAAI,EAAM,KAAK,GAAM,EAAG,MAAM,eAAe,GAAG,MAAM,EAAK,IAAI,CAAC,CAClE,CAAC;IAED,KAAK,IAAM,KAAS,GAGlB,AAFA,MAAM,EAAqB,GAAO,CAAK,GAEvC,MAAM,EAAQ;KACZ,MAAM;KACN,KAAK,EAAM;KACX,OAAO,EAAa,GAAO,CAAK;KAChC,aAAa;KACb,mBAAmB;KACnB,SAAS,CAAC,QAAQ;IACpB,CAAC;GAEL;EAEJ;CAEJ;CAEA,OAAO;EACL;EACA;CACF;AACF"}
1
+ {"version":3,"file":"contactsDirectory.esm.js","names":["CONTACT_CARD_CONCURRENCY","createContactsDirectoryDiscovery","personalAddressBooksCache","contactWebIdCache","loadPersonalAddressBooks","cached","user","promise","scopes","typeIndexLogic","scopedApps","scope","apps","ns","uniqueNamedNodes","app","error","webIdForAddressBookContact","contact","loadDocumentSilently","store","urlNodes","urlNode","webId","resolveWebIdFromAddressBookUrlNode","doc","isHttpUri","discoverAddressBookContacts","books","book","nameEmailIndex","contacts","index","batch","entries","labelForNode","entry","onEntry","discoverAddressBookGroups","groupIndex","groups","group"],"sources":["../../src/directory/contactsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { isHttpUri, labelForNode, loadDocumentSilently, uniqueNamedNodes } from './directoryHelpers'\n\nconst CONTACT_CARD_CONCURRENCY = 8\n\nexport function createContactsDirectoryDiscovery (\n store: LiveStore,\n typeIndexLogic: TypeIndexLogic\n) {\n const personalAddressBooksCache = new Map<string, Promise<NamedNode[]>>()\n const contactWebIdCache = new Map<string, Promise<string | null>>()\n\n async function loadPersonalAddressBooks (user: NamedNode): Promise<NamedNode[]> {\n const cached = personalAddressBooksCache.get(user.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n const scopes = await typeIndexLogic.loadTypeIndexesFor(user)\n let scopedApps = [] as Awaited<ReturnType<TypeIndexLogic['getScopedAppsFromIndex']>>\n\n for (const scope of scopes) {\n const apps = await typeIndexLogic.getScopedAppsFromIndex(scope, ns.vcard('AddressBook'))\n scopedApps = scopedApps.concat(apps)\n }\n\n return uniqueNamedNodes(scopedApps.map(app => app.instance))\n })().catch(error => {\n personalAddressBooksCache.delete(user.value)\n throw error\n })\n\n personalAddressBooksCache.set(user.value, promise)\n return promise\n }\n\n async function webIdForAddressBookContact (contact: NamedNode): Promise<string | null> {\n const cached = contactWebIdCache.get(contact.value)\n if (cached) {\n return cached\n }\n\n const promise = (async () => {\n if (!await loadDocumentSilently(store, contact)) {\n return null\n }\n\n const urlNodes = store.each(contact, ns.vcard('url'), null, contact.doc()) as NamedNode[]\n for (const urlNode of urlNodes) {\n const webId = resolveWebIdFromAddressBookUrlNode(urlNode, contact.doc())\n if (webId) {\n return webId\n }\n }\n\n return null\n })().catch(error => {\n contactWebIdCache.delete(contact.value)\n throw error\n })\n\n contactWebIdCache.set(contact.value, promise)\n return promise\n }\n\n function resolveWebIdFromAddressBookUrlNode (urlNode: NamedNode, doc: NamedNode): string | null {\n if (!store.holds(urlNode, ns.rdf('type'), ns.vcard('WebID'), doc)) {\n return null\n }\n\n const valueNode = store.any(urlNode, ns.vcard('value'), null, doc)\n const webId = valueNode?.value || ''\n return isHttpUri(webId) ? webId : null\n }\n\n async function discoverAddressBookContacts (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const nameEmailIndex = store.any(book, ns.vcard('nameEmailIndex'), null, book.doc()) as NamedNode | null\n if (nameEmailIndex) {\n if (await loadDocumentSilently(store, nameEmailIndex)) {\n const contacts = store.each(undefined, ns.vcard('inAddressBook'), book, nameEmailIndex) as NamedNode[]\n for (let index = 0; index < contacts.length; index += CONTACT_CARD_CONCURRENCY) {\n const batch = contacts.slice(index, index + CONTACT_CARD_CONCURRENCY)\n const entries = await Promise.all(batch.map(async contact => {\n const webId = await webIdForAddressBookContact(contact)\n if (!webId) {\n return null\n }\n\n return {\n kind: 'person' as const,\n uri: webId,\n label: store.anyValue(contact, ns.vcard('fn'), null, nameEmailIndex) || labelForNode(store, contact),\n subjectType: 'agent' as const,\n relationshipLabel: 'Contact' as const,\n sources: ['contacts'] as DirectorySource[]\n }\n }))\n\n for (const entry of entries.filter((entry): entry is NonNullable<typeof entry> => Boolean(entry))) {\n await onEntry(entry)\n }\n }\n }\n }\n }\n }\n }\n\n async function discoverAddressBookGroups (\n user: NamedNode,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const books = await loadPersonalAddressBooks(user)\n\n for (const book of books) {\n if (await loadDocumentSilently(store, book)) {\n const groupIndex = store.any(book, ns.vcard('groupIndex'), null, book.doc()) as NamedNode | null\n if (groupIndex) {\n if (await loadDocumentSilently(store, groupIndex)) {\n const groups = uniqueNamedNodes([\n ...(store.each(book, ns.vcard('includesGroup'), null, groupIndex) as NamedNode[]),\n ...(store.each(book, ns.vcard('includesGroup'), null, book.doc()) as NamedNode[])\n ])\n\n for (const group of groups) {\n await loadDocumentSilently(store, group)\n\n await onEntry({\n kind: 'group',\n uri: group.value,\n label: labelForNode(store, group),\n subjectType: 'agentGroup',\n relationshipLabel: 'Group',\n sources: ['groups']\n })\n }\n }\n }\n }\n }\n }\n\n return {\n discoverAddressBookContacts,\n discoverAddressBookGroups\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"directoryHelpers.cjs.js","names":[],"sources":["../../src/directory/directoryHelpers.ts"],"sourcesContent":["import type { LiveStore, NamedNode } from 'rdflib'\nimport type { DirectoryEntry, DirectoryRelationshipLabel, DirectorySource } from '../types'\nimport { ns } from '../util/ns'\n\nconst DIRECTORY_SOURCE_PRIORITY: DirectorySource[] = ['contacts', 'groups', 'friends', 'catalog']\n\nexport function tokenizeQuery (query: string): string[] {\n return query\n .toLowerCase()\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n}\n\nexport function matchesQuery (label: string, query: string): boolean {\n return matchesAnyLabel([label], query)\n}\n\nexport function matchesAnyLabel (labels: string[], query: string): boolean {\n const queryWords = tokenizeQuery(query)\n if (queryWords.length === 0) return true\n\n const labelWords = labels.flatMap(label => tokenizeQuery(label))\n const fallbackHaystack = labels.join(' ').toLowerCase()\n return queryWords.every(word =>\n labelWords.some(labelWord => labelWord.includes(word)) || fallbackHaystack.includes(word)\n )\n}\n\nexport function sortEntries (entries: Iterable<DirectoryEntry>): DirectoryEntry[] {\n return Array.from(entries)\n .sort((left, right) => left.label.localeCompare(right.label, undefined, { sensitivity: 'base' }))\n}\n\nexport function mergeDirectoryEntry (\n discoveredEntries: Map<string, DirectoryEntry>,\n entry: DirectoryEntry\n): DirectoryEntry {\n const key = directoryEntryKey(entry)\n const existing = discoveredEntries.get(key)\n if (existing) {\n const preferred = preferredDirectoryEntry(existing, entry)\n const labels = canonicalizeSearchableLabels(\n preferred.label,\n [...(existing.searchableLabels ?? [existing.label]), ...(entry.searchableLabels ?? [entry.label])]\n )\n const merged = {\n ...existing,\n label: preferred.label,\n relationshipLabel: bestRelationshipLabel(existing.relationshipLabel, entry.relationshipLabel),\n sources: canonicalizeDirectorySources([...existing.sources, ...entry.sources]),\n searchableLabels: labels\n }\n discoveredEntries.set(key, merged)\n return merged\n }\n\n const normalized = {\n ...entry,\n sources: canonicalizeDirectorySources(entry.sources),\n searchableLabels: entry.searchableLabels ?? [entry.label]\n }\n discoveredEntries.set(key, normalized)\n return normalized\n}\n\nfunction preferredDirectoryEntry (current: DirectoryEntry, incoming: DirectoryEntry): DirectoryEntry {\n return directoryEntrySourcePriority(incoming) < directoryEntrySourcePriority(current) ? incoming : current\n}\n\nfunction directoryEntrySourcePriority (entry: DirectoryEntry): number {\n const priorities = entry.sources.map(source => DIRECTORY_SOURCE_PRIORITY.indexOf(source))\n return priorities.length ? Math.min(...priorities) : DIRECTORY_SOURCE_PRIORITY.length\n}\n\nexport function canonicalizeDirectorySources (sources: DirectorySource[]): DirectorySource[] {\n return DIRECTORY_SOURCE_PRIORITY.filter(source => sources.includes(source))\n}\n\nfunction canonicalizeSearchableLabels (preferredLabel: string, labels: string[]): string[] {\n return uniqueStrings(labels).sort((left, right) => {\n if (left === preferredLabel) return -1\n if (right === preferredLabel) return 1\n return left.localeCompare(right, undefined, { sensitivity: 'base' })\n })\n}\n\nexport function bestRelationshipLabel (\n current: DirectoryRelationshipLabel | undefined,\n incoming: DirectoryRelationshipLabel\n): DirectoryRelationshipLabel {\n if (current === 'Contact' || incoming === 'Contact') return 'Contact'\n if (current === 'Friend' || incoming === 'Friend') return 'Friend'\n if (current === 'Group' || incoming === 'Group') return 'Group'\n return 'People'\n}\n\nexport function directoryEntryKey (entry: DirectoryEntry): string {\n return `${entry.kind}:${entry.uri}`\n}\n\nexport function uniqueNamedNodes (nodes: NamedNode[]): NamedNode[] {\n const seen = new Set<string>()\n return nodes.filter(node => {\n if (seen.has(node.value)) return false\n seen.add(node.value)\n return true\n })\n}\n\nexport function uniqueStrings<T extends string> (values: T[]): T[] {\n return [...new Set(values)]\n}\n\nexport function isHttpUri (value: string | null | undefined): boolean {\n return !!value && (value.startsWith('https://') || value.startsWith('http://'))\n}\n\nexport function fallbackLabel (uri: string): string {\n const withoutFragment = uri.split('#')[0]\n const fragment = uri.includes('#') ? uri.slice(uri.indexOf('#') + 1) : ''\n const base = fragment && fragment !== 'this' && fragment !== 'me'\n ? fragment\n : withoutFragment.slice(withoutFragment.lastIndexOf('/') + 1)\n return decodeURIComponent(base || uri).replace(/[_-]+/g, ' ')\n}\n\nexport function storedLabelForNode (store: LiveStore, node: NamedNode): string | null {\n return store.anyValue(node, ns.vcard('fn')) ||\n store.anyValue(node, ns.foaf('name')) ||\n store.anyValue(node, ns.schema('name')) ||\n store.anyValue(node, ns.rdfs('label')) ||\n null\n}\n\nexport function labelForNode (store: LiveStore, node: NamedNode): string {\n return storedLabelForNode(store, node) || fallbackLabel(node.value)\n}\n\nexport async function loadDocumentSilently (store: LiveStore, node: NamedNode): Promise<boolean> {\n try {\n await store.fetcher.load(node.doc())\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"directoryHelpers.cjs.js","names":["ns","require_ns","DIRECTORY_SOURCE_PRIORITY","tokenizeQuery","query","matchesAnyLabel","queryWords","labelWords","labels","label","fallbackHaystack","labelWord","word","sortEntries","entries","left","right","mergeDirectoryEntry","key","directoryEntryKey","entry","existing","discoveredEntries","preferred","preferredDirectoryEntry","canonicalizeSearchableLabels","merged","bestRelationshipLabel","canonicalizeDirectorySources","normalized","directoryEntrySourcePriority","incoming","current","priorities","source","sources","uniqueStrings","preferredLabel","uniqueNamedNodes","seen","nodes","node","values","isHttpUri","value","fallbackLabel","withoutFragment","uri","fragment","base","storedLabelForNode","store","labelForNode","loadDocumentSilently"],"sources":["../../src/directory/directoryHelpers.ts"],"sourcesContent":["import type { LiveStore, NamedNode } from 'rdflib'\nimport type { DirectoryEntry, DirectoryRelationshipLabel, DirectorySource } from '../types'\nimport { ns } from '../util/ns'\n\nconst DIRECTORY_SOURCE_PRIORITY: DirectorySource[] = ['contacts', 'groups', 'friends', 'catalog']\n\nexport function tokenizeQuery (query: string): string[] {\n return query\n .toLowerCase()\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n}\n\nexport function matchesQuery (label: string, query: string): boolean {\n return matchesAnyLabel([label], query)\n}\n\nexport function matchesAnyLabel (labels: string[], query: string): boolean {\n const queryWords = tokenizeQuery(query)\n if (queryWords.length === 0) return true\n\n const labelWords = labels.flatMap(label => tokenizeQuery(label))\n const fallbackHaystack = labels.join(' ').toLowerCase()\n return queryWords.every(word =>\n labelWords.some(labelWord => labelWord.includes(word)) || fallbackHaystack.includes(word)\n )\n}\n\nexport function sortEntries (entries: Iterable<DirectoryEntry>): DirectoryEntry[] {\n return Array.from(entries)\n .sort((left, right) => left.label.localeCompare(right.label, undefined, { sensitivity: 'base' }))\n}\n\nexport function mergeDirectoryEntry (\n discoveredEntries: Map<string, DirectoryEntry>,\n entry: DirectoryEntry\n): DirectoryEntry {\n const key = directoryEntryKey(entry)\n const existing = discoveredEntries.get(key)\n if (existing) {\n const preferred = preferredDirectoryEntry(existing, entry)\n const labels = canonicalizeSearchableLabels(\n preferred.label,\n [...(existing.searchableLabels ?? [existing.label]), ...(entry.searchableLabels ?? [entry.label])]\n )\n const merged = {\n ...existing,\n label: preferred.label,\n relationshipLabel: bestRelationshipLabel(existing.relationshipLabel, entry.relationshipLabel),\n sources: canonicalizeDirectorySources([...existing.sources, ...entry.sources]),\n searchableLabels: labels\n }\n discoveredEntries.set(key, merged)\n return merged\n }\n\n const normalized = {\n ...entry,\n sources: canonicalizeDirectorySources(entry.sources),\n searchableLabels: entry.searchableLabels ?? [entry.label]\n }\n discoveredEntries.set(key, normalized)\n return normalized\n}\n\nfunction preferredDirectoryEntry (current: DirectoryEntry, incoming: DirectoryEntry): DirectoryEntry {\n return directoryEntrySourcePriority(incoming) < directoryEntrySourcePriority(current) ? incoming : current\n}\n\nfunction directoryEntrySourcePriority (entry: DirectoryEntry): number {\n const priorities = entry.sources.map(source => DIRECTORY_SOURCE_PRIORITY.indexOf(source))\n return priorities.length ? Math.min(...priorities) : DIRECTORY_SOURCE_PRIORITY.length\n}\n\nexport function canonicalizeDirectorySources (sources: DirectorySource[]): DirectorySource[] {\n return DIRECTORY_SOURCE_PRIORITY.filter(source => sources.includes(source))\n}\n\nfunction canonicalizeSearchableLabels (preferredLabel: string, labels: string[]): string[] {\n return uniqueStrings(labels).sort((left, right) => {\n if (left === preferredLabel) return -1\n if (right === preferredLabel) return 1\n return left.localeCompare(right, undefined, { sensitivity: 'base' })\n })\n}\n\nexport function bestRelationshipLabel (\n current: DirectoryRelationshipLabel | undefined,\n incoming: DirectoryRelationshipLabel\n): DirectoryRelationshipLabel {\n if (current === 'Contact' || incoming === 'Contact') return 'Contact'\n if (current === 'Friend' || incoming === 'Friend') return 'Friend'\n if (current === 'Group' || incoming === 'Group') return 'Group'\n return 'People'\n}\n\nexport function directoryEntryKey (entry: DirectoryEntry): string {\n return `${entry.kind}:${entry.uri}`\n}\n\nexport function uniqueNamedNodes (nodes: NamedNode[]): NamedNode[] {\n const seen = new Set<string>()\n return nodes.filter(node => {\n if (seen.has(node.value)) return false\n seen.add(node.value)\n return true\n })\n}\n\nexport function uniqueStrings<T extends string> (values: T[]): T[] {\n return [...new Set(values)]\n}\n\nexport function isHttpUri (value: string | null | undefined): boolean {\n return !!value && (value.startsWith('https://') || value.startsWith('http://'))\n}\n\nexport function fallbackLabel (uri: string): string {\n const withoutFragment = uri.split('#')[0]\n const fragment = uri.includes('#') ? uri.slice(uri.indexOf('#') + 1) : ''\n const base = fragment && fragment !== 'this' && fragment !== 'me'\n ? fragment\n : withoutFragment.slice(withoutFragment.lastIndexOf('/') + 1)\n return decodeURIComponent(base || uri).replace(/[_-]+/g, ' ')\n}\n\nexport function storedLabelForNode (store: LiveStore, node: NamedNode): string | null {\n return store.anyValue(node, ns.vcard('fn')) ||\n store.anyValue(node, ns.foaf('name')) ||\n store.anyValue(node, ns.schema('name')) ||\n store.anyValue(node, ns.rdfs('label')) ||\n null\n}\n\nexport function labelForNode (store: LiveStore, node: NamedNode): string {\n return storedLabelForNode(store, node) || fallbackLabel(node.value)\n}\n\nexport async function loadDocumentSilently (store: LiveStore, node: NamedNode): Promise<boolean> {\n try {\n await store.fetcher.load(node.doc())\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"directoryHelpers.esm.js","names":[],"sources":["../../src/directory/directoryHelpers.ts"],"sourcesContent":["import type { LiveStore, NamedNode } from 'rdflib'\nimport type { DirectoryEntry, DirectoryRelationshipLabel, DirectorySource } from '../types'\nimport { ns } from '../util/ns'\n\nconst DIRECTORY_SOURCE_PRIORITY: DirectorySource[] = ['contacts', 'groups', 'friends', 'catalog']\n\nexport function tokenizeQuery (query: string): string[] {\n return query\n .toLowerCase()\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n}\n\nexport function matchesQuery (label: string, query: string): boolean {\n return matchesAnyLabel([label], query)\n}\n\nexport function matchesAnyLabel (labels: string[], query: string): boolean {\n const queryWords = tokenizeQuery(query)\n if (queryWords.length === 0) return true\n\n const labelWords = labels.flatMap(label => tokenizeQuery(label))\n const fallbackHaystack = labels.join(' ').toLowerCase()\n return queryWords.every(word =>\n labelWords.some(labelWord => labelWord.includes(word)) || fallbackHaystack.includes(word)\n )\n}\n\nexport function sortEntries (entries: Iterable<DirectoryEntry>): DirectoryEntry[] {\n return Array.from(entries)\n .sort((left, right) => left.label.localeCompare(right.label, undefined, { sensitivity: 'base' }))\n}\n\nexport function mergeDirectoryEntry (\n discoveredEntries: Map<string, DirectoryEntry>,\n entry: DirectoryEntry\n): DirectoryEntry {\n const key = directoryEntryKey(entry)\n const existing = discoveredEntries.get(key)\n if (existing) {\n const preferred = preferredDirectoryEntry(existing, entry)\n const labels = canonicalizeSearchableLabels(\n preferred.label,\n [...(existing.searchableLabels ?? [existing.label]), ...(entry.searchableLabels ?? [entry.label])]\n )\n const merged = {\n ...existing,\n label: preferred.label,\n relationshipLabel: bestRelationshipLabel(existing.relationshipLabel, entry.relationshipLabel),\n sources: canonicalizeDirectorySources([...existing.sources, ...entry.sources]),\n searchableLabels: labels\n }\n discoveredEntries.set(key, merged)\n return merged\n }\n\n const normalized = {\n ...entry,\n sources: canonicalizeDirectorySources(entry.sources),\n searchableLabels: entry.searchableLabels ?? [entry.label]\n }\n discoveredEntries.set(key, normalized)\n return normalized\n}\n\nfunction preferredDirectoryEntry (current: DirectoryEntry, incoming: DirectoryEntry): DirectoryEntry {\n return directoryEntrySourcePriority(incoming) < directoryEntrySourcePriority(current) ? incoming : current\n}\n\nfunction directoryEntrySourcePriority (entry: DirectoryEntry): number {\n const priorities = entry.sources.map(source => DIRECTORY_SOURCE_PRIORITY.indexOf(source))\n return priorities.length ? Math.min(...priorities) : DIRECTORY_SOURCE_PRIORITY.length\n}\n\nexport function canonicalizeDirectorySources (sources: DirectorySource[]): DirectorySource[] {\n return DIRECTORY_SOURCE_PRIORITY.filter(source => sources.includes(source))\n}\n\nfunction canonicalizeSearchableLabels (preferredLabel: string, labels: string[]): string[] {\n return uniqueStrings(labels).sort((left, right) => {\n if (left === preferredLabel) return -1\n if (right === preferredLabel) return 1\n return left.localeCompare(right, undefined, { sensitivity: 'base' })\n })\n}\n\nexport function bestRelationshipLabel (\n current: DirectoryRelationshipLabel | undefined,\n incoming: DirectoryRelationshipLabel\n): DirectoryRelationshipLabel {\n if (current === 'Contact' || incoming === 'Contact') return 'Contact'\n if (current === 'Friend' || incoming === 'Friend') return 'Friend'\n if (current === 'Group' || incoming === 'Group') return 'Group'\n return 'People'\n}\n\nexport function directoryEntryKey (entry: DirectoryEntry): string {\n return `${entry.kind}:${entry.uri}`\n}\n\nexport function uniqueNamedNodes (nodes: NamedNode[]): NamedNode[] {\n const seen = new Set<string>()\n return nodes.filter(node => {\n if (seen.has(node.value)) return false\n seen.add(node.value)\n return true\n })\n}\n\nexport function uniqueStrings<T extends string> (values: T[]): T[] {\n return [...new Set(values)]\n}\n\nexport function isHttpUri (value: string | null | undefined): boolean {\n return !!value && (value.startsWith('https://') || value.startsWith('http://'))\n}\n\nexport function fallbackLabel (uri: string): string {\n const withoutFragment = uri.split('#')[0]\n const fragment = uri.includes('#') ? uri.slice(uri.indexOf('#') + 1) : ''\n const base = fragment && fragment !== 'this' && fragment !== 'me'\n ? fragment\n : withoutFragment.slice(withoutFragment.lastIndexOf('/') + 1)\n return decodeURIComponent(base || uri).replace(/[_-]+/g, ' ')\n}\n\nexport function storedLabelForNode (store: LiveStore, node: NamedNode): string | null {\n return store.anyValue(node, ns.vcard('fn')) ||\n store.anyValue(node, ns.foaf('name')) ||\n store.anyValue(node, ns.schema('name')) ||\n store.anyValue(node, ns.rdfs('label')) ||\n null\n}\n\nexport function labelForNode (store: LiveStore, node: NamedNode): string {\n return storedLabelForNode(store, node) || fallbackLabel(node.value)\n}\n\nexport async function loadDocumentSilently (store: LiveStore, node: NamedNode): Promise<boolean> {\n try {\n await store.fetcher.load(node.doc())\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"directoryHelpers.esm.js","names":["DIRECTORY_SOURCE_PRIORITY","tokenizeQuery","query","matchesAnyLabel","queryWords","labelWords","labels","label","fallbackHaystack","labelWord","word","sortEntries","entries","left","right","mergeDirectoryEntry","key","directoryEntryKey","entry","existing","discoveredEntries","preferred","preferredDirectoryEntry","canonicalizeSearchableLabels","merged","bestRelationshipLabel","canonicalizeDirectorySources","normalized","directoryEntrySourcePriority","incoming","current","priorities","source","sources","uniqueStrings","preferredLabel","uniqueNamedNodes","seen","nodes","node","values","isHttpUri","value","fallbackLabel","withoutFragment","uri","fragment","base","storedLabelForNode","store","ns","labelForNode","loadDocumentSilently"],"sources":["../../src/directory/directoryHelpers.ts"],"sourcesContent":["import type { LiveStore, NamedNode } from 'rdflib'\nimport type { DirectoryEntry, DirectoryRelationshipLabel, DirectorySource } from '../types'\nimport { ns } from '../util/ns'\n\nconst DIRECTORY_SOURCE_PRIORITY: DirectorySource[] = ['contacts', 'groups', 'friends', 'catalog']\n\nexport function tokenizeQuery (query: string): string[] {\n return query\n .toLowerCase()\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n}\n\nexport function matchesQuery (label: string, query: string): boolean {\n return matchesAnyLabel([label], query)\n}\n\nexport function matchesAnyLabel (labels: string[], query: string): boolean {\n const queryWords = tokenizeQuery(query)\n if (queryWords.length === 0) return true\n\n const labelWords = labels.flatMap(label => tokenizeQuery(label))\n const fallbackHaystack = labels.join(' ').toLowerCase()\n return queryWords.every(word =>\n labelWords.some(labelWord => labelWord.includes(word)) || fallbackHaystack.includes(word)\n )\n}\n\nexport function sortEntries (entries: Iterable<DirectoryEntry>): DirectoryEntry[] {\n return Array.from(entries)\n .sort((left, right) => left.label.localeCompare(right.label, undefined, { sensitivity: 'base' }))\n}\n\nexport function mergeDirectoryEntry (\n discoveredEntries: Map<string, DirectoryEntry>,\n entry: DirectoryEntry\n): DirectoryEntry {\n const key = directoryEntryKey(entry)\n const existing = discoveredEntries.get(key)\n if (existing) {\n const preferred = preferredDirectoryEntry(existing, entry)\n const labels = canonicalizeSearchableLabels(\n preferred.label,\n [...(existing.searchableLabels ?? [existing.label]), ...(entry.searchableLabels ?? [entry.label])]\n )\n const merged = {\n ...existing,\n label: preferred.label,\n relationshipLabel: bestRelationshipLabel(existing.relationshipLabel, entry.relationshipLabel),\n sources: canonicalizeDirectorySources([...existing.sources, ...entry.sources]),\n searchableLabels: labels\n }\n discoveredEntries.set(key, merged)\n return merged\n }\n\n const normalized = {\n ...entry,\n sources: canonicalizeDirectorySources(entry.sources),\n searchableLabels: entry.searchableLabels ?? [entry.label]\n }\n discoveredEntries.set(key, normalized)\n return normalized\n}\n\nfunction preferredDirectoryEntry (current: DirectoryEntry, incoming: DirectoryEntry): DirectoryEntry {\n return directoryEntrySourcePriority(incoming) < directoryEntrySourcePriority(current) ? incoming : current\n}\n\nfunction directoryEntrySourcePriority (entry: DirectoryEntry): number {\n const priorities = entry.sources.map(source => DIRECTORY_SOURCE_PRIORITY.indexOf(source))\n return priorities.length ? Math.min(...priorities) : DIRECTORY_SOURCE_PRIORITY.length\n}\n\nexport function canonicalizeDirectorySources (sources: DirectorySource[]): DirectorySource[] {\n return DIRECTORY_SOURCE_PRIORITY.filter(source => sources.includes(source))\n}\n\nfunction canonicalizeSearchableLabels (preferredLabel: string, labels: string[]): string[] {\n return uniqueStrings(labels).sort((left, right) => {\n if (left === preferredLabel) return -1\n if (right === preferredLabel) return 1\n return left.localeCompare(right, undefined, { sensitivity: 'base' })\n })\n}\n\nexport function bestRelationshipLabel (\n current: DirectoryRelationshipLabel | undefined,\n incoming: DirectoryRelationshipLabel\n): DirectoryRelationshipLabel {\n if (current === 'Contact' || incoming === 'Contact') return 'Contact'\n if (current === 'Friend' || incoming === 'Friend') return 'Friend'\n if (current === 'Group' || incoming === 'Group') return 'Group'\n return 'People'\n}\n\nexport function directoryEntryKey (entry: DirectoryEntry): string {\n return `${entry.kind}:${entry.uri}`\n}\n\nexport function uniqueNamedNodes (nodes: NamedNode[]): NamedNode[] {\n const seen = new Set<string>()\n return nodes.filter(node => {\n if (seen.has(node.value)) return false\n seen.add(node.value)\n return true\n })\n}\n\nexport function uniqueStrings<T extends string> (values: T[]): T[] {\n return [...new Set(values)]\n}\n\nexport function isHttpUri (value: string | null | undefined): boolean {\n return !!value && (value.startsWith('https://') || value.startsWith('http://'))\n}\n\nexport function fallbackLabel (uri: string): string {\n const withoutFragment = uri.split('#')[0]\n const fragment = uri.includes('#') ? uri.slice(uri.indexOf('#') + 1) : ''\n const base = fragment && fragment !== 'this' && fragment !== 'me'\n ? fragment\n : withoutFragment.slice(withoutFragment.lastIndexOf('/') + 1)\n return decodeURIComponent(base || uri).replace(/[_-]+/g, ' ')\n}\n\nexport function storedLabelForNode (store: LiveStore, node: NamedNode): string | null {\n return store.anyValue(node, ns.vcard('fn')) ||\n store.anyValue(node, ns.foaf('name')) ||\n store.anyValue(node, ns.schema('name')) ||\n store.anyValue(node, ns.rdfs('label')) ||\n null\n}\n\nexport function labelForNode (store: LiveStore, node: NamedNode): string {\n return storedLabelForNode(store, node) || fallbackLabel(node.value)\n}\n\nexport async function loadDocumentSilently (store: LiveStore, node: NamedNode): Promise<boolean> {\n try {\n await store.fetcher.load(node.doc())\n return true\n } catch (_error) {\n return false\n }\n}\n"],"mappings":";;AAIA,IAAMA,IAA+C;CAAC;CAAY;CAAU;CAAW;AAAS;AAEhG,SAAgBC,EAAe,GAAyB;CACtD,OAAOC,EACJ,YAAY,CAAC,CACb,KAAK,CAAC,CACN,MAAM,KAAK,CAAC,CACZ,OAAO,OAAO;AACnB;AAMA,SAAgBC,EAAiB,GAAkB,GAAwB;CACzE,IAAMC,IAAaH,EAAcC,CAAK;CACtC,IAAIE,EAAW,WAAW,GAAG,OAAO;CAEpC,IAAMC,IAAaC,EAAO,SAAQ,MAASL,EAAcM,CAAK,CAAC,GACzDC,IAAmBF,EAAO,KAAK,GAAG,CAAC,CAAC,YAAY;CACtD,OAAOF,EAAW,OAAM,MACtBC,EAAW,MAAK,MAAaI,EAAU,SAASC,CAAI,CAAC,KAAKF,EAAiB,SAASE,CAAI,CAC1F;AACF;AAEA,SAAgBC,EAAa,GAAqD;CAChF,OAAO,MAAM,KAAKC,CAAO,CAAC,CACvB,MAAM,GAAM,MAAUC,EAAK,MAAM,cAAcC,EAAM,OAAO,KAAA,GAAW,EAAE,aAAa,OAAO,CAAC,CAAC;AACpG;AAEA,SAAgBC,EACd,GACA,GACgB;CAChB,IAAMC,IAAMC,EAAkBC,CAAK,GAC7BC,IAAWC,EAAkB,IAAIJ,CAAG;CAC1C,IAAIG,GAAU;EACZ,IAAME,IAAYC,EAAwBH,GAAUD,CAAK,GACnDZ,IAASiB,EACbF,EAAU,OACV,CAAC,GAAIF,EAAS,oBAAoB,CAACA,EAAS,KAAK,GAAI,GAAID,EAAM,oBAAoB,CAACA,EAAM,KAAK,CAAE,CACnG,GACMM,IAAS;GACb,GAAGL;GACH,OAAOE,EAAU;GACjB,mBAAmBI,EAAsBN,EAAS,mBAAmBD,EAAM,iBAAiB;GAC5F,SAASQ,EAA6B,CAAC,GAAGP,EAAS,SAAS,GAAGD,EAAM,OAAO,CAAC;GAC7E,kBAAkBZ;EACpB;EAEA,OADAc,EAAkB,IAAIJ,GAAKQ,CAAM,GAC1BA;CACT;CAEA,IAAMG,IAAa;EACjB,GAAGT;EACH,SAASQ,EAA6BR,EAAM,OAAO;EACnD,kBAAkBA,EAAM,oBAAoB,CAACA,EAAM,KAAK;CAC1D;CAEA,OADAE,EAAkB,IAAIJ,GAAKW,CAAU,GAC9BA;AACT;AAEA,SAASL,EAAyB,GAAyB,GAA0C;CACnG,OAAOM,EAA6BC,CAAQ,IAAID,EAA6BE,CAAO,IAAID,IAAWC;AACrG;AAEA,SAASF,EAA8B,GAA+B;CACpE,IAAMG,IAAab,EAAM,QAAQ,KAAI,MAAUlB,EAA0B,QAAQgC,CAAM,CAAC;CACxF,OAAOD,EAAW,SAAS,KAAK,IAAI,GAAGA,CAAU,IAAI/B,EAA0B;AACjF;AAEA,SAAgB0B,EAA8B,GAA+C;CAC3F,OAAO1B,EAA0B,QAAO,MAAUiC,EAAQ,SAASD,CAAM,CAAC;AAC5E;AAEA,SAAST,EAA8B,GAAwB,GAA4B;CACzF,OAAOW,EAAc5B,CAAM,CAAC,CAAC,MAAM,GAAM,MACnCO,MAASsB,IAAuB,KAChCrB,MAAUqB,IAAuB,IAC9BtB,EAAK,cAAcC,GAAO,KAAA,GAAW,EAAE,aAAa,OAAO,CAAC,CACpE;AACH;AAEA,SAAgBW,EACd,GACA,GAC4B;CAI5B,OAHIK,MAAY,aAAaD,MAAa,YAAkB,YACxDC,MAAY,YAAYD,MAAa,WAAiB,WACtDC,MAAY,WAAWD,MAAa,UAAgB,UACjD;AACT;AAEA,SAAgBZ,EAAmB,GAA+B;CAChE,OAAO,GAAGC,EAAM,KAAK,GAAGA,EAAM;AAChC;AAEA,SAAgBkB,EAAkB,GAAiC;CACjE,IAAMC,oBAAO,IAAI,IAAY;CAC7B,OAAOC,EAAM,QAAO,MAClB,CAAID,EAAK,IAAIE,EAAK,KAAK,MACvBF,EAAK,IAAIE,EAAK,KAAK,GACZ,GACR;AACH;AAEA,SAAgBL,EAAiC,GAAkB;CACjE,OAAO,CAAC,GAAG,IAAI,IAAIM,CAAM,CAAC;AAC5B;AAEA,SAAgBC,EAAW,GAA2C;CACpE,OAAO,CAAC,CAACC,MAAUA,EAAM,WAAW,UAAU,KAAKA,EAAM,WAAW,SAAS;AAC/E;AAEA,SAAgBC,EAAe,GAAqB;CAClD,IAAMC,IAAkBC,EAAI,MAAM,GAAG,CAAC,CAAC,IACjCC,IAAWD,EAAI,SAAS,GAAG,IAAIA,EAAI,MAAMA,EAAI,QAAQ,GAAG,IAAI,CAAC,IAAI,IACjEE,IAAOD,KAAYA,MAAa,UAAUA,MAAa,OACzDA,IACAF,EAAgB,MAAMA,EAAgB,YAAY,GAAG,IAAI,CAAC;CAC9D,OAAO,mBAAmBG,KAAQF,CAAG,CAAC,CAAC,QAAQ,UAAU,GAAG;AAC9D;AAEA,SAAgBG,EAAoB,GAAkB,GAAgC;CACpF,OAAOC,EAAM,SAASV,GAAMW,EAAG,MAAM,IAAI,CAAC,KACxCD,EAAM,SAASV,GAAMW,EAAG,KAAK,MAAM,CAAC,KACpCD,EAAM,SAASV,GAAMW,EAAG,OAAO,MAAM,CAAC,KACtCD,EAAM,SAASV,GAAMW,EAAG,KAAK,OAAO,CAAC,KACrC;AACJ;AAEA,SAAgBC,EAAc,GAAkB,GAAyB;CACvE,OAAOH,EAAmBC,GAAOV,CAAI,KAAKI,EAAcJ,EAAK,KAAK;AACpE;AAEA,eAAsBa,EAAsB,GAAkB,GAAmC;CAC/F,IAAI;EAEF,OADA,MAAMH,EAAM,QAAQ,KAAKV,EAAK,IAAI,CAAC,GAC5B;CACT,QAAiB;EACf,OAAO;CACT;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"directoryLogic.cjs.js","names":[],"sources":["../../src/directory/directoryLogic.ts"],"sourcesContent":["import { type AuthnLogic, type DirectoryEntry, type DirectoryLogic, type DirectorySearchOptions, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore } from 'rdflib'\nimport { createContactsDirectoryDiscovery } from './contactsDirectory'\nimport { createFriendsDirectoryDiscovery } from './friendsDirectory'\nimport { createCatalogDirectoryDiscovery } from './catalogDirectory'\nimport { matchesAnyLabel, mergeDirectoryEntry, sortEntries } from './directoryHelpers'\n\nconst DEFAULT_FOAF_DISTANCE = 3\n\nexport const DEFAULT_DIRECTORY_CATALOG_URL = 'https://raw.githubusercontent.com/solid/catalog/refs/heads/main/catalog-data.ttl'\nexport const DEFAULT_DIRECTORY_SOURCES: DirectorySource[] = ['contacts', 'friends', 'catalog', 'groups']\n\nexport function createDirectoryLogic (\n store: LiveStore,\n authn: AuthnLogic,\n typeIndexLogic: TypeIndexLogic\n): DirectoryLogic {\n const contactsDiscovery = createContactsDirectoryDiscovery(store, typeIndexLogic)\n const friendsDiscovery = createFriendsDirectoryDiscovery(store)\n const catalogDiscovery = createCatalogDirectoryDiscovery()\n\n async function discoverWithNormalizedOptions (\n normalized: ReturnType<typeof normalizeOptions>\n ): Promise<DirectoryEntry[]> {\n const discoveredEntries = new Map<string, DirectoryEntry>()\n const discoveryTasks: Promise<void>[] = []\n\n const mergeEntry = (entry: DirectoryEntry): void => {\n mergeDirectoryEntry(discoveredEntries, entry)\n }\n\n if (normalized.sources.includes('catalog')) {\n discoveryTasks.push(catalogDiscovery.discoverCatalogEntries(normalized.catalogUrl, mergeEntry))\n }\n\n if (normalized.user) {\n if (normalized.sources.includes('contacts')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookContacts(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('groups')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookGroups(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('friends')) {\n discoveryTasks.push(friendsDiscovery.discoverFoafPeople(normalized.user, normalized.maxFoafDistance, mergeEntry))\n }\n }\n\n if (!discoveryTasks.length) {\n return []\n }\n\n const results = await Promise.allSettled(discoveryTasks)\n if (results.every(result => result.status === 'rejected')) {\n throw new Error('Unable to load directory entries.')\n }\n\n return sortEntries(discoveredEntries.values())\n }\n\n async function search (options: DirectorySearchOptions = {}): Promise<DirectoryEntry[]> {\n const normalized = normalizeOptions(options)\n const entries = await discoverWithNormalizedOptions(normalized)\n return entries.filter(entry => matchesAnyLabel([entry.label, ...(entry.searchableLabels ?? [])], normalized.query))\n }\n\n return {\n search\n }\n\n function normalizeOptions (options: DirectorySearchOptions = {}) {\n const sources = options.sources === undefined ? [...DEFAULT_DIRECTORY_SOURCES] : [...options.sources]\n return {\n query: options.query ?? '',\n sources,\n catalogUrl: options.catalogUrl ?? DEFAULT_DIRECTORY_CATALOG_URL,\n user: options.user ?? authn.currentUser(),\n maxFoafDistance: options.maxFoafDistance ?? DEFAULT_FOAF_DISTANCE\n }\n }\n}\n"],"mappings":"mKAOA,IAAM,EAAwB,EAEjB,EAAgC,mFAChC,EAA+C,CAAC,WAAY,UAAW,UAAW,QAAQ,EAEvG,SAAgB,EACd,EACA,EACA,EACgB,CAChB,IAAM,EAAoB,EAAA,iCAAiC,EAAO,CAAc,EAC1E,EAAmB,EAAA,gCAAgC,CAAK,EACxD,EAAmB,EAAA,gCAAgC,EAEzD,eAAe,EACb,EAC2B,CAC3B,IAAM,EAAoB,IAAI,IACxB,EAAkC,CAAC,EAEnC,EAAc,GAAgC,CAClD,EAAA,oBAAoB,EAAmB,CAAK,CAC9C,EAoBA,GAlBI,EAAW,QAAQ,SAAS,SAAS,GACvC,EAAe,KAAK,EAAiB,uBAAuB,EAAW,WAAY,CAAU,CAAC,EAG5F,EAAW,OACT,EAAW,QAAQ,SAAS,UAAU,GACxC,EAAe,KAAK,EAAkB,4BAA4B,EAAW,KAAM,CAAU,CAAC,EAG5F,EAAW,QAAQ,SAAS,QAAQ,GACtC,EAAe,KAAK,EAAkB,0BAA0B,EAAW,KAAM,CAAU,CAAC,EAG1F,EAAW,QAAQ,SAAS,SAAS,GACvC,EAAe,KAAK,EAAiB,mBAAmB,EAAW,KAAM,EAAW,gBAAiB,CAAU,CAAC,GAIhH,CAAC,EAAe,OAClB,MAAO,CAAC,EAIV,IAAI,MADkB,QAAQ,WAAW,CAAc,EAAA,CAC3C,MAAM,GAAU,EAAO,SAAW,UAAU,EACtD,MAAU,MAAM,mCAAmC,EAGrD,OAAO,EAAA,YAAY,EAAkB,OAAO,CAAC,CAC/C,CAEA,eAAe,EAAQ,EAAkC,CAAC,EAA8B,CACtF,IAAM,EAAa,EAAiB,CAAO,EAE3C,OAAO,MADe,EAA8B,CAAU,EAAA,CAC/C,OAAO,GAAS,EAAA,gBAAgB,CAAC,EAAM,MAAO,GAAI,EAAM,kBAAoB,CAAC,CAAE,EAAG,EAAW,KAAK,CAAC,CACpH,CAEA,MAAO,CACL,QACF,EAEA,SAAS,EAAkB,EAAkC,CAAC,EAAG,CAC/D,IAAM,EAAU,EAAQ,UAAY,IAAA,GAAY,CAAC,GAAG,CAAyB,EAAI,CAAC,GAAG,EAAQ,OAAO,EACpG,MAAO,CACL,MAAO,EAAQ,OAAS,GACxB,UACA,WAAY,EAAQ,YAAA,mFACpB,KAAM,EAAQ,MAAQ,EAAM,YAAY,EACxC,gBAAiB,EAAQ,iBAAmB,CAC9C,CACF,CACF"}
1
+ {"version":3,"file":"directoryLogic.cjs.js","names":["createContactsDirectoryDiscovery","createFriendsDirectoryDiscovery","createCatalogDirectoryDiscovery","sortEntries","matchesAnyLabel","require_directoryHelpers","require_contactsDirectory","require_friendsDirectory","require_catalogDirectory","DEFAULT_FOAF_DISTANCE","DEFAULT_DIRECTORY_CATALOG_URL","DEFAULT_DIRECTORY_SOURCES","createDirectoryLogic","contactsDiscovery","store","typeIndexLogic","friendsDiscovery","catalogDiscovery","discoverWithNormalizedOptions","discoveredEntries","discoveryTasks","mergeEntry","entry","normalized","result","search","normalizeOptions","options","sources","authn"],"sources":["../../src/directory/directoryLogic.ts"],"sourcesContent":["import { type AuthnLogic, type DirectoryEntry, type DirectoryLogic, type DirectorySearchOptions, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore } from 'rdflib'\nimport { createContactsDirectoryDiscovery } from './contactsDirectory'\nimport { createFriendsDirectoryDiscovery } from './friendsDirectory'\nimport { createCatalogDirectoryDiscovery } from './catalogDirectory'\nimport { matchesAnyLabel, mergeDirectoryEntry, sortEntries } from './directoryHelpers'\n\nconst DEFAULT_FOAF_DISTANCE = 3\n\nexport const DEFAULT_DIRECTORY_CATALOG_URL = 'https://raw.githubusercontent.com/solid/catalog/refs/heads/main/catalog-data.ttl'\nexport const DEFAULT_DIRECTORY_SOURCES: DirectorySource[] = ['contacts', 'friends', 'catalog', 'groups']\n\nexport function createDirectoryLogic (\n store: LiveStore,\n authn: AuthnLogic,\n typeIndexLogic: TypeIndexLogic\n): DirectoryLogic {\n const contactsDiscovery = createContactsDirectoryDiscovery(store, typeIndexLogic)\n const friendsDiscovery = createFriendsDirectoryDiscovery(store)\n const catalogDiscovery = createCatalogDirectoryDiscovery()\n\n async function discoverWithNormalizedOptions (\n normalized: ReturnType<typeof normalizeOptions>\n ): Promise<DirectoryEntry[]> {\n const discoveredEntries = new Map<string, DirectoryEntry>()\n const discoveryTasks: Promise<void>[] = []\n\n const mergeEntry = (entry: DirectoryEntry): void => {\n mergeDirectoryEntry(discoveredEntries, entry)\n }\n\n if (normalized.sources.includes('catalog')) {\n discoveryTasks.push(catalogDiscovery.discoverCatalogEntries(normalized.catalogUrl, mergeEntry))\n }\n\n if (normalized.user) {\n if (normalized.sources.includes('contacts')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookContacts(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('groups')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookGroups(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('friends')) {\n discoveryTasks.push(friendsDiscovery.discoverFoafPeople(normalized.user, normalized.maxFoafDistance, mergeEntry))\n }\n }\n\n if (!discoveryTasks.length) {\n return []\n }\n\n const results = await Promise.allSettled(discoveryTasks)\n if (results.every(result => result.status === 'rejected')) {\n throw new Error('Unable to load directory entries.')\n }\n\n return sortEntries(discoveredEntries.values())\n }\n\n async function search (options: DirectorySearchOptions = {}): Promise<DirectoryEntry[]> {\n const normalized = normalizeOptions(options)\n const entries = await discoverWithNormalizedOptions(normalized)\n return entries.filter(entry => matchesAnyLabel([entry.label, ...(entry.searchableLabels ?? [])], normalized.query))\n }\n\n return {\n search\n }\n\n function normalizeOptions (options: DirectorySearchOptions = {}) {\n const sources = options.sources === undefined ? [...DEFAULT_DIRECTORY_SOURCES] : [...options.sources]\n return {\n query: options.query ?? '',\n sources,\n catalogUrl: options.catalogUrl ?? DEFAULT_DIRECTORY_CATALOG_URL,\n user: options.user ?? authn.currentUser(),\n maxFoafDistance: options.maxFoafDistance ?? DEFAULT_FOAF_DISTANCE\n }\n }\n}\n"],"mappings":"mKAOA,IAAMS,EAAwB,EAEjBC,EAAgC,mFAChCC,EAA+C,CAAC,WAAY,UAAW,UAAW,QAAQ,EAEvG,SAAgBC,EACd,EACA,EACA,EACgB,CAChB,IAAMC,EAAoBb,EAAAA,iCAAiCc,EAAOC,CAAc,EAC1EC,EAAmBf,EAAAA,gCAAgCa,CAAK,EACxDG,EAAmBf,EAAAA,gCAAgC,EAEzD,eAAegB,EACb,EAC2B,CAC3B,IAAMC,EAAoB,IAAI,IACxBC,EAAkC,CAAC,EAEnCC,EAAc,GAAgC,CAClDhB,EAAA,oBAAoBc,EAAmBG,CAAK,CAC9C,EAoBA,GAlBIC,EAAW,QAAQ,SAAS,SAAS,GACvCH,EAAe,KAAKH,EAAiB,uBAAuBM,EAAW,WAAYF,CAAU,CAAC,EAG5FE,EAAW,OACTA,EAAW,QAAQ,SAAS,UAAU,GACxCH,EAAe,KAAKP,EAAkB,4BAA4BU,EAAW,KAAMF,CAAU,CAAC,EAG5FE,EAAW,QAAQ,SAAS,QAAQ,GACtCH,EAAe,KAAKP,EAAkB,0BAA0BU,EAAW,KAAMF,CAAU,CAAC,EAG1FE,EAAW,QAAQ,SAAS,SAAS,GACvCH,EAAe,KAAKJ,EAAiB,mBAAmBO,EAAW,KAAMA,EAAW,gBAAiBF,CAAU,CAAC,GAIhH,CAACD,EAAe,OAClB,MAAO,CAAC,EAIV,IAAI,MADkB,QAAQ,WAAWA,CAAc,EAAA,CAC3C,MAAM,GAAUI,EAAO,SAAW,UAAU,EACtD,MAAU,MAAM,mCAAmC,EAGrD,OAAOrB,EAAAA,YAAYgB,EAAkB,OAAO,CAAC,CAC/C,CAEA,eAAeM,EAAQ,EAAkC,CAAC,EAA8B,CACtF,IAAMF,EAAaG,EAAiBC,CAAO,EAE3C,OAAO,MADeT,EAA8BK,CAAU,EAAA,CAC/C,OAAO,GAASnB,EAAAA,gBAAgB,CAACkB,EAAM,MAAO,GAAIA,EAAM,kBAAoB,CAAC,CAAE,EAAGC,EAAW,KAAK,CAAC,CACpH,CAEA,MAAO,CACL,QACF,EAEA,SAASG,EAAkB,EAAkC,CAAC,EAAG,CAC/D,IAAME,EAAUD,EAAQ,UAAY,IAAA,GAAY,CAAC,GAAGhB,CAAyB,EAAI,CAAC,GAAGgB,EAAQ,OAAO,EACpG,MAAO,CACL,MAAOA,EAAQ,OAAS,GACxB,UACA,WAAYA,EAAQ,YAAA,mFACpB,KAAMA,EAAQ,MAAQE,EAAM,YAAY,EACxC,gBAAiBF,EAAQ,iBAAmBlB,CAC9C,CACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"directoryLogic.esm.js","names":[],"sources":["../../src/directory/directoryLogic.ts"],"sourcesContent":["import { type AuthnLogic, type DirectoryEntry, type DirectoryLogic, type DirectorySearchOptions, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore } from 'rdflib'\nimport { createContactsDirectoryDiscovery } from './contactsDirectory'\nimport { createFriendsDirectoryDiscovery } from './friendsDirectory'\nimport { createCatalogDirectoryDiscovery } from './catalogDirectory'\nimport { matchesAnyLabel, mergeDirectoryEntry, sortEntries } from './directoryHelpers'\n\nconst DEFAULT_FOAF_DISTANCE = 3\n\nexport const DEFAULT_DIRECTORY_CATALOG_URL = 'https://raw.githubusercontent.com/solid/catalog/refs/heads/main/catalog-data.ttl'\nexport const DEFAULT_DIRECTORY_SOURCES: DirectorySource[] = ['contacts', 'friends', 'catalog', 'groups']\n\nexport function createDirectoryLogic (\n store: LiveStore,\n authn: AuthnLogic,\n typeIndexLogic: TypeIndexLogic\n): DirectoryLogic {\n const contactsDiscovery = createContactsDirectoryDiscovery(store, typeIndexLogic)\n const friendsDiscovery = createFriendsDirectoryDiscovery(store)\n const catalogDiscovery = createCatalogDirectoryDiscovery()\n\n async function discoverWithNormalizedOptions (\n normalized: ReturnType<typeof normalizeOptions>\n ): Promise<DirectoryEntry[]> {\n const discoveredEntries = new Map<string, DirectoryEntry>()\n const discoveryTasks: Promise<void>[] = []\n\n const mergeEntry = (entry: DirectoryEntry): void => {\n mergeDirectoryEntry(discoveredEntries, entry)\n }\n\n if (normalized.sources.includes('catalog')) {\n discoveryTasks.push(catalogDiscovery.discoverCatalogEntries(normalized.catalogUrl, mergeEntry))\n }\n\n if (normalized.user) {\n if (normalized.sources.includes('contacts')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookContacts(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('groups')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookGroups(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('friends')) {\n discoveryTasks.push(friendsDiscovery.discoverFoafPeople(normalized.user, normalized.maxFoafDistance, mergeEntry))\n }\n }\n\n if (!discoveryTasks.length) {\n return []\n }\n\n const results = await Promise.allSettled(discoveryTasks)\n if (results.every(result => result.status === 'rejected')) {\n throw new Error('Unable to load directory entries.')\n }\n\n return sortEntries(discoveredEntries.values())\n }\n\n async function search (options: DirectorySearchOptions = {}): Promise<DirectoryEntry[]> {\n const normalized = normalizeOptions(options)\n const entries = await discoverWithNormalizedOptions(normalized)\n return entries.filter(entry => matchesAnyLabel([entry.label, ...(entry.searchableLabels ?? [])], normalized.query))\n }\n\n return {\n search\n }\n\n function normalizeOptions (options: DirectorySearchOptions = {}) {\n const sources = options.sources === undefined ? [...DEFAULT_DIRECTORY_SOURCES] : [...options.sources]\n return {\n query: options.query ?? '',\n sources,\n catalogUrl: options.catalogUrl ?? DEFAULT_DIRECTORY_CATALOG_URL,\n user: options.user ?? authn.currentUser(),\n maxFoafDistance: options.maxFoafDistance ?? DEFAULT_FOAF_DISTANCE\n }\n }\n}\n"],"mappings":";;;;;AAOA,IAAM,IAAwB,GAEjB,IAAgC,oFAChC,IAA+C;CAAC;CAAY;CAAW;CAAW;AAAQ;AAEvG,SAAgB,EACd,GACA,GACA,GACgB;CAChB,IAAM,IAAoB,EAAiC,GAAO,CAAc,GAC1E,IAAmB,EAAgC,CAAK,GACxD,IAAmB,EAAgC;CAEzD,eAAe,EACb,GAC2B;EAC3B,IAAM,oBAAoB,IAAI,IAA4B,GACpD,IAAkC,CAAC,GAEnC,KAAc,MAAgC;GAClD,EAAoB,GAAmB,CAAK;EAC9C;EAoBA,IAlBI,EAAW,QAAQ,SAAS,SAAS,KACvC,EAAe,KAAK,EAAiB,uBAAuB,EAAW,YAAY,CAAU,CAAC,GAG5F,EAAW,SACT,EAAW,QAAQ,SAAS,UAAU,KACxC,EAAe,KAAK,EAAkB,4BAA4B,EAAW,MAAM,CAAU,CAAC,GAG5F,EAAW,QAAQ,SAAS,QAAQ,KACtC,EAAe,KAAK,EAAkB,0BAA0B,EAAW,MAAM,CAAU,CAAC,GAG1F,EAAW,QAAQ,SAAS,SAAS,KACvC,EAAe,KAAK,EAAiB,mBAAmB,EAAW,MAAM,EAAW,iBAAiB,CAAU,CAAC,IAIhH,CAAC,EAAe,QAClB,OAAO,CAAC;EAIV,KAAI,MADkB,QAAQ,WAAW,CAAc,EAAA,CAC3C,OAAM,MAAU,EAAO,WAAW,UAAU,GACtD,MAAU,MAAM,mCAAmC;EAGrD,OAAO,EAAY,EAAkB,OAAO,CAAC;CAC/C;CAEA,eAAe,EAAQ,IAAkC,CAAC,GAA8B;EACtF,IAAM,IAAa,EAAiB,CAAO;EAE3C,QAAO,MADe,EAA8B,CAAU,EAAA,CAC/C,QAAO,MAAS,EAAgB,CAAC,EAAM,OAAO,GAAI,EAAM,oBAAoB,CAAC,CAAE,GAAG,EAAW,KAAK,CAAC;CACpH;CAEA,OAAO,EACL,UACF;CAEA,SAAS,EAAkB,IAAkC,CAAC,GAAG;EAC/D,IAAM,IAAU,EAAQ,YAAY,KAAA,IAAY,CAAC,GAAG,CAAyB,IAAI,CAAC,GAAG,EAAQ,OAAO;EACpG,OAAO;GACL,OAAO,EAAQ,SAAS;GACxB;GACA,YAAY,EAAQ,cAAA;GACpB,MAAM,EAAQ,QAAQ,EAAM,YAAY;GACxC,iBAAiB,EAAQ,mBAAmB;EAC9C;CACF;AACF"}
1
+ {"version":3,"file":"directoryLogic.esm.js","names":["DEFAULT_FOAF_DISTANCE","DEFAULT_DIRECTORY_CATALOG_URL","DEFAULT_DIRECTORY_SOURCES","createDirectoryLogic","contactsDiscovery","createContactsDirectoryDiscovery","store","typeIndexLogic","friendsDiscovery","createFriendsDirectoryDiscovery","catalogDiscovery","createCatalogDirectoryDiscovery","discoverWithNormalizedOptions","discoveredEntries","discoveryTasks","mergeEntry","entry","normalized","result","sortEntries","search","normalizeOptions","options","matchesAnyLabel","sources","authn"],"sources":["../../src/directory/directoryLogic.ts"],"sourcesContent":["import { type AuthnLogic, type DirectoryEntry, type DirectoryLogic, type DirectorySearchOptions, type DirectorySource, type TypeIndexLogic } from '../types'\nimport { type LiveStore } from 'rdflib'\nimport { createContactsDirectoryDiscovery } from './contactsDirectory'\nimport { createFriendsDirectoryDiscovery } from './friendsDirectory'\nimport { createCatalogDirectoryDiscovery } from './catalogDirectory'\nimport { matchesAnyLabel, mergeDirectoryEntry, sortEntries } from './directoryHelpers'\n\nconst DEFAULT_FOAF_DISTANCE = 3\n\nexport const DEFAULT_DIRECTORY_CATALOG_URL = 'https://raw.githubusercontent.com/solid/catalog/refs/heads/main/catalog-data.ttl'\nexport const DEFAULT_DIRECTORY_SOURCES: DirectorySource[] = ['contacts', 'friends', 'catalog', 'groups']\n\nexport function createDirectoryLogic (\n store: LiveStore,\n authn: AuthnLogic,\n typeIndexLogic: TypeIndexLogic\n): DirectoryLogic {\n const contactsDiscovery = createContactsDirectoryDiscovery(store, typeIndexLogic)\n const friendsDiscovery = createFriendsDirectoryDiscovery(store)\n const catalogDiscovery = createCatalogDirectoryDiscovery()\n\n async function discoverWithNormalizedOptions (\n normalized: ReturnType<typeof normalizeOptions>\n ): Promise<DirectoryEntry[]> {\n const discoveredEntries = new Map<string, DirectoryEntry>()\n const discoveryTasks: Promise<void>[] = []\n\n const mergeEntry = (entry: DirectoryEntry): void => {\n mergeDirectoryEntry(discoveredEntries, entry)\n }\n\n if (normalized.sources.includes('catalog')) {\n discoveryTasks.push(catalogDiscovery.discoverCatalogEntries(normalized.catalogUrl, mergeEntry))\n }\n\n if (normalized.user) {\n if (normalized.sources.includes('contacts')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookContacts(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('groups')) {\n discoveryTasks.push(contactsDiscovery.discoverAddressBookGroups(normalized.user, mergeEntry))\n }\n\n if (normalized.sources.includes('friends')) {\n discoveryTasks.push(friendsDiscovery.discoverFoafPeople(normalized.user, normalized.maxFoafDistance, mergeEntry))\n }\n }\n\n if (!discoveryTasks.length) {\n return []\n }\n\n const results = await Promise.allSettled(discoveryTasks)\n if (results.every(result => result.status === 'rejected')) {\n throw new Error('Unable to load directory entries.')\n }\n\n return sortEntries(discoveredEntries.values())\n }\n\n async function search (options: DirectorySearchOptions = {}): Promise<DirectoryEntry[]> {\n const normalized = normalizeOptions(options)\n const entries = await discoverWithNormalizedOptions(normalized)\n return entries.filter(entry => matchesAnyLabel([entry.label, ...(entry.searchableLabels ?? [])], normalized.query))\n }\n\n return {\n search\n }\n\n function normalizeOptions (options: DirectorySearchOptions = {}) {\n const sources = options.sources === undefined ? [...DEFAULT_DIRECTORY_SOURCES] : [...options.sources]\n return {\n query: options.query ?? '',\n sources,\n catalogUrl: options.catalogUrl ?? DEFAULT_DIRECTORY_CATALOG_URL,\n user: options.user ?? authn.currentUser(),\n maxFoafDistance: options.maxFoafDistance ?? DEFAULT_FOAF_DISTANCE\n }\n }\n}\n"],"mappings":";;;;;AAOA,IAAMA,IAAwB,GAEjBC,IAAgC,oFAChCC,IAA+C;CAAC;CAAY;CAAW;CAAW;AAAQ;AAEvG,SAAgBC,EACd,GACA,GACA,GACgB;CAChB,IAAMC,IAAoBC,EAAiCC,GAAOC,CAAc,GAC1EC,IAAmBC,EAAgCH,CAAK,GACxDI,IAAmBC,EAAgC;CAEzD,eAAeC,EACb,GAC2B;EAC3B,IAAMC,oBAAoB,IAAI,IAA4B,GACpDC,IAAkC,CAAC,GAEnCC,KAAc,MAAgC;GAClD,EAAoBF,GAAmBG,CAAK;EAC9C;EAoBA,IAlBIC,EAAW,QAAQ,SAAS,SAAS,KACvCH,EAAe,KAAKJ,EAAiB,uBAAuBO,EAAW,YAAYF,CAAU,CAAC,GAG5FE,EAAW,SACTA,EAAW,QAAQ,SAAS,UAAU,KACxCH,EAAe,KAAKV,EAAkB,4BAA4Ba,EAAW,MAAMF,CAAU,CAAC,GAG5FE,EAAW,QAAQ,SAAS,QAAQ,KACtCH,EAAe,KAAKV,EAAkB,0BAA0Ba,EAAW,MAAMF,CAAU,CAAC,GAG1FE,EAAW,QAAQ,SAAS,SAAS,KACvCH,EAAe,KAAKN,EAAiB,mBAAmBS,EAAW,MAAMA,EAAW,iBAAiBF,CAAU,CAAC,IAIhH,CAACD,EAAe,QAClB,OAAO,CAAC;EAIV,KAAI,MADkB,QAAQ,WAAWA,CAAc,EAAA,CAC3C,OAAM,MAAUI,EAAO,WAAW,UAAU,GACtD,MAAU,MAAM,mCAAmC;EAGrD,OAAOC,EAAYN,EAAkB,OAAO,CAAC;CAC/C;CAEA,eAAeO,EAAQ,IAAkC,CAAC,GAA8B;EACtF,IAAMH,IAAaI,EAAiBC,CAAO;EAE3C,QAAO,MADeV,EAA8BK,CAAU,EAAA,CAC/C,QAAO,MAASM,EAAgB,CAACP,EAAM,OAAO,GAAIA,EAAM,oBAAoB,CAAC,CAAE,GAAGC,EAAW,KAAK,CAAC;CACpH;CAEA,OAAO,EACL,UACF;CAEA,SAASI,EAAkB,IAAkC,CAAC,GAAG;EAC/D,IAAMG,IAAUF,EAAQ,YAAY,KAAA,IAAY,CAAC,GAAGpB,CAAyB,IAAI,CAAC,GAAGoB,EAAQ,OAAO;EACpG,OAAO;GACL,OAAOA,EAAQ,SAAS;GACxB;GACA,YAAYA,EAAQ,cAAA;GACpB,MAAMA,EAAQ,QAAQG,EAAM,YAAY;GACxC,iBAAiBH,EAAQ,mBAAmBtB;EAC9C;CACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"friendsDirectory.cjs.js","names":[],"sources":["../../src/directory/friendsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { loadDocumentSilently, storedLabelForNode } from './directoryHelpers'\n\nconst PEOPLE_SEARCH_CONCURRENCY = 6\n\nexport function createFriendsDirectoryDiscovery (store: LiveStore) {\n function relationshipLabelForDepth (depth: number) {\n return depth === 1 ? 'Friend' : 'People'\n }\n\n async function emitPersonEntry (\n person: NamedNode,\n depth: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const personName = storedLabelForNode(store, person)\n if (!personName) return\n\n await onEntry({\n kind: 'person',\n uri: person.value,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: relationshipLabelForDepth(depth),\n sources: ['friends']\n })\n }\n\n async function discoverFoafPeople (\n user: NamedNode,\n maxFoafDistance: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const visited = new Set<string>([user.value])\n const emitted = new Set<string>()\n const loadedDocs = new Set<string>()\n let queue: Array<{ person: NamedNode, depth: number }> = [{ person: user, depth: 0 }]\n\n const processPerson = async (currentEntry: { person: NamedNode, depth: number }) => {\n const { person: current, depth } = currentEntry\n const currentDoc = current.doc().value\n if (!loadedDocs.has(currentDoc)) {\n loadedDocs.add(currentDoc)\n await loadDocumentSilently(store, current)\n }\n\n if (current.value !== user.value) {\n if (!emitted.has(current.value)) {\n emitted.add(current.value)\n await emitPersonEntry(current, depth, onEntry)\n }\n }\n\n if (depth >= maxFoafDistance) {\n return [] as Array<{ person: NamedNode, depth: number }>\n }\n\n const nextPeople: Array<{ person: NamedNode, depth: number }> = []\n const contacts = store.each(current, ns.foaf('knows')) as NamedNode[]\n for (const contact of contacts) {\n if (contact.termType === 'NamedNode') {\n const contactName = storedLabelForNode(store, contact)\n if (contact.value !== user.value && contactName && !emitted.has(contact.value)) {\n emitted.add(contact.value)\n await onEntry({\n kind: 'person',\n uri: contact.value,\n label: contactName,\n subjectType: 'agent',\n relationshipLabel: depth === 0 ? 'Friend' : 'People',\n sources: ['friends']\n })\n }\n\n if (!visited.has(contact.value)) {\n visited.add(contact.value)\n nextPeople.push({ person: contact, depth: depth + 1 })\n }\n }\n }\n\n return nextPeople\n }\n\n while (queue.length > 0) {\n const nextQueue: Array<{ person: NamedNode, depth: number }> = []\n\n for (let index = 0; index < queue.length; index += PEOPLE_SEARCH_CONCURRENCY) {\n const batch = queue.slice(index, index + PEOPLE_SEARCH_CONCURRENCY)\n const nested = await Promise.all(batch.map(processPerson))\n nested.forEach(entries => nextQueue.push(...entries))\n }\n\n queue = nextQueue\n }\n }\n\n return {\n discoverFoafPeople\n }\n}\n"],"mappings":"4EAKA,IAAM,EAA4B,EAElC,SAAgB,EAAiC,EAAkB,CACjE,SAAS,EAA2B,EAAe,CACjD,OAAO,IAAU,EAAI,SAAW,QAClC,CAEA,eAAe,EACb,EACA,EACA,EACe,CACf,IAAM,EAAa,EAAA,mBAAmB,EAAO,CAAM,EAC9C,GAEL,MAAM,EAAQ,CACZ,KAAM,SACN,IAAK,EAAO,MACZ,MAAO,EACP,YAAa,QACb,kBAAmB,EAA0B,CAAK,EAClD,QAAS,CAAC,SAAS,CACrB,CAAC,CACH,CAEA,eAAe,EACb,EACA,EACA,EACe,CACf,IAAM,EAAU,IAAI,IAAY,CAAC,EAAK,KAAK,CAAC,EACtC,EAAU,IAAI,IACd,EAAa,IAAI,IACnB,EAAqD,CAAC,CAAE,OAAQ,EAAM,MAAO,CAAE,CAAC,EAE9E,EAAgB,KAAO,IAAuD,CAClF,GAAM,CAAE,OAAQ,EAAS,SAAU,EAC7B,EAAa,EAAQ,IAAI,CAAC,CAAC,MAajC,GAZK,EAAW,IAAI,CAAU,IAC5B,EAAW,IAAI,CAAU,EACzB,MAAM,EAAA,qBAAqB,EAAO,CAAO,GAGvC,EAAQ,QAAU,EAAK,QACpB,EAAQ,IAAI,EAAQ,KAAK,IAC5B,EAAQ,IAAI,EAAQ,KAAK,EACzB,MAAM,EAAgB,EAAS,EAAO,CAAO,IAI7C,GAAS,EACX,MAAO,CAAC,EAGV,IAAM,EAA0D,CAAC,EAC3D,EAAW,EAAM,KAAK,EAAS,EAAA,GAAG,KAAK,OAAO,CAAC,EACrD,IAAK,IAAM,KAAW,EACpB,GAAI,EAAQ,WAAa,YAAa,CACpC,IAAM,EAAc,EAAA,mBAAmB,EAAO,CAAO,EACjD,EAAQ,QAAU,EAAK,OAAS,GAAe,CAAC,EAAQ,IAAI,EAAQ,KAAK,IAC3E,EAAQ,IAAI,EAAQ,KAAK,EACzB,MAAM,EAAQ,CACZ,KAAM,SACN,IAAK,EAAQ,MACb,MAAO,EACP,YAAa,QACb,kBAAmB,IAAU,EAAI,SAAW,SAC5C,QAAS,CAAC,SAAS,CACrB,CAAC,GAGE,EAAQ,IAAI,EAAQ,KAAK,IAC5B,EAAQ,IAAI,EAAQ,KAAK,EACzB,EAAW,KAAK,CAAE,OAAQ,EAAS,MAAO,EAAQ,CAAE,CAAC,EAEzD,CAGF,OAAO,CACT,EAEA,KAAO,EAAM,OAAS,GAAG,CACvB,IAAM,EAAyD,CAAC,EAEhE,IAAK,IAAI,EAAQ,EAAG,EAAQ,EAAM,OAAQ,GAAS,EAA2B,CAC5E,IAAM,EAAQ,EAAM,MAAM,EAAO,EAAQ,CAAyB,GAElE,MADqB,QAAQ,IAAI,EAAM,IAAI,CAAa,CAAC,EAAA,CAClD,QAAQ,GAAW,EAAU,KAAK,GAAG,CAAO,CAAC,CACtD,CAEA,EAAQ,CACV,CACF,CAEA,MAAO,CACL,oBACF,CACF"}
1
+ {"version":3,"file":"friendsDirectory.cjs.js","names":["storedLabelForNode","loadDocumentSilently","ns","require_ns","require_directoryHelpers","PEOPLE_SEARCH_CONCURRENCY","createFriendsDirectoryDiscovery","relationshipLabelForDepth","depth","emitPersonEntry","personName","store","person","onEntry","discoverFoafPeople","visited","user","emitted","loadedDocs","queue","processPerson","current","currentEntry","currentDoc","maxFoafDistance","nextPeople","contacts","contact","contactName","nextQueue","index","batch","entries"],"sources":["../../src/directory/friendsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { loadDocumentSilently, storedLabelForNode } from './directoryHelpers'\n\nconst PEOPLE_SEARCH_CONCURRENCY = 6\n\nexport function createFriendsDirectoryDiscovery (store: LiveStore) {\n function relationshipLabelForDepth (depth: number) {\n return depth === 1 ? 'Friend' : 'People'\n }\n\n async function emitPersonEntry (\n person: NamedNode,\n depth: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const personName = storedLabelForNode(store, person)\n if (!personName) return\n\n await onEntry({\n kind: 'person',\n uri: person.value,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: relationshipLabelForDepth(depth),\n sources: ['friends']\n })\n }\n\n async function discoverFoafPeople (\n user: NamedNode,\n maxFoafDistance: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const visited = new Set<string>([user.value])\n const emitted = new Set<string>()\n const loadedDocs = new Set<string>()\n let queue: Array<{ person: NamedNode, depth: number }> = [{ person: user, depth: 0 }]\n\n const processPerson = async (currentEntry: { person: NamedNode, depth: number }) => {\n const { person: current, depth } = currentEntry\n const currentDoc = current.doc().value\n if (!loadedDocs.has(currentDoc)) {\n loadedDocs.add(currentDoc)\n await loadDocumentSilently(store, current)\n }\n\n if (current.value !== user.value) {\n if (!emitted.has(current.value)) {\n emitted.add(current.value)\n await emitPersonEntry(current, depth, onEntry)\n }\n }\n\n if (depth >= maxFoafDistance) {\n return [] as Array<{ person: NamedNode, depth: number }>\n }\n\n const nextPeople: Array<{ person: NamedNode, depth: number }> = []\n const contacts = store.each(current, ns.foaf('knows')) as NamedNode[]\n for (const contact of contacts) {\n if (contact.termType === 'NamedNode') {\n const contactName = storedLabelForNode(store, contact)\n if (contact.value !== user.value && contactName && !emitted.has(contact.value)) {\n emitted.add(contact.value)\n await onEntry({\n kind: 'person',\n uri: contact.value,\n label: contactName,\n subjectType: 'agent',\n relationshipLabel: depth === 0 ? 'Friend' : 'People',\n sources: ['friends']\n })\n }\n\n if (!visited.has(contact.value)) {\n visited.add(contact.value)\n nextPeople.push({ person: contact, depth: depth + 1 })\n }\n }\n }\n\n return nextPeople\n }\n\n while (queue.length > 0) {\n const nextQueue: Array<{ person: NamedNode, depth: number }> = []\n\n for (let index = 0; index < queue.length; index += PEOPLE_SEARCH_CONCURRENCY) {\n const batch = queue.slice(index, index + PEOPLE_SEARCH_CONCURRENCY)\n const nested = await Promise.all(batch.map(processPerson))\n nested.forEach(entries => nextQueue.push(...entries))\n }\n\n queue = nextQueue\n }\n }\n\n return {\n discoverFoafPeople\n }\n}\n"],"mappings":"4EAKA,IAAMK,EAA4B,EAElC,SAAgBC,EAAiC,EAAkB,CACjE,SAASC,EAA2B,EAAe,CACjD,OAAOC,IAAU,EAAI,SAAW,QAClC,CAEA,eAAeC,EACb,EACA,EACA,EACe,CACf,IAAMC,EAAaV,EAAAA,mBAAmBW,EAAOC,CAAM,EAC9CF,GAEL,MAAMG,EAAQ,CACZ,KAAM,SACN,IAAKD,EAAO,MACZ,MAAOF,EACP,YAAa,QACb,kBAAmBH,EAA0BC,CAAK,EAClD,QAAS,CAAC,SAAS,CACrB,CAAC,CACH,CAEA,eAAeM,EACb,EACA,EACA,EACe,CACf,IAAMC,EAAU,IAAI,IAAY,CAACC,EAAK,KAAK,CAAC,EACtCC,EAAU,IAAI,IACdC,EAAa,IAAI,IACnBC,EAAqD,CAAC,CAAE,OAAQH,EAAM,MAAO,CAAE,CAAC,EAE9EI,EAAgB,KAAO,IAAuD,CAClF,GAAM,CAAE,OAAQC,EAAS,SAAUC,EAC7BC,EAAaF,EAAQ,IAAI,CAAC,CAAC,MAajC,GAZKH,EAAW,IAAIK,CAAU,IAC5BL,EAAW,IAAIK,CAAU,EACzB,MAAMtB,EAAAA,qBAAqBU,EAAOU,CAAO,GAGvCA,EAAQ,QAAUL,EAAK,QACpBC,EAAQ,IAAII,EAAQ,KAAK,IAC5BJ,EAAQ,IAAII,EAAQ,KAAK,EACzB,MAAMZ,EAAgBY,EAASb,EAAOK,CAAO,IAI7CL,GAASgB,EACX,MAAO,CAAC,EAGV,IAAMC,EAA0D,CAAC,EAC3DC,EAAWf,EAAM,KAAKU,EAASnB,EAAAA,GAAG,KAAK,OAAO,CAAC,EACrD,IAAK,IAAMyB,KAAWD,EACpB,GAAIC,EAAQ,WAAa,YAAa,CACpC,IAAMC,EAAc5B,EAAAA,mBAAmBW,EAAOgB,CAAO,EACjDA,EAAQ,QAAUX,EAAK,OAASY,GAAe,CAACX,EAAQ,IAAIU,EAAQ,KAAK,IAC3EV,EAAQ,IAAIU,EAAQ,KAAK,EACzB,MAAMd,EAAQ,CACZ,KAAM,SACN,IAAKc,EAAQ,MACb,MAAOC,EACP,YAAa,QACb,kBAAmBpB,IAAU,EAAI,SAAW,SAC5C,QAAS,CAAC,SAAS,CACrB,CAAC,GAGEO,EAAQ,IAAIY,EAAQ,KAAK,IAC5BZ,EAAQ,IAAIY,EAAQ,KAAK,EACzBF,EAAW,KAAK,CAAE,OAAQE,EAAS,MAAOnB,EAAQ,CAAE,CAAC,EAEzD,CAGF,OAAOiB,CACT,EAEA,KAAON,EAAM,OAAS,GAAG,CACvB,IAAMU,EAAyD,CAAC,EAEhE,IAAK,IAAIC,EAAQ,EAAGA,EAAQX,EAAM,OAAQ,GAASd,EAA2B,CAC5E,IAAM0B,EAAQZ,EAAM,MAAMW,EAAOA,EAAQzB,CAAyB,GAElE,MADqB,QAAQ,IAAI0B,EAAM,IAAIX,CAAa,CAAC,EAAA,CAClD,QAAQ,GAAWS,EAAU,KAAK,GAAGG,CAAO,CAAC,CACtD,CAEA,EAAQH,CACV,CACF,CAEA,MAAO,CACL,oBACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"friendsDirectory.esm.js","names":[],"sources":["../../src/directory/friendsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { loadDocumentSilently, storedLabelForNode } from './directoryHelpers'\n\nconst PEOPLE_SEARCH_CONCURRENCY = 6\n\nexport function createFriendsDirectoryDiscovery (store: LiveStore) {\n function relationshipLabelForDepth (depth: number) {\n return depth === 1 ? 'Friend' : 'People'\n }\n\n async function emitPersonEntry (\n person: NamedNode,\n depth: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const personName = storedLabelForNode(store, person)\n if (!personName) return\n\n await onEntry({\n kind: 'person',\n uri: person.value,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: relationshipLabelForDepth(depth),\n sources: ['friends']\n })\n }\n\n async function discoverFoafPeople (\n user: NamedNode,\n maxFoafDistance: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const visited = new Set<string>([user.value])\n const emitted = new Set<string>()\n const loadedDocs = new Set<string>()\n let queue: Array<{ person: NamedNode, depth: number }> = [{ person: user, depth: 0 }]\n\n const processPerson = async (currentEntry: { person: NamedNode, depth: number }) => {\n const { person: current, depth } = currentEntry\n const currentDoc = current.doc().value\n if (!loadedDocs.has(currentDoc)) {\n loadedDocs.add(currentDoc)\n await loadDocumentSilently(store, current)\n }\n\n if (current.value !== user.value) {\n if (!emitted.has(current.value)) {\n emitted.add(current.value)\n await emitPersonEntry(current, depth, onEntry)\n }\n }\n\n if (depth >= maxFoafDistance) {\n return [] as Array<{ person: NamedNode, depth: number }>\n }\n\n const nextPeople: Array<{ person: NamedNode, depth: number }> = []\n const contacts = store.each(current, ns.foaf('knows')) as NamedNode[]\n for (const contact of contacts) {\n if (contact.termType === 'NamedNode') {\n const contactName = storedLabelForNode(store, contact)\n if (contact.value !== user.value && contactName && !emitted.has(contact.value)) {\n emitted.add(contact.value)\n await onEntry({\n kind: 'person',\n uri: contact.value,\n label: contactName,\n subjectType: 'agent',\n relationshipLabel: depth === 0 ? 'Friend' : 'People',\n sources: ['friends']\n })\n }\n\n if (!visited.has(contact.value)) {\n visited.add(contact.value)\n nextPeople.push({ person: contact, depth: depth + 1 })\n }\n }\n }\n\n return nextPeople\n }\n\n while (queue.length > 0) {\n const nextQueue: Array<{ person: NamedNode, depth: number }> = []\n\n for (let index = 0; index < queue.length; index += PEOPLE_SEARCH_CONCURRENCY) {\n const batch = queue.slice(index, index + PEOPLE_SEARCH_CONCURRENCY)\n const nested = await Promise.all(batch.map(processPerson))\n nested.forEach(entries => nextQueue.push(...entries))\n }\n\n queue = nextQueue\n }\n }\n\n return {\n discoverFoafPeople\n }\n}\n"],"mappings":";;;AAKA,IAAM,IAA4B;AAElC,SAAgB,EAAiC,GAAkB;CACjE,SAAS,EAA2B,GAAe;EACjD,OAAO,MAAU,IAAI,WAAW;CAClC;CAEA,eAAe,EACb,GACA,GACA,GACe;EACf,IAAM,IAAa,EAAmB,GAAO,CAAM;EACnD,AAAK,KAEL,MAAM,EAAQ;GACZ,MAAM;GACN,KAAK,EAAO;GACZ,OAAO;GACP,aAAa;GACb,mBAAmB,EAA0B,CAAK;GAClD,SAAS,CAAC,SAAS;EACrB,CAAC;CACH;CAEA,eAAe,EACb,GACA,GACA,GACe;EACf,IAAM,oBAAU,IAAI,IAAY,CAAC,EAAK,KAAK,CAAC,GACtC,oBAAU,IAAI,IAAY,GAC1B,oBAAa,IAAI,IAAY,GAC/B,IAAqD,CAAC;GAAE,QAAQ;GAAM,OAAO;EAAE,CAAC,GAE9E,IAAgB,OAAO,MAAuD;GAClF,IAAM,EAAE,QAAQ,GAAS,aAAU,GAC7B,IAAa,EAAQ,IAAI,CAAC,CAAC;GAajC,IAZK,EAAW,IAAI,CAAU,MAC5B,EAAW,IAAI,CAAU,GACzB,MAAM,EAAqB,GAAO,CAAO,IAGvC,EAAQ,UAAU,EAAK,UACpB,EAAQ,IAAI,EAAQ,KAAK,MAC5B,EAAQ,IAAI,EAAQ,KAAK,GACzB,MAAM,EAAgB,GAAS,GAAO,CAAO,KAI7C,KAAS,GACX,OAAO,CAAC;GAGV,IAAM,IAA0D,CAAC,GAC3D,IAAW,EAAM,KAAK,GAAS,EAAG,KAAK,OAAO,CAAC;GACrD,KAAK,IAAM,KAAW,GACpB,IAAI,EAAQ,aAAa,aAAa;IACpC,IAAM,IAAc,EAAmB,GAAO,CAAO;IAarD,AAZI,EAAQ,UAAU,EAAK,SAAS,KAAe,CAAC,EAAQ,IAAI,EAAQ,KAAK,MAC3E,EAAQ,IAAI,EAAQ,KAAK,GACzB,MAAM,EAAQ;KACZ,MAAM;KACN,KAAK,EAAQ;KACb,OAAO;KACP,aAAa;KACb,mBAAmB,MAAU,IAAI,WAAW;KAC5C,SAAS,CAAC,SAAS;IACrB,CAAC,IAGE,EAAQ,IAAI,EAAQ,KAAK,MAC5B,EAAQ,IAAI,EAAQ,KAAK,GACzB,EAAW,KAAK;KAAE,QAAQ;KAAS,OAAO,IAAQ;IAAE,CAAC;GAEzD;GAGF,OAAO;EACT;EAEA,OAAO,EAAM,SAAS,IAAG;GACvB,IAAM,IAAyD,CAAC;GAEhE,KAAK,IAAI,IAAQ,GAAG,IAAQ,EAAM,QAAQ,KAAS,GAA2B;IAC5E,IAAM,IAAQ,EAAM,MAAM,GAAO,IAAQ,CAAyB;IAElE,CAAA,MADqB,QAAQ,IAAI,EAAM,IAAI,CAAa,CAAC,EAAA,CAClD,SAAQ,MAAW,EAAU,KAAK,GAAG,CAAO,CAAC;GACtD;GAEA,IAAQ;EACV;CACF;CAEA,OAAO,EACL,sBACF;AACF"}
1
+ {"version":3,"file":"friendsDirectory.esm.js","names":["PEOPLE_SEARCH_CONCURRENCY","createFriendsDirectoryDiscovery","relationshipLabelForDepth","depth","emitPersonEntry","personName","storedLabelForNode","store","person","onEntry","discoverFoafPeople","visited","user","emitted","loadedDocs","queue","processPerson","current","currentEntry","currentDoc","loadDocumentSilently","maxFoafDistance","nextPeople","contacts","ns","contact","contactName","nextQueue","index","batch","entries"],"sources":["../../src/directory/friendsDirectory.ts"],"sourcesContent":["import { type DirectoryEntry } from '../types'\nimport { type LiveStore, NamedNode } from 'rdflib'\nimport { ns } from '../util/ns'\nimport { loadDocumentSilently, storedLabelForNode } from './directoryHelpers'\n\nconst PEOPLE_SEARCH_CONCURRENCY = 6\n\nexport function createFriendsDirectoryDiscovery (store: LiveStore) {\n function relationshipLabelForDepth (depth: number) {\n return depth === 1 ? 'Friend' : 'People'\n }\n\n async function emitPersonEntry (\n person: NamedNode,\n depth: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const personName = storedLabelForNode(store, person)\n if (!personName) return\n\n await onEntry({\n kind: 'person',\n uri: person.value,\n label: personName,\n subjectType: 'agent',\n relationshipLabel: relationshipLabelForDepth(depth),\n sources: ['friends']\n })\n }\n\n async function discoverFoafPeople (\n user: NamedNode,\n maxFoafDistance: number,\n onEntry: (entry: DirectoryEntry) => void | Promise<void>\n ): Promise<void> {\n const visited = new Set<string>([user.value])\n const emitted = new Set<string>()\n const loadedDocs = new Set<string>()\n let queue: Array<{ person: NamedNode, depth: number }> = [{ person: user, depth: 0 }]\n\n const processPerson = async (currentEntry: { person: NamedNode, depth: number }) => {\n const { person: current, depth } = currentEntry\n const currentDoc = current.doc().value\n if (!loadedDocs.has(currentDoc)) {\n loadedDocs.add(currentDoc)\n await loadDocumentSilently(store, current)\n }\n\n if (current.value !== user.value) {\n if (!emitted.has(current.value)) {\n emitted.add(current.value)\n await emitPersonEntry(current, depth, onEntry)\n }\n }\n\n if (depth >= maxFoafDistance) {\n return [] as Array<{ person: NamedNode, depth: number }>\n }\n\n const nextPeople: Array<{ person: NamedNode, depth: number }> = []\n const contacts = store.each(current, ns.foaf('knows')) as NamedNode[]\n for (const contact of contacts) {\n if (contact.termType === 'NamedNode') {\n const contactName = storedLabelForNode(store, contact)\n if (contact.value !== user.value && contactName && !emitted.has(contact.value)) {\n emitted.add(contact.value)\n await onEntry({\n kind: 'person',\n uri: contact.value,\n label: contactName,\n subjectType: 'agent',\n relationshipLabel: depth === 0 ? 'Friend' : 'People',\n sources: ['friends']\n })\n }\n\n if (!visited.has(contact.value)) {\n visited.add(contact.value)\n nextPeople.push({ person: contact, depth: depth + 1 })\n }\n }\n }\n\n return nextPeople\n }\n\n while (queue.length > 0) {\n const nextQueue: Array<{ person: NamedNode, depth: number }> = []\n\n for (let index = 0; index < queue.length; index += PEOPLE_SEARCH_CONCURRENCY) {\n const batch = queue.slice(index, index + PEOPLE_SEARCH_CONCURRENCY)\n const nested = await Promise.all(batch.map(processPerson))\n nested.forEach(entries => nextQueue.push(...entries))\n }\n\n queue = nextQueue\n }\n }\n\n return {\n discoverFoafPeople\n }\n}\n"],"mappings":";;;AAKA,IAAMA,IAA4B;AAElC,SAAgBC,EAAiC,GAAkB;CACjE,SAASC,EAA2B,GAAe;EACjD,OAAOC,MAAU,IAAI,WAAW;CAClC;CAEA,eAAeC,EACb,GACA,GACA,GACe;EACf,IAAMC,IAAaC,EAAmBC,GAAOC,CAAM;EACnD,AAAKH,KAEL,MAAMI,EAAQ;GACZ,MAAM;GACN,KAAKD,EAAO;GACZ,OAAOH;GACP,aAAa;GACb,mBAAmBH,EAA0BC,CAAK;GAClD,SAAS,CAAC,SAAS;EACrB,CAAC;CACH;CAEA,eAAeO,EACb,GACA,GACA,GACe;EACf,IAAMC,oBAAU,IAAI,IAAY,CAACC,EAAK,KAAK,CAAC,GACtCC,oBAAU,IAAI,IAAY,GAC1BC,oBAAa,IAAI,IAAY,GAC/BC,IAAqD,CAAC;GAAE,QAAQH;GAAM,OAAO;EAAE,CAAC,GAE9EI,IAAgB,OAAO,MAAuD;GAClF,IAAM,EAAE,QAAQC,GAAS,aAAUC,GAC7BC,IAAaF,EAAQ,IAAI,CAAC,CAAC;GAajC,IAZKH,EAAW,IAAIK,CAAU,MAC5BL,EAAW,IAAIK,CAAU,GACzB,MAAMC,EAAqBb,GAAOU,CAAO,IAGvCA,EAAQ,UAAUL,EAAK,UACpBC,EAAQ,IAAII,EAAQ,KAAK,MAC5BJ,EAAQ,IAAII,EAAQ,KAAK,GACzB,MAAMb,EAAgBa,GAASd,GAAOM,CAAO,KAI7CN,KAASkB,GACX,OAAO,CAAC;GAGV,IAAMC,IAA0D,CAAC,GAC3DC,IAAWhB,EAAM,KAAKU,GAASO,EAAG,KAAK,OAAO,CAAC;GACrD,KAAK,IAAMC,KAAWF,GACpB,IAAIE,EAAQ,aAAa,aAAa;IACpC,IAAMC,IAAcpB,EAAmBC,GAAOkB,CAAO;IAarD,AAZIA,EAAQ,UAAUb,EAAK,SAASc,KAAe,CAACb,EAAQ,IAAIY,EAAQ,KAAK,MAC3EZ,EAAQ,IAAIY,EAAQ,KAAK,GACzB,MAAMhB,EAAQ;KACZ,MAAM;KACN,KAAKgB,EAAQ;KACb,OAAOC;KACP,aAAa;KACb,mBAAmBvB,MAAU,IAAI,WAAW;KAC5C,SAAS,CAAC,SAAS;IACrB,CAAC,IAGEQ,EAAQ,IAAIc,EAAQ,KAAK,MAC5Bd,EAAQ,IAAIc,EAAQ,KAAK,GACzBH,EAAW,KAAK;KAAE,QAAQG;KAAS,OAAOtB,IAAQ;IAAE,CAAC;GAEzD;GAGF,OAAOmB;EACT;EAEA,OAAOP,EAAM,SAAS,IAAG;GACvB,IAAMY,IAAyD,CAAC;GAEhE,KAAK,IAAIC,IAAQ,GAAGA,IAAQb,EAAM,QAAQ,KAASf,GAA2B;IAC5E,IAAM6B,IAAQd,EAAM,MAAMa,GAAOA,IAAQ5B,CAAyB;IAElE,CAAA,MADqB,QAAQ,IAAI6B,EAAM,IAAIb,CAAa,CAAC,EAAA,CAClD,SAAQ,MAAWW,EAAU,KAAK,GAAGG,CAAO,CAAC;GACtD;GAEA,IAAQH;EACV;CACF;CAEA,OAAO,EACL,sBACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"inboxLogic.cjs.js","names":[],"sources":["../../src/inbox/inboxLogic.ts"],"sourcesContent":["import { NamedNode } from 'rdflib'\nimport { InboxLogic } from '../types'\nimport { getArchiveUrl } from '../util/utils'\n\nexport function createInboxLogic(store, profileLogic, utilityLogic, containerLogic, aclLogic): InboxLogic {\n\n async function createInboxFor(peerWebId: string, nick: string) {\n const myWebId: NamedNode = await profileLogic.loadMe()\n const podRoot: NamedNode = await profileLogic.getPodRoot(myWebId)\n const ourInbox = `${podRoot.value}p2p-inboxes/${encodeURIComponent(nick)}/`\n await containerLogic.createContainer(ourInbox)\n // const aclDocUrl = await aclLogic.findAclDocUrl(ourInbox);\n await utilityLogic.setSinglePeerAccess({\n ownerWebId: myWebId.value,\n peerWebId,\n accessToModes: 'acl:Append',\n target: ourInbox\n })\n return ourInbox\n }\n\n async function getNewMessages(\n user?: NamedNode\n ): Promise<NamedNode[]> {\n if (!user) {\n user = await profileLogic.loadMe()\n }\n const inbox = await profileLogic.getMainInbox(user)\n const urls = await containerLogic.getContainerMembers(inbox)\n return urls.filter(url => !containerLogic.isContainer(url))\n }\n\n async function markAsRead(url: string, date: Date) {\n const downloaded = await store.fetcher._fetch(url)\n if (downloaded.status !== 200) {\n throw new Error(`Not OK! ${url}`)\n }\n const archiveUrl = getArchiveUrl(url, date)\n const options = {\n method: 'PUT',\n body: await downloaded.text(),\n headers: [\n ['Content-Type', downloaded.headers.get('Content-Type') || 'application/octet-stream']\n ]\n }\n const uploaded = await store.fetcher._fetch(archiveUrl, options)\n if (uploaded.status.toString()[0] === '2') {\n await store.fetcher._fetch(url, {\n method: 'DELETE'\n })\n }\n }\n return {\n createInboxFor,\n getNewMessages,\n markAsRead\n }\n}\n"],"mappings":"wCAIA,SAAgB,EAAiB,EAAO,EAAc,EAAc,EAAgB,EAAsB,CAEtG,eAAe,EAAe,EAAmB,EAAc,CAC7D,IAAM,EAAqB,MAAM,EAAa,OAAO,EAE/C,EAAW,IAAG,MADa,EAAa,WAAW,CAAO,EAAA,CACpC,MAAM,cAAc,mBAAmB,CAAI,EAAE,GASzE,OARA,MAAM,EAAe,gBAAgB,CAAQ,EAE7C,MAAM,EAAa,oBAAoB,CACrC,WAAY,EAAQ,MACpB,YACA,cAAe,aACf,OAAQ,CACV,CAAC,EACM,CACX,CAEA,eAAe,EACX,EACsB,CACtB,AACE,IAAO,MAAM,EAAa,OAAO,EAEnC,IAAM,EAAQ,MAAM,EAAa,aAAa,CAAI,EAElD,OAAO,MADY,EAAe,oBAAoB,CAAK,EAAA,CAC/C,OAAO,GAAO,CAAC,EAAe,YAAY,CAAG,CAAC,CAC9D,CAEA,eAAe,EAAW,EAAa,EAAY,CACjD,IAAM,EAAa,MAAM,EAAM,QAAQ,OAAO,CAAG,EACjD,GAAI,EAAW,SAAW,IACxB,MAAU,MAAM,WAAW,GAAK,EAElC,IAAM,EAAa,EAAA,cAAc,EAAK,CAAI,EACpC,EAAU,CACd,OAAQ,MACR,KAAM,MAAM,EAAW,KAAK,EAC5B,QAAS,CACP,CAAC,eAAgB,EAAW,QAAQ,IAAI,cAAc,GAAK,0BAA0B,CACvF,CACF,GAEI,MADmB,EAAM,QAAQ,OAAO,EAAY,CAAO,EAAA,CAClD,OAAO,SAAS,CAAC,CAAC,KAAO,KACpC,MAAM,EAAM,QAAQ,OAAO,EAAK,CAC9B,OAAQ,QACV,CAAC,CAEL,CACA,MAAO,CACL,iBACA,iBACA,YACF,CACF"}
1
+ {"version":3,"file":"inboxLogic.cjs.js","names":["getArchiveUrl","require_utils","createInboxLogic","createInboxFor","myWebId","profileLogic","ourInbox","nick","containerLogic","utilityLogic","getNewMessages","user","inbox","url","markAsRead","downloaded","store","archiveUrl","date","options"],"sources":["../../src/inbox/inboxLogic.ts"],"sourcesContent":["import { NamedNode } from 'rdflib'\nimport { InboxLogic } from '../types'\nimport { getArchiveUrl } from '../util/utils'\n\nexport function createInboxLogic(store, profileLogic, utilityLogic, containerLogic, aclLogic): InboxLogic {\n\n async function createInboxFor(peerWebId: string, nick: string) {\n const myWebId: NamedNode = await profileLogic.loadMe()\n const podRoot: NamedNode = await profileLogic.getPodRoot(myWebId)\n const ourInbox = `${podRoot.value}p2p-inboxes/${encodeURIComponent(nick)}/`\n await containerLogic.createContainer(ourInbox)\n // const aclDocUrl = await aclLogic.findAclDocUrl(ourInbox);\n await utilityLogic.setSinglePeerAccess({\n ownerWebId: myWebId.value,\n peerWebId,\n accessToModes: 'acl:Append',\n target: ourInbox\n })\n return ourInbox\n }\n\n async function getNewMessages(\n user?: NamedNode\n ): Promise<NamedNode[]> {\n if (!user) {\n user = await profileLogic.loadMe()\n }\n const inbox = await profileLogic.getMainInbox(user)\n const urls = await containerLogic.getContainerMembers(inbox)\n return urls.filter(url => !containerLogic.isContainer(url))\n }\n\n async function markAsRead(url: string, date: Date) {\n const downloaded = await store.fetcher._fetch(url)\n if (downloaded.status !== 200) {\n throw new Error(`Not OK! ${url}`)\n }\n const archiveUrl = getArchiveUrl(url, date)\n const options = {\n method: 'PUT',\n body: await downloaded.text(),\n headers: [\n ['Content-Type', downloaded.headers.get('Content-Type') || 'application/octet-stream']\n ]\n }\n const uploaded = await store.fetcher._fetch(archiveUrl, options)\n if (uploaded.status.toString()[0] === '2') {\n await store.fetcher._fetch(url, {\n method: 'DELETE'\n })\n }\n }\n return {\n createInboxFor,\n getNewMessages,\n markAsRead\n }\n}\n"],"mappings":"wCAIA,SAAgBE,EAAiB,EAAO,EAAc,EAAc,EAAgB,EAAsB,CAEtG,eAAeC,EAAe,EAAmB,EAAc,CAC7D,IAAMC,EAAqB,MAAMC,EAAa,OAAO,EAE/CC,EAAW,IAAG,MADaD,EAAa,WAAWD,CAAO,EAAA,CACpC,MAAM,cAAc,mBAAmBG,CAAI,EAAE,GASzE,OARA,MAAMC,EAAe,gBAAgBF,CAAQ,EAE7C,MAAMG,EAAa,oBAAoB,CACrC,WAAYL,EAAQ,MACpB,YACA,cAAe,aACf,OAAQE,CACV,CAAC,EACMA,CACX,CAEA,eAAeI,EACX,EACsB,CACtB,AACEC,IAAO,MAAMN,EAAa,OAAO,EAEnC,IAAMO,EAAQ,MAAMP,EAAa,aAAaM,CAAI,EAElD,OAAO,MADYH,EAAe,oBAAoBI,CAAK,EAAA,CAC/C,OAAO,GAAO,CAACJ,EAAe,YAAYK,CAAG,CAAC,CAC9D,CAEA,eAAeC,EAAW,EAAa,EAAY,CACjD,IAAMC,EAAa,MAAMC,EAAM,QAAQ,OAAOH,CAAG,EACjD,GAAIE,EAAW,SAAW,IACxB,MAAU,MAAM,WAAWF,GAAK,EAElC,IAAMI,EAAajB,EAAAA,cAAca,EAAKK,CAAI,EACpCC,EAAU,CACd,OAAQ,MACR,KAAM,MAAMJ,EAAW,KAAK,EAC5B,QAAS,CACP,CAAC,eAAgBA,EAAW,QAAQ,IAAI,cAAc,GAAK,0BAA0B,CACvF,CACF,GAEI,MADmBC,EAAM,QAAQ,OAAOC,EAAYE,CAAO,EAAA,CAClD,OAAO,SAAS,CAAC,CAAC,KAAO,KACpC,MAAMH,EAAM,QAAQ,OAAOH,EAAK,CAC9B,OAAQ,QACV,CAAC,CAEL,CACA,MAAO,CACL,iBACA,iBACA,YACF,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"inboxLogic.esm.js","names":[],"sources":["../../src/inbox/inboxLogic.ts"],"sourcesContent":["import { NamedNode } from 'rdflib'\nimport { InboxLogic } from '../types'\nimport { getArchiveUrl } from '../util/utils'\n\nexport function createInboxLogic(store, profileLogic, utilityLogic, containerLogic, aclLogic): InboxLogic {\n\n async function createInboxFor(peerWebId: string, nick: string) {\n const myWebId: NamedNode = await profileLogic.loadMe()\n const podRoot: NamedNode = await profileLogic.getPodRoot(myWebId)\n const ourInbox = `${podRoot.value}p2p-inboxes/${encodeURIComponent(nick)}/`\n await containerLogic.createContainer(ourInbox)\n // const aclDocUrl = await aclLogic.findAclDocUrl(ourInbox);\n await utilityLogic.setSinglePeerAccess({\n ownerWebId: myWebId.value,\n peerWebId,\n accessToModes: 'acl:Append',\n target: ourInbox\n })\n return ourInbox\n }\n\n async function getNewMessages(\n user?: NamedNode\n ): Promise<NamedNode[]> {\n if (!user) {\n user = await profileLogic.loadMe()\n }\n const inbox = await profileLogic.getMainInbox(user)\n const urls = await containerLogic.getContainerMembers(inbox)\n return urls.filter(url => !containerLogic.isContainer(url))\n }\n\n async function markAsRead(url: string, date: Date) {\n const downloaded = await store.fetcher._fetch(url)\n if (downloaded.status !== 200) {\n throw new Error(`Not OK! ${url}`)\n }\n const archiveUrl = getArchiveUrl(url, date)\n const options = {\n method: 'PUT',\n body: await downloaded.text(),\n headers: [\n ['Content-Type', downloaded.headers.get('Content-Type') || 'application/octet-stream']\n ]\n }\n const uploaded = await store.fetcher._fetch(archiveUrl, options)\n if (uploaded.status.toString()[0] === '2') {\n await store.fetcher._fetch(url, {\n method: 'DELETE'\n })\n }\n }\n return {\n createInboxFor,\n getNewMessages,\n markAsRead\n }\n}\n"],"mappings":";;AAIA,SAAgB,EAAiB,GAAO,GAAc,GAAc,GAAgB,GAAsB;CAEtG,eAAe,EAAe,GAAmB,GAAc;EAC7D,IAAM,IAAqB,MAAM,EAAa,OAAO,GAE/C,IAAW,IAAG,MADa,EAAa,WAAW,CAAO,EAAA,CACpC,MAAM,cAAc,mBAAmB,CAAI,EAAE;EASzE,OARA,MAAM,EAAe,gBAAgB,CAAQ,GAE7C,MAAM,EAAa,oBAAoB;GACrC,YAAY,EAAQ;GACpB;GACA,eAAe;GACf,QAAQ;EACV,CAAC,GACM;CACX;CAEA,eAAe,EACX,GACsB;EACtB,AACE,MAAO,MAAM,EAAa,OAAO;EAEnC,IAAM,IAAQ,MAAM,EAAa,aAAa,CAAI;EAElD,QAAO,MADY,EAAe,oBAAoB,CAAK,EAAA,CAC/C,QAAO,MAAO,CAAC,EAAe,YAAY,CAAG,CAAC;CAC9D;CAEA,eAAe,EAAW,GAAa,GAAY;EACjD,IAAM,IAAa,MAAM,EAAM,QAAQ,OAAO,CAAG;EACjD,IAAI,EAAW,WAAW,KACxB,MAAU,MAAM,WAAW,GAAK;EAElC,IAAM,IAAa,EAAc,GAAK,CAAI,GACpC,IAAU;GACd,QAAQ;GACR,MAAM,MAAM,EAAW,KAAK;GAC5B,SAAS,CACP,CAAC,gBAAgB,EAAW,QAAQ,IAAI,cAAc,KAAK,0BAA0B,CACvF;EACF;EAEA,CAAI,MADmB,EAAM,QAAQ,OAAO,GAAY,CAAO,EAAA,CAClD,OAAO,SAAS,CAAC,CAAC,OAAO,OACpC,MAAM,EAAM,QAAQ,OAAO,GAAK,EAC9B,QAAQ,SACV,CAAC;CAEL;CACA,OAAO;EACL;EACA;EACA;CACF;AACF"}
1
+ {"version":3,"file":"inboxLogic.esm.js","names":["createInboxLogic","createInboxFor","myWebId","profileLogic","ourInbox","nick","containerLogic","utilityLogic","getNewMessages","user","inbox","url","markAsRead","downloaded","store","archiveUrl","getArchiveUrl","date","options"],"sources":["../../src/inbox/inboxLogic.ts"],"sourcesContent":["import { NamedNode } from 'rdflib'\nimport { InboxLogic } from '../types'\nimport { getArchiveUrl } from '../util/utils'\n\nexport function createInboxLogic(store, profileLogic, utilityLogic, containerLogic, aclLogic): InboxLogic {\n\n async function createInboxFor(peerWebId: string, nick: string) {\n const myWebId: NamedNode = await profileLogic.loadMe()\n const podRoot: NamedNode = await profileLogic.getPodRoot(myWebId)\n const ourInbox = `${podRoot.value}p2p-inboxes/${encodeURIComponent(nick)}/`\n await containerLogic.createContainer(ourInbox)\n // const aclDocUrl = await aclLogic.findAclDocUrl(ourInbox);\n await utilityLogic.setSinglePeerAccess({\n ownerWebId: myWebId.value,\n peerWebId,\n accessToModes: 'acl:Append',\n target: ourInbox\n })\n return ourInbox\n }\n\n async function getNewMessages(\n user?: NamedNode\n ): Promise<NamedNode[]> {\n if (!user) {\n user = await profileLogic.loadMe()\n }\n const inbox = await profileLogic.getMainInbox(user)\n const urls = await containerLogic.getContainerMembers(inbox)\n return urls.filter(url => !containerLogic.isContainer(url))\n }\n\n async function markAsRead(url: string, date: Date) {\n const downloaded = await store.fetcher._fetch(url)\n if (downloaded.status !== 200) {\n throw new Error(`Not OK! ${url}`)\n }\n const archiveUrl = getArchiveUrl(url, date)\n const options = {\n method: 'PUT',\n body: await downloaded.text(),\n headers: [\n ['Content-Type', downloaded.headers.get('Content-Type') || 'application/octet-stream']\n ]\n }\n const uploaded = await store.fetcher._fetch(archiveUrl, options)\n if (uploaded.status.toString()[0] === '2') {\n await store.fetcher._fetch(url, {\n method: 'DELETE'\n })\n }\n }\n return {\n createInboxFor,\n getNewMessages,\n markAsRead\n }\n}\n"],"mappings":";;AAIA,SAAgBA,EAAiB,GAAO,GAAc,GAAc,GAAgB,GAAsB;CAEtG,eAAeC,EAAe,GAAmB,GAAc;EAC7D,IAAMC,IAAqB,MAAMC,EAAa,OAAO,GAE/CC,IAAW,IAAG,MADaD,EAAa,WAAWD,CAAO,EAAA,CACpC,MAAM,cAAc,mBAAmBG,CAAI,EAAE;EASzE,OARA,MAAMC,EAAe,gBAAgBF,CAAQ,GAE7C,MAAMG,EAAa,oBAAoB;GACrC,YAAYL,EAAQ;GACpB;GACA,eAAe;GACf,QAAQE;EACV,CAAC,GACMA;CACX;CAEA,eAAeI,EACX,GACsB;EACtB,AACEC,MAAO,MAAMN,EAAa,OAAO;EAEnC,IAAMO,IAAQ,MAAMP,EAAa,aAAaM,CAAI;EAElD,QAAO,MADYH,EAAe,oBAAoBI,CAAK,EAAA,CAC/C,QAAO,MAAO,CAACJ,EAAe,YAAYK,CAAG,CAAC;CAC9D;CAEA,eAAeC,EAAW,GAAa,GAAY;EACjD,IAAMC,IAAa,MAAMC,EAAM,QAAQ,OAAOH,CAAG;EACjD,IAAIE,EAAW,WAAW,KACxB,MAAU,MAAM,WAAWF,GAAK;EAElC,IAAMI,IAAaC,EAAcL,GAAKM,CAAI,GACpCC,IAAU;GACd,QAAQ;GACR,MAAM,MAAML,EAAW,KAAK;GAC5B,SAAS,CACP,CAAC,gBAAgBA,EAAW,QAAQ,IAAI,cAAc,KAAK,0BAA0B,CACvF;EACF;EAEA,CAAI,MADmBC,EAAM,QAAQ,OAAOC,GAAYG,CAAO,EAAA,CAClD,OAAO,SAAS,CAAC,CAAC,OAAO,OACpC,MAAMJ,EAAM,QAAQ,OAAOH,GAAK,EAC9B,QAAQ,SACV,CAAC;CAEL;CACA,OAAO;EACL;EACA;EACA;CACF;AACF"}