You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.4 KiB
84 lines
2.4 KiB
|
5 months ago
|
import type { StandardSchemaV1 } from '$libs/standard-schema';
|
||
|
|
import { HTTP_CONTENT_TYPE_JSON, HTTP_HEADER_CONTENT_TYPE, HTTP_METHOD_POST } from '$libs/http';
|
||
|
|
import {
|
||
|
|
PERMISSION_ERROR_MSG_REQUEST_FAILED_PREFIX,
|
||
|
|
PERMISSION_ERROR_MSG_RESPONSE_NOT_JSON_PREFIX,
|
||
|
|
PERMISSION_HTTP_CREDENTIALS_INCLUDE
|
||
|
|
} from './consts.ts';
|
||
|
|
import { PermRemoteRequestError } from './errors.ts';
|
||
|
|
import type { PermissionClientOptions } from './types.ts';
|
||
|
|
|
||
|
|
const PERMISSION_JSON_PASSTHROUGH_SCHEMA: StandardSchemaV1<unknown, unknown> = {
|
||
|
|
'~standard': {
|
||
|
|
version: 1,
|
||
|
|
vendor: 'active-perm',
|
||
|
|
validate(value) {
|
||
|
|
return { value };
|
||
|
|
}
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
function joinUrl(base: string, path: string): string {
|
||
|
|
return `${base.replace(/\/$/, '')}/${path.replace(/^\//, '')}`;
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function postPermissionJson<T>(
|
||
|
|
options: PermissionClientOptions,
|
||
|
|
path: string,
|
||
|
|
body: unknown
|
||
|
|
): Promise<T> {
|
||
|
|
const url = joinUrl(options.endpoint, path);
|
||
|
|
if (options.http) {
|
||
|
|
const response = await options.http.post(url, {
|
||
|
|
body: body as Record<string, unknown>,
|
||
|
|
schema: PERMISSION_JSON_PASSTHROUGH_SCHEMA
|
||
|
|
});
|
||
|
|
if (response.ok) return response.value as T;
|
||
|
|
const status = 'status' in response ? response.status : undefined;
|
||
|
|
throw new PermRemoteRequestError(
|
||
|
|
`${PERMISSION_ERROR_MSG_REQUEST_FAILED_PREFIX}${status ?? url}`,
|
||
|
|
url,
|
||
|
|
status
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const fetcher = options.fetcher ?? fetch.bind(globalThis);
|
||
|
|
const response = await fetcher(url, {
|
||
|
|
method: HTTP_METHOD_POST,
|
||
|
|
headers: { [HTTP_HEADER_CONTENT_TYPE]: HTTP_CONTENT_TYPE_JSON },
|
||
|
|
credentials: PERMISSION_HTTP_CREDENTIALS_INCLUDE,
|
||
|
|
body: JSON.stringify(body)
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
throw new PermRemoteRequestError(
|
||
|
|
`${PERMISSION_ERROR_MSG_REQUEST_FAILED_PREFIX}${response.status} ${response.statusText}`,
|
||
|
|
url,
|
||
|
|
response.status
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return readPermissionJson<T>(response, url);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function readPermissionJson<T>(response: Response, url: string): Promise<T> {
|
||
|
|
const contentType = response.headers.get(HTTP_HEADER_CONTENT_TYPE);
|
||
|
|
if (contentType && !contentType.toLowerCase().includes(HTTP_CONTENT_TYPE_JSON)) {
|
||
|
|
throw new PermRemoteRequestError(
|
||
|
|
`${PERMISSION_ERROR_MSG_RESPONSE_NOT_JSON_PREFIX}${url}`,
|
||
|
|
url,
|
||
|
|
response.status
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
return (await response.json()) as T;
|
||
|
|
} catch (_error) {
|
||
|
|
throw new PermRemoteRequestError(
|
||
|
|
`${PERMISSION_ERROR_MSG_RESPONSE_NOT_JSON_PREFIX}${url}`,
|
||
|
|
url,
|
||
|
|
response.status
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|