@noeldemartin/solid-utils 0.2.0 → 0.3.0-next.a444b642b5ee2c1d412a667cb87b853b85115b98
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/CHANGELOG.md +35 -0
- package/dist/noeldemartin-solid-utils.cjs.js +1 -1
- package/dist/noeldemartin-solid-utils.cjs.js.map +1 -1
- package/dist/noeldemartin-solid-utils.d.ts +61 -2
- package/dist/noeldemartin-solid-utils.esm.js +1 -1
- package/dist/noeldemartin-solid-utils.esm.js.map +1 -1
- package/dist/noeldemartin-solid-utils.umd.js +16 -16
- package/dist/noeldemartin-solid-utils.umd.js.map +1 -1
- package/package.json +5 -3
- package/src/helpers/auth.ts +20 -4
- package/src/main.ts +1 -0
- package/src/testing/ResponseStub.ts +46 -0
- package/src/testing/faking.ts +36 -0
- package/src/testing/index.ts +3 -0
- package/src/testing/mocking.ts +34 -0
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noeldemartin/solid-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-next.a444b642b5ee2c1d412a667cb87b853b85115b98",
|
|
4
4
|
"description": "My JavaScript utilities for Solid",
|
|
5
5
|
"main": "dist/noeldemartin-solid-utils.cjs.js",
|
|
6
6
|
"module": "dist/noeldemartin-solid-utils.esm.js",
|
|
7
7
|
"browser": "dist/noeldemartin-solid-utils.umd.js",
|
|
8
8
|
"types": "dist/noeldemartin-solid-utils.d.ts",
|
|
9
|
+
"sideEffects": false,
|
|
9
10
|
"scripts": {
|
|
10
11
|
"build": "rm dist -rf && npm run build:js && npm run build:types",
|
|
11
12
|
"build:js": "noeldemartin-build-javascript",
|
|
@@ -30,8 +31,9 @@
|
|
|
30
31
|
"homepage": "https://github.com/noeldemartin/solid-utils",
|
|
31
32
|
"dependencies": {
|
|
32
33
|
"@babel/runtime": "^7.14.0",
|
|
33
|
-
"@noeldemartin/
|
|
34
|
-
"@noeldemartin/utils": "^0.
|
|
34
|
+
"@noeldemartin/faker": "^7.6.0",
|
|
35
|
+
"@noeldemartin/solid-utils-external": "^0.1.1",
|
|
36
|
+
"@noeldemartin/utils": "^0.4.0",
|
|
35
37
|
"@types/rdf-js": "^4.0.1",
|
|
36
38
|
"core-js": "^3.12.1",
|
|
37
39
|
"jest-diff": "^26.6.2",
|
package/src/helpers/auth.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { Fetch } from './io';
|
|
|
9
9
|
|
|
10
10
|
export interface SolidUserProfile {
|
|
11
11
|
webId: string;
|
|
12
|
-
storageUrls: string[];
|
|
12
|
+
storageUrls: [string, ...string[]];
|
|
13
13
|
cloaked: boolean;
|
|
14
14
|
writableProfileUrl: string | null;
|
|
15
15
|
name?: string;
|
|
@@ -106,11 +106,15 @@ async function fetchUserProfile(webId: string, fetch?: Fetch): Promise<SolidUser
|
|
|
106
106
|
parentUrl = urlParentDirectory(parentUrl);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
if (storageUrls.length === 0) {
|
|
110
|
+
throw new Error(`Could not find any storage for ${webId}.`);
|
|
111
|
+
}
|
|
112
|
+
|
|
109
113
|
return {
|
|
110
114
|
webId,
|
|
111
115
|
cloaked,
|
|
112
116
|
writableProfileUrl,
|
|
113
|
-
storageUrls: arrayUnique(storageUrls),
|
|
117
|
+
storageUrls: arrayUnique(storageUrls) as [string, ...string[]],
|
|
114
118
|
...objectWithoutEmpty({
|
|
115
119
|
name:
|
|
116
120
|
store.statement(webId, 'vcard:fn')?.object.value ??
|
|
@@ -125,8 +129,20 @@ async function fetchUserProfile(webId: string, fetch?: Fetch): Promise<SolidUser
|
|
|
125
129
|
};
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
export
|
|
129
|
-
|
|
132
|
+
export interface FetchLoginUserProfileOptions {
|
|
133
|
+
required?: boolean;
|
|
134
|
+
fetch?: Fetch;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function fetchLoginUserProfile(
|
|
138
|
+
loginUrl: string,
|
|
139
|
+
options: FetchLoginUserProfileOptions = {},
|
|
140
|
+
): Promise<SolidUserProfile | null> {
|
|
141
|
+
if (options.required) {
|
|
142
|
+
return fetchUserProfile(loginUrl, options.fetch);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const fetchProfile = silenced(url => fetchUserProfile(url, options.fetch));
|
|
130
146
|
|
|
131
147
|
return await fetchProfile(loginUrl)
|
|
132
148
|
?? await fetchProfile(loginUrl.replace(/\/$/, '').concat('/profile/card#me'))
|
package/src/main.ts
CHANGED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export default class ResponseStub implements Response {
|
|
2
|
+
|
|
3
|
+
private rawBody: string;
|
|
4
|
+
|
|
5
|
+
public readonly body!: ReadableStream<Uint8Array> | null;
|
|
6
|
+
public readonly bodyUsed!: boolean;
|
|
7
|
+
public readonly headers: Headers;
|
|
8
|
+
public readonly ok!: boolean;
|
|
9
|
+
public readonly redirected!: boolean;
|
|
10
|
+
public readonly status: number;
|
|
11
|
+
public readonly statusText!: string;
|
|
12
|
+
public readonly trailer!: Promise<Headers>;
|
|
13
|
+
public readonly type!: ResponseType;
|
|
14
|
+
public readonly url!: string;
|
|
15
|
+
|
|
16
|
+
public constructor(rawBody: string = '', headers: Record<string, string> = {}, status: number = 200) {
|
|
17
|
+
this.rawBody = rawBody;
|
|
18
|
+
this.headers = new Headers(headers);
|
|
19
|
+
this.status = status;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public async arrayBuffer(): Promise<ArrayBuffer> {
|
|
23
|
+
throw new Error('ResponseStub.arrayBuffer is not implemented');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async blob(): Promise<Blob> {
|
|
27
|
+
throw new Error('ResponseStub.blob is not implemented');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public async formData(): Promise<FormData> {
|
|
31
|
+
throw new Error('ResponseStub.formData is not implemented');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async json(): Promise<unknown> {
|
|
35
|
+
return JSON.parse(this.rawBody);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public async text(): Promise<string> {
|
|
39
|
+
return this.rawBody;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public clone(): Response {
|
|
43
|
+
return { ...this };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { faker } from '@noeldemartin/faker';
|
|
2
|
+
import { stringToSlug } from '@noeldemartin/utils';
|
|
3
|
+
|
|
4
|
+
export interface ContainerOptions {
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface DocumentOptions extends ContainerOptions {
|
|
9
|
+
containerUrl: string;
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ResourceOptions extends DocumentOptions {
|
|
14
|
+
documentUrl: string;
|
|
15
|
+
hash: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function fakeContainerUrl(options: Partial<ContainerOptions> = {}): string {
|
|
19
|
+
const baseUrl = options.baseUrl ?? faker.internet.url();
|
|
20
|
+
|
|
21
|
+
return baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function fakeDocumentUrl(options: Partial<DocumentOptions> = {}): string {
|
|
25
|
+
const containerUrl = options.containerUrl ?? fakeContainerUrl(options);
|
|
26
|
+
const name = options.name ?? faker.random.word();
|
|
27
|
+
|
|
28
|
+
return containerUrl + stringToSlug(name);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function fakeResourceUrl(options: Partial<ResourceOptions> = {}): string {
|
|
32
|
+
const documentUrl = options.documentUrl ?? fakeDocumentUrl(options);
|
|
33
|
+
const hash = options.hash ?? 'it';
|
|
34
|
+
|
|
35
|
+
return documentUrl + '#' + hash;
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { fail } from '@noeldemartin/utils';
|
|
2
|
+
import type { GetClosureArgs, GetClosureResult } from '@noeldemartin/utils';
|
|
3
|
+
|
|
4
|
+
import type { Fetch } from '@/helpers/io';
|
|
5
|
+
|
|
6
|
+
import ResponseStub from './ResponseStub';
|
|
7
|
+
|
|
8
|
+
export interface FetchMockMethods {
|
|
9
|
+
mockResponse(body?: string, headers?: Record<string, string>, status?: number): void;
|
|
10
|
+
mockNotFoundResponse(): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type FetchMock = jest.Mock<GetClosureResult<Fetch>, GetClosureArgs<Fetch>> & Fetch & FetchMockMethods;
|
|
14
|
+
|
|
15
|
+
export function mockFetch(): FetchMock {
|
|
16
|
+
const responses: ResponseStub[] = [];
|
|
17
|
+
const methods: FetchMockMethods = {
|
|
18
|
+
mockResponse(body, headers, status) {
|
|
19
|
+
responses.push(new ResponseStub(body, headers, status));
|
|
20
|
+
},
|
|
21
|
+
mockNotFoundResponse() {
|
|
22
|
+
responses.push(new ResponseStub('', {}, 404));
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
|
+
const fetchMock = jest.fn(async (...args: GetClosureArgs<Fetch>) => {
|
|
28
|
+
return responses.shift() ?? fail<Response>('fetch mock called without response');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
Object.assign(fetchMock, methods);
|
|
32
|
+
|
|
33
|
+
return fetchMock as FetchMock;
|
|
34
|
+
}
|