@undefineds.co/xpod 0.3.6 → 0.3.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/cli.json +1 -1
- package/config/cloud.json +54 -22
- package/config/local.json +56 -12
- package/config/resolver.json +10 -2
- package/config/xpod.base.json +50 -0
- package/config/xpod.json +8 -8
- package/dist/agents/config/resolve.js +10 -10
- package/dist/agents/config/resolve.js.map +1 -1
- package/dist/api/chatkit/index.d.ts +1 -1
- package/dist/api/chatkit/index.js.map +1 -1
- package/dist/api/chatkit/pod-store.d.ts +14 -11
- package/dist/api/chatkit/pod-store.js +114 -78
- package/dist/api/chatkit/pod-store.js.map +1 -1
- package/dist/api/chatkit/runtime/AcpAgentRuntime.js +1 -1
- package/dist/api/chatkit/runtime/AcpAgentRuntime.js.map +1 -1
- package/dist/api/chatkit/service.js +1 -1
- package/dist/api/chatkit/service.js.map +1 -1
- package/dist/api/chatkit/types.d.ts +11 -11
- package/dist/api/chatkit/types.js +3 -3
- package/dist/api/chatkit/types.js.map +1 -1
- package/dist/api/container/cloud.js +0 -8
- package/dist/api/container/cloud.js.map +1 -1
- package/dist/api/container/index.js +2 -1
- package/dist/api/container/index.js.map +1 -1
- package/dist/api/container/local.js +0 -7
- package/dist/api/container/local.js.map +1 -1
- package/dist/api/container/routes.js +3 -17
- package/dist/api/container/routes.js.map +1 -1
- package/dist/api/container/types.d.ts +0 -2
- package/dist/api/container/types.js.map +1 -1
- package/dist/api/handlers/PodManagementHandler.d.ts +3 -0
- package/dist/api/handlers/PodManagementHandler.js +71 -1
- package/dist/api/handlers/PodManagementHandler.js.map +1 -1
- package/dist/api/handlers/RunHandler.js +5 -5
- package/dist/api/handlers/RunHandler.js.map +1 -1
- package/dist/api/runs/AgentRuntimeTypes.d.ts +7 -8
- package/dist/api/runs/AgentRuntimeTypes.js.map +1 -1
- package/dist/api/runs/InngestRunExecutionBackend.d.ts +2 -2
- package/dist/api/runs/ManagedRunWorker.d.ts +1 -1
- package/dist/api/runs/ManagedRunWorker.js +6 -6
- package/dist/api/runs/ManagedRunWorker.js.map +1 -1
- package/dist/api/runs/PiAgentRuntimeDriver.d.ts +16 -1
- package/dist/api/runs/PiAgentRuntimeDriver.js +182 -23
- package/dist/api/runs/PiAgentRuntimeDriver.js.map +1 -1
- package/dist/api/runs/RunStateCenter.d.ts +3 -3
- package/dist/api/runs/RunStateCenter.js +13 -13
- package/dist/api/runs/RunStateCenter.js.map +1 -1
- package/dist/api/runs/store.d.ts +4 -4
- package/dist/api/runs/store.js +2 -2
- package/dist/api/runs/store.js.map +1 -1
- package/dist/api/service/VectorStoreService.d.ts +1 -1
- package/dist/api/service/VectorStoreService.js +16 -16
- package/dist/api/service/VectorStoreService.js.map +1 -1
- package/dist/api/tasks/InngestTaskScheduler.d.ts +4 -4
- package/dist/api/tasks/TaskMaterializer.d.ts +3 -3
- package/dist/api/tasks/TaskMaterializer.js +11 -11
- package/dist/api/tasks/TaskMaterializer.js.map +1 -1
- package/dist/api/tasks/TaskService.d.ts +3 -3
- package/dist/api/tasks/TaskService.js +11 -7
- package/dist/api/tasks/TaskService.js.map +1 -1
- package/dist/api/tasks/store.d.ts +10 -4
- package/dist/api/tasks/store.js +14 -4
- package/dist/api/tasks/store.js.map +1 -1
- package/dist/api/workspace/types.d.ts +3 -3
- package/dist/api/workspace/types.js +6 -6
- package/dist/api/workspace/types.js.map +1 -1
- package/dist/cli/commands/config.js +2 -2
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/start.js +9 -3
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/components/components.jsonld +8 -2
- package/dist/components/context.jsonld +308 -51
- package/dist/http/search/SearchHttpHandler.js +8 -8
- package/dist/http/search/SearchHttpHandler.js.map +1 -1
- package/dist/identity/drizzle/PodLookupRepository.d.ts +11 -1
- package/dist/identity/drizzle/PodLookupRepository.js +95 -4
- package/dist/identity/drizzle/PodLookupRepository.js.map +1 -1
- package/dist/identity/drizzle/db.js +4 -43
- package/dist/identity/drizzle/db.js.map +1 -1
- package/dist/identity/drizzle/schema.pg.d.ts +0 -5
- package/dist/identity/drizzle/schema.pg.js +2 -16
- package/dist/identity/drizzle/schema.pg.js.map +1 -1
- package/dist/identity/drizzle/schema.sqlite.d.ts +19 -176
- package/dist/identity/drizzle/schema.sqlite.js +2 -16
- package/dist/identity/drizzle/schema.sqlite.js.map +1 -1
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.d.ts +4 -4
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js +7 -7
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.js.map +1 -1
- package/dist/identity/oidc/AutoDetectIdentityProviderHandler.jsonld +6 -6
- package/dist/identity/oidc/AutoDetectOidcHandler.d.ts +4 -4
- package/dist/identity/oidc/AutoDetectOidcHandler.js +6 -6
- package/dist/identity/oidc/AutoDetectOidcHandler.js.map +1 -1
- package/dist/identity/oidc/AutoDetectOidcHandler.jsonld +6 -6
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +37 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +211 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js.map +1 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +158 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/main.js +8 -2
- package/dist/main.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.d.ts +3 -4
- package/dist/provision/ProvisionPodCreator.js +8 -13
- package/dist/provision/ProvisionPodCreator.js.map +1 -1
- package/dist/provision/ProvisionPodCreator.jsonld +7 -7
- package/dist/runtime/Proxy.d.ts +0 -1
- package/dist/runtime/Proxy.js +0 -9
- package/dist/runtime/Proxy.js.map +1 -1
- package/dist/runtime/bootstrap.d.ts +1 -0
- package/dist/runtime/bootstrap.js +5 -2
- package/dist/runtime/bootstrap.js.map +1 -1
- package/dist/runtime/css-process.d.ts +12 -4
- package/dist/runtime/css-process.js +61 -14
- package/dist/runtime/css-process.js.map +1 -1
- package/dist/runtime/oidc-issuer.d.ts +3 -2
- package/dist/runtime/oidc-issuer.js +3 -2
- package/dist/runtime/oidc-issuer.js.map +1 -1
- package/dist/runtime/runtime-types.d.ts +1 -0
- package/dist/runtime/runtime-types.js.map +1 -1
- package/dist/solidfs/LocalFirstRdfRepresentationResolver.d.ts +21 -0
- package/dist/solidfs/LocalFirstRdfRepresentationResolver.js +38 -0
- package/dist/solidfs/LocalFirstRdfRepresentationResolver.js.map +1 -0
- package/dist/solidfs/LocalSolidFS.d.ts +18 -0
- package/dist/solidfs/LocalSolidFS.js +539 -0
- package/dist/solidfs/LocalSolidFS.js.map +1 -0
- package/dist/solidfs/PodSolidFsHttpClient.d.ts +16 -0
- package/dist/solidfs/PodSolidFsHttpClient.js +93 -0
- package/dist/solidfs/PodSolidFsHttpClient.js.map +1 -0
- package/dist/solidfs/PodSolidFsHydrator.d.ts +27 -0
- package/dist/solidfs/PodSolidFsHydrator.js +127 -0
- package/dist/solidfs/PodSolidFsHydrator.js.map +1 -0
- package/dist/solidfs/PodSolidFsSyncer.d.ts +21 -0
- package/dist/solidfs/PodSolidFsSyncer.js +78 -0
- package/dist/solidfs/PodSolidFsSyncer.js.map +1 -0
- package/dist/solidfs/RdfIndexSolidFsSyncer.d.ts +22 -0
- package/dist/solidfs/RdfIndexSolidFsSyncer.js +131 -0
- package/dist/solidfs/RdfIndexSolidFsSyncer.js.map +1 -0
- package/dist/solidfs/index.d.ts +7 -0
- package/dist/solidfs/index.js +24 -0
- package/dist/solidfs/index.js.map +1 -0
- package/dist/solidfs/types.d.ts +131 -0
- package/dist/solidfs/types.js +19 -0
- package/dist/solidfs/types.js.map +1 -0
- package/dist/storage/RepresentationPartialConvertingStore.js +6 -13
- package/dist/storage/RepresentationPartialConvertingStore.js.map +1 -1
- package/dist/storage/SparqlUpdateResourceStore.d.ts +4 -0
- package/dist/storage/SparqlUpdateResourceStore.js +13 -0
- package/dist/storage/SparqlUpdateResourceStore.js.map +1 -1
- package/dist/storage/SparqlUpdateResourceStore.jsonld +26 -0
- package/dist/storage/accessors/MixDataAccessor.d.ts +85 -4
- package/dist/storage/accessors/MixDataAccessor.js +511 -16
- package/dist/storage/accessors/MixDataAccessor.js.map +1 -1
- package/dist/storage/accessors/MixDataAccessor.jsonld +176 -1
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.d.ts +7 -0
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js +72 -4
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.js.map +1 -1
- package/dist/storage/accessors/QuintStoreSparqlDataAccessor.jsonld +24 -0
- package/dist/storage/quint/BaseQuintStore.d.ts +3 -0
- package/dist/storage/quint/BaseQuintStore.js +51 -27
- package/dist/storage/quint/BaseQuintStore.js.map +1 -1
- package/dist/storage/quint/PgQuintStore.d.ts +1 -0
- package/dist/storage/quint/PgQuintStore.js +50 -32
- package/dist/storage/quint/PgQuintStore.js.map +1 -1
- package/dist/storage/quint/PgQuintStore.jsonld +4 -3
- package/dist/storage/quint/SqliteQuintStore.d.ts +5 -0
- package/dist/storage/quint/SqliteQuintStore.js +100 -0
- package/dist/storage/quint/SqliteQuintStore.js.map +1 -1
- package/dist/storage/quint/SqliteQuintStore.jsonld +20 -0
- package/dist/storage/quint/types.d.ts +16 -0
- package/dist/storage/quint/types.js.map +1 -1
- package/dist/storage/rdf/Rdf3xTripleIndex.d.ts +55 -0
- package/dist/storage/rdf/Rdf3xTripleIndex.js +1235 -0
- package/dist/storage/rdf/Rdf3xTripleIndex.js.map +1 -0
- package/dist/storage/rdf/RdfContentTypes.d.ts +9 -0
- package/dist/storage/rdf/RdfContentTypes.js +79 -0
- package/dist/storage/rdf/RdfContentTypes.js.map +1 -0
- package/dist/storage/rdf/RdfLocalQueryEngine.d.ts +79 -0
- package/dist/storage/rdf/RdfLocalQueryEngine.js +2705 -0
- package/dist/storage/rdf/RdfLocalQueryEngine.js.map +1 -0
- package/dist/storage/rdf/RdfQuadIndex.d.ts +98 -0
- package/dist/storage/rdf/RdfQuadIndex.js +1840 -0
- package/dist/storage/rdf/RdfQuadIndex.js.map +1 -0
- package/dist/storage/rdf/RdfQuadIndex.jsonld +416 -0
- package/dist/storage/rdf/RdfShadowComparator.d.ts +12 -0
- package/dist/storage/rdf/RdfShadowComparator.js +47 -0
- package/dist/storage/rdf/RdfShadowComparator.js.map +1 -0
- package/dist/storage/rdf/RdfSparqlAdapter.d.ts +147 -0
- package/dist/storage/rdf/RdfSparqlAdapter.js +2420 -0
- package/dist/storage/rdf/RdfSparqlAdapter.js.map +1 -0
- package/dist/storage/rdf/RdfSparqlAdapter.jsonld +414 -0
- package/dist/storage/rdf/RdfTermDictionary.d.ts +27 -0
- package/dist/storage/rdf/RdfTermDictionary.js +352 -0
- package/dist/storage/rdf/RdfTermDictionary.js.map +1 -0
- package/dist/storage/rdf/RdfTermDictionary.jsonld +114 -0
- package/dist/storage/rdf/RdfTermSemantics.d.ts +6 -0
- package/dist/storage/rdf/RdfTermSemantics.js +40 -0
- package/dist/storage/rdf/RdfTermSemantics.js.map +1 -0
- package/dist/storage/rdf/RdfTextIndex.d.ts +23 -0
- package/dist/storage/rdf/RdfTextIndex.js +569 -0
- package/dist/storage/rdf/RdfTextIndex.js.map +1 -0
- package/dist/storage/rdf/RdfVectorIndex.d.ts +22 -0
- package/dist/storage/rdf/RdfVectorIndex.js +631 -0
- package/dist/storage/rdf/RdfVectorIndex.js.map +1 -0
- package/dist/storage/rdf/RdfXmlSerializer.d.ts +2 -0
- package/dist/storage/rdf/RdfXmlSerializer.js +123 -0
- package/dist/storage/rdf/RdfXmlSerializer.js.map +1 -0
- package/dist/storage/rdf/ShadowRdfQuintStore.d.ts +58 -0
- package/dist/storage/rdf/ShadowRdfQuintStore.js +202 -0
- package/dist/storage/rdf/ShadowRdfQuintStore.js.map +1 -0
- package/dist/storage/rdf/ShadowRdfQuintStore.jsonld +308 -0
- package/dist/storage/rdf/SolidRdfEngine.d.ts +56 -0
- package/dist/storage/rdf/SolidRdfEngine.js +292 -0
- package/dist/storage/rdf/SolidRdfEngine.js.map +1 -0
- package/dist/storage/rdf/SolidRdfEngine.jsonld +372 -0
- package/dist/storage/rdf/SolidRdfSparqlEngine.d.ts +92 -0
- package/dist/storage/rdf/SolidRdfSparqlEngine.js +477 -0
- package/dist/storage/rdf/SolidRdfSparqlEngine.js.map +1 -0
- package/dist/storage/rdf/SolidRdfSparqlEngine.jsonld +257 -0
- package/dist/storage/rdf/index.d.ts +15 -0
- package/dist/storage/rdf/index.js +61 -0
- package/dist/storage/rdf/index.js.map +1 -0
- package/dist/storage/rdf/models-benchmark.d.ts +260 -0
- package/dist/storage/rdf/models-benchmark.js +1405 -0
- package/dist/storage/rdf/models-benchmark.js.map +1 -0
- package/dist/storage/rdf/types.d.ts +726 -0
- package/dist/storage/rdf/types.js +3 -0
- package/dist/storage/rdf/types.js.map +1 -0
- package/dist/storage/rdf/types.jsonld +316 -0
- package/dist/storage/vector/VectorIndexingListener.d.ts +5 -5
- package/dist/storage/vector/VectorIndexingListener.js +19 -19
- package/dist/storage/vector/VectorIndexingListener.js.map +1 -1
- package/package.json +3 -2
- package/templates/pod/acp/.acr.hbs +39 -0
- package/templates/pod/acp/README.acr +18 -0
- package/templates/pod/acp/profile/card.acr +22 -0
- package/templates/pod/base/README$.md.hbs +27 -0
- package/templates/pod/base/profile/card$.ttl.hbs +13 -0
- package/templates/pod/wac/.acl.hbs +26 -0
- package/templates/pod/wac/README.acl.hbs +14 -0
- package/templates/pod/wac/profile/card.acl.hbs +19 -0
- package/dist/api/handlers/WebIdProfileHandler.d.ts +0 -16
- package/dist/api/handlers/WebIdProfileHandler.js +0 -423
- package/dist/api/handlers/WebIdProfileHandler.js.map +0 -1
- package/dist/identity/drizzle/WebIdProfileRepository.d.ts +0 -63
- package/dist/identity/drizzle/WebIdProfileRepository.js +0 -168
- package/dist/identity/drizzle/WebIdProfileRepository.js.map +0 -1
- package/dist/identity/drizzle/WebIdProfileRepository.jsonld +0 -112
- package/dist/storage/quint/BaseQuintStore.jsonld +0 -257
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Root ACR for the agent account
|
|
2
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
3
|
+
@prefix acp: <http://www.w3.org/ns/solid/acp#>.
|
|
4
|
+
|
|
5
|
+
# The owner has full access to every resource in their pod.
|
|
6
|
+
# Other agents have no access rights,
|
|
7
|
+
# unless specifically authorized in other ACRs.
|
|
8
|
+
<#root>
|
|
9
|
+
a acp:AccessControlResource;
|
|
10
|
+
# Set the access to the root storage folder itself
|
|
11
|
+
acp:resource <./>;
|
|
12
|
+
# The homepage is readable by the public
|
|
13
|
+
acp:accessControl <#fullOwnerAccess>, <#publicReadAccess>;
|
|
14
|
+
# All resources will inherit this authorization
|
|
15
|
+
acp:memberAccessControl <#fullOwnerAccess>.
|
|
16
|
+
|
|
17
|
+
# The public only has read access
|
|
18
|
+
<#publicReadAccess>
|
|
19
|
+
a acp:AccessControl;
|
|
20
|
+
acp:apply [
|
|
21
|
+
a acp:Policy;
|
|
22
|
+
acp:allow acl:Read;
|
|
23
|
+
acp:anyOf [
|
|
24
|
+
a acp:Matcher;
|
|
25
|
+
acp:agent acp:PublicAgent
|
|
26
|
+
]
|
|
27
|
+
].
|
|
28
|
+
|
|
29
|
+
# The owner has all of the access modes allowed
|
|
30
|
+
<#fullOwnerAccess>
|
|
31
|
+
a acp:AccessControl;
|
|
32
|
+
acp:apply [
|
|
33
|
+
a acp:Policy;
|
|
34
|
+
acp:allow acl:Read, acl:Write, acl:Control;
|
|
35
|
+
acp:anyOf [
|
|
36
|
+
a acp:Matcher;
|
|
37
|
+
acp:agent <{{webId}}>
|
|
38
|
+
]
|
|
39
|
+
].
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
2
|
+
@prefix acp: <http://www.w3.org/ns/solid/acp#>.
|
|
3
|
+
|
|
4
|
+
<#card>
|
|
5
|
+
a acp:AccessControlResource;
|
|
6
|
+
acp:resource <./README>;
|
|
7
|
+
acp:accessControl <#publicReadAccess>.
|
|
8
|
+
|
|
9
|
+
<#publicReadAccess>
|
|
10
|
+
a acp:AccessControl;
|
|
11
|
+
acp:apply [
|
|
12
|
+
a acp:Policy;
|
|
13
|
+
acp:allow acl:Read;
|
|
14
|
+
acp:anyOf [
|
|
15
|
+
a acp:Matcher;
|
|
16
|
+
acp:agent acp:PublicAgent
|
|
17
|
+
]
|
|
18
|
+
].
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# ACR for the WebID profile document
|
|
2
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
3
|
+
@prefix acp: <http://www.w3.org/ns/solid/acp#>.
|
|
4
|
+
|
|
5
|
+
# The WebID profile is readable by the public.
|
|
6
|
+
# This is required for discovery and verification,
|
|
7
|
+
# e.g. when checking identity providers.
|
|
8
|
+
<#card>
|
|
9
|
+
a acp:AccessControlResource;
|
|
10
|
+
acp:resource <./card>;
|
|
11
|
+
acp:accessControl <#publicReadAccess>.
|
|
12
|
+
|
|
13
|
+
<#publicReadAccess>
|
|
14
|
+
a acp:AccessControl;
|
|
15
|
+
acp:apply [
|
|
16
|
+
a acp:Policy;
|
|
17
|
+
acp:allow acl:Read;
|
|
18
|
+
acp:anyOf [
|
|
19
|
+
a acp:Matcher;
|
|
20
|
+
acp:agent acp:PublicAgent
|
|
21
|
+
]
|
|
22
|
+
].
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Welcome to your pod
|
|
2
|
+
|
|
3
|
+
## A place to store your data
|
|
4
|
+
Your pod is a **secure storage space** for your documents and data.
|
|
5
|
+
<br>
|
|
6
|
+
You can choose to share those with other people and apps.
|
|
7
|
+
|
|
8
|
+
As the owner of this pod,
|
|
9
|
+
identified by <a href="{{webId}}">{{webId}}</a>,
|
|
10
|
+
you have access to all of your documents.
|
|
11
|
+
|
|
12
|
+
## Working with your pod
|
|
13
|
+
The easiest way to interact with pods
|
|
14
|
+
is through Solid apps.
|
|
15
|
+
<br>
|
|
16
|
+
For example,
|
|
17
|
+
you can open your pod in [Databrowser](https://solidos.github.io/mashlib/dist/browse.html?uri={{base.path}}).
|
|
18
|
+
|
|
19
|
+
## Accessing your account
|
|
20
|
+
To keep track of your pods, webIDs and any other resources,
|
|
21
|
+
you can [log in]({{oidcIssuer}}.account/) to your account.
|
|
22
|
+
There you can, for example, update the owners of this pod.
|
|
23
|
+
|
|
24
|
+
## Learn more
|
|
25
|
+
The [Solid website](https://solidproject.org/)
|
|
26
|
+
and the people on its [forum](https://forum.solidproject.org/)
|
|
27
|
+
will be glad to help you on your journey.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
|
2
|
+
@prefix solid: <http://www.w3.org/ns/solid/terms#>.
|
|
3
|
+
|
|
4
|
+
<>
|
|
5
|
+
a foaf:PersonalProfileDocument;
|
|
6
|
+
foaf:maker <{{webId}}>;
|
|
7
|
+
foaf:primaryTopic <{{webId}}>.
|
|
8
|
+
|
|
9
|
+
<{{webId}}>
|
|
10
|
+
{{#if name}}foaf:name "{{name}}";{{/if}}
|
|
11
|
+
{{#if oidcIssuer}}solid:oidcIssuer <{{oidcIssuer}}>;{{/if}}
|
|
12
|
+
{{#if storage}}solid:storage <{{storage}}>;{{/if}}
|
|
13
|
+
a foaf:Person.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Root ACL resource for the agent account
|
|
2
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
3
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
|
4
|
+
|
|
5
|
+
# The homepage is readable by the public
|
|
6
|
+
<#public>
|
|
7
|
+
a acl:Authorization;
|
|
8
|
+
acl:agentClass foaf:Agent;
|
|
9
|
+
acl:accessTo <./>;
|
|
10
|
+
acl:mode acl:Read.
|
|
11
|
+
|
|
12
|
+
# The owner has full access to every resource in their pod.
|
|
13
|
+
# Other agents have no access rights,
|
|
14
|
+
# unless specifically authorized in other .acl resources.
|
|
15
|
+
<#owner>
|
|
16
|
+
a acl:Authorization;
|
|
17
|
+
acl:agent <{{webId}}>;
|
|
18
|
+
# Optional owner email, to be used for account recovery:
|
|
19
|
+
{{#if email}}acl:agent <mailto:{{{email}}}>;{{/if}}
|
|
20
|
+
# Set the access to the root storage folder itself
|
|
21
|
+
acl:accessTo <./>;
|
|
22
|
+
# All resources will inherit this authorization, by default
|
|
23
|
+
acl:default <./>;
|
|
24
|
+
# The owner has all of the access modes allowed
|
|
25
|
+
acl:mode
|
|
26
|
+
acl:Read, acl:Write, acl:Control.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
2
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
|
3
|
+
|
|
4
|
+
<#public>
|
|
5
|
+
a acl:Authorization;
|
|
6
|
+
acl:accessTo <./README>;
|
|
7
|
+
acl:agentClass foaf:Agent;
|
|
8
|
+
acl:mode acl:Read.
|
|
9
|
+
|
|
10
|
+
<#owner>
|
|
11
|
+
a acl:Authorization;
|
|
12
|
+
acl:accessTo <./README>;
|
|
13
|
+
acl:agent <{{webId}}>;
|
|
14
|
+
acl:mode acl:Read, acl:Write, acl:Control.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# ACL resource for the WebID profile document
|
|
2
|
+
@prefix acl: <http://www.w3.org/ns/auth/acl#>.
|
|
3
|
+
@prefix foaf: <http://xmlns.com/foaf/0.1/>.
|
|
4
|
+
|
|
5
|
+
# The WebID profile is readable by the public.
|
|
6
|
+
# This is required for discovery and verification,
|
|
7
|
+
# e.g. when checking identity providers.
|
|
8
|
+
<#public>
|
|
9
|
+
a acl:Authorization;
|
|
10
|
+
acl:agentClass foaf:Agent;
|
|
11
|
+
acl:accessTo <./card>;
|
|
12
|
+
acl:mode acl:Read.
|
|
13
|
+
|
|
14
|
+
# The owner has full access to the profile
|
|
15
|
+
<#owner>
|
|
16
|
+
a acl:Authorization;
|
|
17
|
+
acl:agent <{{webId}}>;
|
|
18
|
+
acl:accessTo <./card>;
|
|
19
|
+
acl:mode acl:Read, acl:Write, acl:Control.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WebID Profile API Handler
|
|
3
|
-
*
|
|
4
|
-
* 提供 WebID Profile 托管服务的 HTTP API
|
|
5
|
-
*
|
|
6
|
-
* GET /{username}/profile/card - 获取 WebID Profile (Turtle 格式)
|
|
7
|
-
* POST /api/v1/identity/{username}/storage - 更新 storage 指针 (需认证)
|
|
8
|
-
*/
|
|
9
|
-
import type { ApiServer } from '../ApiServer';
|
|
10
|
-
import type { WebIdProfileRepository } from '../../identity/drizzle/WebIdProfileRepository';
|
|
11
|
-
import type { PodLookupRepository } from '../../identity/drizzle/PodLookupRepository';
|
|
12
|
-
export interface WebIdProfileHandlerOptions {
|
|
13
|
-
profileRepo: WebIdProfileRepository;
|
|
14
|
-
podLookupRepo?: PodLookupRepository;
|
|
15
|
-
}
|
|
16
|
-
export declare function registerWebIdProfileRoutes(server: ApiServer, options: WebIdProfileHandlerOptions): void;
|
|
@@ -1,423 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* WebID Profile API Handler
|
|
4
|
-
*
|
|
5
|
-
* 提供 WebID Profile 托管服务的 HTTP API
|
|
6
|
-
*
|
|
7
|
-
* GET /{username}/profile/card - 获取 WebID Profile (Turtle 格式)
|
|
8
|
-
* POST /api/v1/identity/{username}/storage - 更新 storage 指针 (需认证)
|
|
9
|
-
*/
|
|
10
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.registerWebIdProfileRoutes = registerWebIdProfileRoutes;
|
|
12
|
-
const global_logger_factory_1 = require("global-logger-factory");
|
|
13
|
-
const logger = (0, global_logger_factory_1.getLoggerFor)('WebIdProfileHandler');
|
|
14
|
-
function registerWebIdProfileRoutes(server, options) {
|
|
15
|
-
const { profileRepo } = options;
|
|
16
|
-
/**
|
|
17
|
-
* GET /{username}/profile/card
|
|
18
|
-
*
|
|
19
|
-
* 获取 WebID Profile (Turtle 格式)
|
|
20
|
-
* 这是 Solid 标准的 WebID 端点
|
|
21
|
-
*/
|
|
22
|
-
server.get('/:username/profile/card', async (request, response, params) => {
|
|
23
|
-
const username = decodeURIComponent(params.username);
|
|
24
|
-
try {
|
|
25
|
-
const profile = await resolveIdentityLookup(username, options, request);
|
|
26
|
-
if (!profile) {
|
|
27
|
-
sendError(response, 404, 'Profile not found');
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
// 返回 Turtle 格式
|
|
31
|
-
const turtle = profileRepo.generateProfileTurtle(profile);
|
|
32
|
-
response.statusCode = 200;
|
|
33
|
-
response.setHeader('Content-Type', 'text/turtle');
|
|
34
|
-
response.setHeader('Link', `<${profile.webidUrl}>; rel="describedby"`);
|
|
35
|
-
response.end(turtle);
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
logger.error(`Failed to get profile for ${username}: ${error}`);
|
|
39
|
-
sendError(response, 500, 'Internal server error');
|
|
40
|
-
}
|
|
41
|
-
}, { public: true });
|
|
42
|
-
/**
|
|
43
|
-
* POST /api/v1/identity/{username}/storage
|
|
44
|
-
*
|
|
45
|
-
* 更新 storage 指针
|
|
46
|
-
* 用于 Local 节点更新其 storage URL
|
|
47
|
-
*
|
|
48
|
-
* Request body:
|
|
49
|
-
* {
|
|
50
|
-
* "storageUrl": "https://alice.undefineds.xyz/"
|
|
51
|
-
* }
|
|
52
|
-
*/
|
|
53
|
-
server.post('/api/v1/identity/:username/storage', async (request, response, params) => {
|
|
54
|
-
const username = decodeURIComponent(params.username);
|
|
55
|
-
try {
|
|
56
|
-
const body = await readJsonBody(request);
|
|
57
|
-
const payload = body;
|
|
58
|
-
if (!payload?.storageUrl) {
|
|
59
|
-
sendError(response, 400, 'storageUrl is required');
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
// 验证 URL 格式
|
|
63
|
-
try {
|
|
64
|
-
new URL(payload.storageUrl);
|
|
65
|
-
}
|
|
66
|
-
catch {
|
|
67
|
-
sendError(response, 400, 'Invalid storageUrl format');
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
const profile = await profileRepo.updateStorage(username, {
|
|
71
|
-
storageUrl: payload.storageUrl,
|
|
72
|
-
storageMode: payload.storageMode,
|
|
73
|
-
});
|
|
74
|
-
if (!profile) {
|
|
75
|
-
sendError(response, 404, 'Profile not found');
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
logger.info(`Updated storage for ${username}: ${payload.storageUrl}`);
|
|
79
|
-
sendJson(response, 200, {
|
|
80
|
-
success: true,
|
|
81
|
-
username,
|
|
82
|
-
storageUrl: profile.storageUrl,
|
|
83
|
-
storageMode: profile.storageMode,
|
|
84
|
-
updatedAt: profile.updatedAt.toISOString(),
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
catch (error) {
|
|
88
|
-
logger.error(`Failed to update storage for ${username}: ${error}`);
|
|
89
|
-
sendError(response, 500, 'Internal server error');
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
/**
|
|
93
|
-
* GET /api/v1/identity/{username}
|
|
94
|
-
*
|
|
95
|
-
* 获取 WebID Profile 信息 (JSON 格式)
|
|
96
|
-
*/
|
|
97
|
-
server.get('/api/v1/identity/:username', async (request, response, params) => {
|
|
98
|
-
const username = decodeURIComponent(params.username);
|
|
99
|
-
try {
|
|
100
|
-
const profile = await resolveIdentityLookup(username, options, request);
|
|
101
|
-
if (!profile) {
|
|
102
|
-
sendError(response, 404, 'Profile not found');
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const body = {
|
|
106
|
-
username: profile.username,
|
|
107
|
-
webidUrl: profile.webidUrl,
|
|
108
|
-
storageUrl: profile.storageUrl,
|
|
109
|
-
storageMode: profile.storageMode,
|
|
110
|
-
oidcIssuer: profile.oidcIssuer,
|
|
111
|
-
};
|
|
112
|
-
if (profile.createdAt) {
|
|
113
|
-
body.createdAt = profile.createdAt.toISOString();
|
|
114
|
-
}
|
|
115
|
-
if (profile.updatedAt) {
|
|
116
|
-
body.updatedAt = profile.updatedAt.toISOString();
|
|
117
|
-
}
|
|
118
|
-
sendJson(response, 200, body);
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
logger.error(`Failed to get profile for ${username}: ${error}`);
|
|
122
|
-
sendError(response, 500, 'Internal server error');
|
|
123
|
-
}
|
|
124
|
-
}, { public: true });
|
|
125
|
-
/**
|
|
126
|
-
* POST /api/v1/identity
|
|
127
|
-
*
|
|
128
|
-
* 创建 WebID Profile
|
|
129
|
-
*
|
|
130
|
-
* Request body:
|
|
131
|
-
* {
|
|
132
|
-
* "username": "alice",
|
|
133
|
-
* "storageMode": "local", // optional, default: "cloud"
|
|
134
|
-
* "storageUrl": "https://alice.undefineds.xyz/" // optional
|
|
135
|
-
* }
|
|
136
|
-
*/
|
|
137
|
-
server.post('/api/v1/identity', async (request, response, _params) => {
|
|
138
|
-
try {
|
|
139
|
-
const body = await readJsonBody(request);
|
|
140
|
-
const payload = body;
|
|
141
|
-
if (!payload?.username) {
|
|
142
|
-
sendError(response, 400, 'username is required');
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
// 验证用户名格式
|
|
146
|
-
if (!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(payload.username)) {
|
|
147
|
-
sendError(response, 400, 'Invalid username format');
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// 检查是否已存在
|
|
151
|
-
const existing = await profileRepo.get(payload.username);
|
|
152
|
-
if (existing) {
|
|
153
|
-
sendError(response, 409, 'Username already taken');
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
const profile = await profileRepo.create({
|
|
157
|
-
username: payload.username,
|
|
158
|
-
storageMode: payload.storageMode,
|
|
159
|
-
storageUrl: payload.storageUrl,
|
|
160
|
-
accountId: payload.accountId,
|
|
161
|
-
});
|
|
162
|
-
logger.info(`Created profile for ${payload.username}`);
|
|
163
|
-
sendJson(response, 201, {
|
|
164
|
-
success: true,
|
|
165
|
-
username: profile.username,
|
|
166
|
-
webidUrl: profile.webidUrl,
|
|
167
|
-
storageUrl: profile.storageUrl,
|
|
168
|
-
storageMode: profile.storageMode,
|
|
169
|
-
createdAt: profile.createdAt.toISOString(),
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
catch (error) {
|
|
173
|
-
logger.error(`Failed to create profile: ${error}`);
|
|
174
|
-
sendError(response, 500, 'Internal server error');
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
logger.info('WebID Profile routes registered');
|
|
178
|
-
}
|
|
179
|
-
async function resolveIdentityLookup(username, options, request) {
|
|
180
|
-
try {
|
|
181
|
-
const profile = await resolveProfileWithStorageBackfill(username, options);
|
|
182
|
-
if (profile) {
|
|
183
|
-
return profile;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
logger.warn(`Profile lookup unavailable for ${username}, falling back to Pod index: ${error}`);
|
|
188
|
-
}
|
|
189
|
-
return resolveProfileFromPods(username, options, request);
|
|
190
|
-
}
|
|
191
|
-
async function resolveProfileFromPods(username, options, request) {
|
|
192
|
-
const { podLookupRepo } = options;
|
|
193
|
-
const identityBaseUrl = getHostedIdentityBaseUrl(request);
|
|
194
|
-
if (podLookupRepo) {
|
|
195
|
-
const webidUrl = buildHostedWebIdUrl(username, identityBaseUrl);
|
|
196
|
-
const webIdMatch = await tryFindPodByWebId(podLookupRepo, webidUrl, username);
|
|
197
|
-
if (webIdMatch) {
|
|
198
|
-
return profileFromPod(username, webidUrl, webIdMatch);
|
|
199
|
-
}
|
|
200
|
-
const match = await tryFindPodByStorageSlug(podLookupRepo, username);
|
|
201
|
-
if (match) {
|
|
202
|
-
return profileFromPod(username, buildStorageWebIdUrl(match.baseUrl), match);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
const hostedStorageUrl = new URL(`${encodeURIComponent(username)}/`, identityBaseUrl).toString();
|
|
206
|
-
if (await probeHostedStorageRoot(hostedStorageUrl, username)) {
|
|
207
|
-
return {
|
|
208
|
-
username,
|
|
209
|
-
webidUrl: buildHostedWebIdUrl(username, identityBaseUrl),
|
|
210
|
-
storageUrl: hostedStorageUrl,
|
|
211
|
-
storageMode: 'cloud',
|
|
212
|
-
oidcIssuer: deriveOrigin(identityBaseUrl),
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
return null;
|
|
216
|
-
}
|
|
217
|
-
async function resolveProfileWithStorageBackfill(username, options) {
|
|
218
|
-
const { profileRepo, podLookupRepo } = options;
|
|
219
|
-
const profile = await profileRepo.get(username);
|
|
220
|
-
if (!profile) {
|
|
221
|
-
return null;
|
|
222
|
-
}
|
|
223
|
-
if (profile.storageUrl || !profile.accountId || !podLookupRepo) {
|
|
224
|
-
return profile;
|
|
225
|
-
}
|
|
226
|
-
let pods;
|
|
227
|
-
try {
|
|
228
|
-
pods = await podLookupRepo.listByAccountId(profile.accountId);
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
logger.warn(`Skipped storage backfill for ${username}: pod index unavailable for account ${profile.accountId}: ${error}`);
|
|
232
|
-
return profile;
|
|
233
|
-
}
|
|
234
|
-
const storageUrl = selectStorageBackfillCandidate(username, pods);
|
|
235
|
-
if (!storageUrl) {
|
|
236
|
-
logger.warn(`Skipped storage backfill for ${username}: no unambiguous pod found for account ${profile.accountId}`);
|
|
237
|
-
return profile;
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
const updated = await profileRepo.updateStorage(username, {
|
|
241
|
-
storageUrl,
|
|
242
|
-
storageMode: profile.storageMode,
|
|
243
|
-
});
|
|
244
|
-
if (updated) {
|
|
245
|
-
logger.info(`Backfilled storage for ${username}: ${storageUrl}`);
|
|
246
|
-
return updated;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
catch (error) {
|
|
250
|
-
logger.warn(`Failed to backfill storage for ${username}: ${error}`);
|
|
251
|
-
}
|
|
252
|
-
return profile;
|
|
253
|
-
}
|
|
254
|
-
function selectStorageBackfillCandidate(username, pods) {
|
|
255
|
-
if (pods.length === 0) {
|
|
256
|
-
return null;
|
|
257
|
-
}
|
|
258
|
-
const exactMatches = pods.filter((pod) => derivePodSlug(pod.baseUrl) === username);
|
|
259
|
-
if (exactMatches.length === 1) {
|
|
260
|
-
return ensureTrailingSlash(exactMatches[0].baseUrl);
|
|
261
|
-
}
|
|
262
|
-
if (exactMatches.length > 1) {
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
if (pods.length === 1) {
|
|
266
|
-
return ensureTrailingSlash(pods[0].baseUrl);
|
|
267
|
-
}
|
|
268
|
-
return null;
|
|
269
|
-
}
|
|
270
|
-
function derivePodSlug(baseUrl) {
|
|
271
|
-
try {
|
|
272
|
-
const parsed = new URL(baseUrl);
|
|
273
|
-
const [slug] = parsed.pathname.split('/').filter(Boolean);
|
|
274
|
-
return slug || null;
|
|
275
|
-
}
|
|
276
|
-
catch {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
async function tryFindPodByWebId(podLookupRepo, webidUrl, username) {
|
|
281
|
-
try {
|
|
282
|
-
if (typeof podLookupRepo.findByWebId === 'function') {
|
|
283
|
-
return await podLookupRepo.findByWebId(webidUrl);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
catch (error) {
|
|
287
|
-
logger.warn(`WebID index lookup unavailable for ${username}: ${error}`);
|
|
288
|
-
}
|
|
289
|
-
return undefined;
|
|
290
|
-
}
|
|
291
|
-
async function tryFindPodByStorageSlug(podLookupRepo, username) {
|
|
292
|
-
try {
|
|
293
|
-
const pods = await podLookupRepo.listAllPods();
|
|
294
|
-
return pods.find((pod) => derivePodSlug(pod.baseUrl) === username);
|
|
295
|
-
}
|
|
296
|
-
catch (error) {
|
|
297
|
-
logger.warn(`Pod index lookup unavailable for ${username}: ${error}`);
|
|
298
|
-
return undefined;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function profileFromPod(username, webidUrl, pod) {
|
|
302
|
-
const storageUrl = ensureTrailingSlash(pod.baseUrl);
|
|
303
|
-
return {
|
|
304
|
-
username,
|
|
305
|
-
webidUrl,
|
|
306
|
-
storageUrl,
|
|
307
|
-
storageMode: 'cloud',
|
|
308
|
-
oidcIssuer: deriveOrigin(webidUrl),
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
function buildHostedWebIdUrl(username, identityBaseUrl = getHostedIdentityBaseUrl()) {
|
|
312
|
-
return new URL(`${encodeURIComponent(username)}/profile/card#me`, identityBaseUrl).toString();
|
|
313
|
-
}
|
|
314
|
-
function buildStorageWebIdUrl(storageUrl) {
|
|
315
|
-
return new URL('profile/card#me', ensureTrailingSlash(storageUrl)).toString();
|
|
316
|
-
}
|
|
317
|
-
function getHostedIdentityBaseUrl(request) {
|
|
318
|
-
return ensureTrailingSlash(requestOrigin(request) ??
|
|
319
|
-
absoluteHttpUrl(process.env.CSS_BASE_URL) ??
|
|
320
|
-
absoluteHttpUrl(process.env.BASE_URL) ??
|
|
321
|
-
'http://localhost:3000/');
|
|
322
|
-
}
|
|
323
|
-
function absoluteHttpUrl(value) {
|
|
324
|
-
if (!value) {
|
|
325
|
-
return undefined;
|
|
326
|
-
}
|
|
327
|
-
try {
|
|
328
|
-
const url = new URL(value);
|
|
329
|
-
return url.protocol === 'http:' || url.protocol === 'https:' ? url.toString() : undefined;
|
|
330
|
-
}
|
|
331
|
-
catch {
|
|
332
|
-
return undefined;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
function requestOrigin(request) {
|
|
336
|
-
if (!request?.headers) {
|
|
337
|
-
return undefined;
|
|
338
|
-
}
|
|
339
|
-
const host = firstHeader(request.headers['x-forwarded-host']) ?? firstHeader(request.headers.host);
|
|
340
|
-
if (!host) {
|
|
341
|
-
return undefined;
|
|
342
|
-
}
|
|
343
|
-
const proto = firstHeader(request.headers['x-forwarded-proto']) ?? 'https';
|
|
344
|
-
return absoluteHttpUrl(`${proto}://${host}`);
|
|
345
|
-
}
|
|
346
|
-
function firstHeader(value) {
|
|
347
|
-
if (Array.isArray(value)) {
|
|
348
|
-
return value[0];
|
|
349
|
-
}
|
|
350
|
-
return value;
|
|
351
|
-
}
|
|
352
|
-
async function probeHostedStorageRoot(storageUrl, username) {
|
|
353
|
-
const controller = new AbortController();
|
|
354
|
-
const timer = setTimeout(() => controller.abort(), 2_000);
|
|
355
|
-
try {
|
|
356
|
-
const response = await fetch(storageUrl, {
|
|
357
|
-
method: 'HEAD',
|
|
358
|
-
signal: controller.signal,
|
|
359
|
-
});
|
|
360
|
-
if (isHostedStorageRootResponse(response)) {
|
|
361
|
-
logger.info(`Resolved hosted WebID profile for ${username} from existing storage root: ${storageUrl}`);
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
return false;
|
|
365
|
-
}
|
|
366
|
-
catch (error) {
|
|
367
|
-
logger.warn(`Hosted storage root probe unavailable for ${username}: ${error}`);
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
finally {
|
|
371
|
-
clearTimeout(timer);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
function isHostedStorageRootResponse(response) {
|
|
375
|
-
if (response.status < 200 || response.status >= 400) {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
const link = response.headers.get('link') ?? '';
|
|
379
|
-
return /<http:\/\/www\.w3\.org\/ns\/pim\/space#Storage>;\s*rel="?type"?/iu.test(link) ||
|
|
380
|
-
/<http:\/\/www\.w3\.org\/ns\/ldp#(?:Basic)?Container>;\s*rel="?type"?/iu.test(link);
|
|
381
|
-
}
|
|
382
|
-
function ensureTrailingSlash(url) {
|
|
383
|
-
return url.replace(/\/+$/, '') + '/';
|
|
384
|
-
}
|
|
385
|
-
function deriveOrigin(url) {
|
|
386
|
-
try {
|
|
387
|
-
return ensureTrailingSlash(new URL(url).origin);
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
return undefined;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
async function readJsonBody(request) {
|
|
394
|
-
return new Promise((resolve, reject) => {
|
|
395
|
-
let data = '';
|
|
396
|
-
request.setEncoding('utf8');
|
|
397
|
-
request.on('data', (chunk) => {
|
|
398
|
-
data += chunk;
|
|
399
|
-
});
|
|
400
|
-
request.on('end', () => {
|
|
401
|
-
if (!data) {
|
|
402
|
-
resolve(undefined);
|
|
403
|
-
return;
|
|
404
|
-
}
|
|
405
|
-
try {
|
|
406
|
-
resolve(JSON.parse(data));
|
|
407
|
-
}
|
|
408
|
-
catch {
|
|
409
|
-
resolve(undefined);
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
request.on('error', reject);
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
function sendJson(response, status, data) {
|
|
416
|
-
response.statusCode = status;
|
|
417
|
-
response.setHeader('Content-Type', 'application/json');
|
|
418
|
-
response.end(JSON.stringify(data));
|
|
419
|
-
}
|
|
420
|
-
function sendError(response, status, message) {
|
|
421
|
-
sendJson(response, status, { error: message });
|
|
422
|
-
}
|
|
423
|
-
//# sourceMappingURL=WebIdProfileHandler.js.map
|