@seliseblocks/client 0.1.5 → 0.2.0
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/{AI_USAGE_GUIDE.md → AGENT_GUIDE.md} +165 -165
- package/CHANGELOG.md +57 -0
- package/LICENSE +1 -1
- package/README.md +234 -222
- package/dist/auth/auth-client.d.ts +3 -3
- package/dist/client.d.ts +26 -2
- package/dist/client.js +3 -1
- package/dist/data/data-client.js +33 -33
- package/dist/http/http-client.d.ts +2 -2
- package/dist/http/http-client.js +55 -22
- package/dist/index.d.ts +7 -4
- package/dist/mfa/mfa-client.d.ts +2 -0
- package/dist/mfa/mfa-client.js +2 -0
- package/dist/mfa/types.d.ts +2 -1
- package/dist/notifier/types.d.ts +1 -1
- package/package.json +13 -2
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { BlocksAuthenticationClient } from "../auth/auth-client.js";
|
|
2
|
-
import {
|
|
2
|
+
import { BlocksResolvedConfig } from "../client.js";
|
|
3
3
|
import { BlocksExternalRequestOptions, BlocksRequestOptions } from "../types.js";
|
|
4
4
|
export declare class BlocksHttpClient {
|
|
5
5
|
private readonly config;
|
|
6
6
|
private readonly auth;
|
|
7
7
|
private readonly fetchImpl;
|
|
8
|
-
constructor(config:
|
|
8
|
+
constructor(config: BlocksResolvedConfig, auth: BlocksAuthenticationClient, fetchImpl?: typeof fetch);
|
|
9
9
|
request<T>(path: string, options?: BlocksRequestOptions): Promise<T>;
|
|
10
10
|
external<T = unknown>(url: string, options?: BlocksExternalRequestOptions): Promise<T>;
|
|
11
11
|
}
|
package/dist/http/http-client.js
CHANGED
|
@@ -12,26 +12,38 @@ export class BlocksHttpClient {
|
|
|
12
12
|
}
|
|
13
13
|
async request(path, options = {}) {
|
|
14
14
|
const url = buildUrl(this.config.apiUrl, path, options.query);
|
|
15
|
-
const headers = new Headers(options.headers);
|
|
16
15
|
const rawBody = isBodyInit(options.body) ? options.body : undefined;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
headers.set("
|
|
16
|
+
const send = async (accessTokenOverride) => {
|
|
17
|
+
const headers = new Headers(options.headers);
|
|
18
|
+
headers.set("Accept", "application/json");
|
|
19
|
+
headers.set("x-blocks-key", this.config.xBlocksKey);
|
|
20
|
+
if (options.body !== undefined && !rawBody && !headers.has("Content-Type")) {
|
|
21
|
+
headers.set("Content-Type", "application/json");
|
|
22
|
+
}
|
|
23
|
+
if (options.auth !== false) {
|
|
24
|
+
const token = accessTokenOverride ?? options.accessToken ?? await this.auth.accessToken();
|
|
25
|
+
if (token)
|
|
26
|
+
headers.set("Authorization", `Bearer ${token}`);
|
|
27
|
+
}
|
|
28
|
+
return this.fetchImpl(url, {
|
|
29
|
+
body: rawBody ?? (options.body === undefined ? undefined : JSON.stringify(options.body)),
|
|
30
|
+
// IAM's hosted IdP flow sets the session as a Secure, httpOnly cookie by default;
|
|
31
|
+
// without this the browser never sends it back on subsequent Blocks API calls.
|
|
32
|
+
credentials: "include",
|
|
33
|
+
headers,
|
|
34
|
+
method: options.method ?? (options.body === undefined ? "GET" : "POST")
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
let response = await send();
|
|
38
|
+
// A 401 on a token the caller supplied directly (options.accessToken) is the
|
|
39
|
+
// caller's problem to resolve, not ours. Otherwise, give the app one chance to
|
|
40
|
+
// recover through its own onUnauthorized hook (expected to dedupe concurrent
|
|
41
|
+
// callers behind a single refresh) and retry exactly once with what it returns.
|
|
42
|
+
if (response.status === 401 && options.auth !== false && options.accessToken === undefined && this.config.onUnauthorized) {
|
|
43
|
+
const freshToken = await this.config.onUnauthorized();
|
|
44
|
+
if (freshToken)
|
|
45
|
+
response = await send(freshToken);
|
|
21
46
|
}
|
|
22
|
-
if (options.auth !== false) {
|
|
23
|
-
const token = options.accessToken ?? await this.auth.accessToken();
|
|
24
|
-
if (token)
|
|
25
|
-
headers.set("Authorization", `Bearer ${token}`);
|
|
26
|
-
}
|
|
27
|
-
const response = await this.fetchImpl(url, {
|
|
28
|
-
body: rawBody ?? (options.body === undefined ? undefined : JSON.stringify(options.body)),
|
|
29
|
-
// IAM's hosted IdP flow sets the session as a Secure, httpOnly cookie by default;
|
|
30
|
-
// without this the browser never sends it back on subsequent Blocks API calls.
|
|
31
|
-
credentials: "include",
|
|
32
|
-
headers,
|
|
33
|
-
method: options.method ?? (options.body === undefined ? "GET" : "POST")
|
|
34
|
-
});
|
|
35
47
|
const body = await parseBody(response);
|
|
36
48
|
if (!response.ok)
|
|
37
49
|
throw new BlocksApiError(response.status, response.statusText, body);
|
|
@@ -49,6 +61,23 @@ export class BlocksHttpClient {
|
|
|
49
61
|
return body;
|
|
50
62
|
}
|
|
51
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* `request` attaches the caller's bearer token, `x-blocks-key`, and
|
|
66
|
+
* `credentials: "include"`, so it must only ever reach the configured Blocks
|
|
67
|
+
* API. An absolute URL is still accepted -- callers legitimately pass a full
|
|
68
|
+
* API URL -- but one pointing somewhere else would hand a live session to a
|
|
69
|
+
* third party, so it is refused with a pointer to `external`, which sends no
|
|
70
|
+
* Blocks credentials by design.
|
|
71
|
+
*/
|
|
72
|
+
function sameOriginOnly(path, baseUrl) {
|
|
73
|
+
const target = new URL(path);
|
|
74
|
+
const base = new URL(`${baseUrl}/`);
|
|
75
|
+
if (target.origin !== base.origin) {
|
|
76
|
+
throw new Error(`Refusing to send Blocks credentials to ${target.origin}: it is not the configured apiUrl (${base.origin}). `
|
|
77
|
+
+ "Use blocks.http.external(url) for third-party URLs such as a pre-signed storage upload.");
|
|
78
|
+
}
|
|
79
|
+
return target;
|
|
80
|
+
}
|
|
52
81
|
function isBodyInit(value) {
|
|
53
82
|
return typeof Blob !== "undefined" && value instanceof Blob
|
|
54
83
|
|| typeof FormData !== "undefined" && value instanceof FormData
|
|
@@ -59,7 +88,7 @@ function isBodyInit(value) {
|
|
|
59
88
|
}
|
|
60
89
|
function buildUrl(baseUrl, path, query) {
|
|
61
90
|
const url = /^https?:\/\//i.test(path)
|
|
62
|
-
?
|
|
91
|
+
? sameOriginOnly(path, baseUrl)
|
|
63
92
|
: new URL(path.replace(/^\/+/, ""), `${baseUrl}/`);
|
|
64
93
|
for (const [key, value] of Object.entries(query ?? {})) {
|
|
65
94
|
if (value !== undefined)
|
|
@@ -73,9 +102,13 @@ async function parseBody(response) {
|
|
|
73
102
|
const text = await response.text();
|
|
74
103
|
if (!text)
|
|
75
104
|
return undefined;
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
105
|
+
// Parsing is best-effort for every content type, including a declared
|
|
106
|
+
// application/json. A proxy, WAF, or load balancer in front of the API can
|
|
107
|
+
// answer with an HTML error page while still claiming JSON; throwing a raw
|
|
108
|
+
// SyntaxError there would lose the HTTP status entirely and break the
|
|
109
|
+
// documented contract that a non-2xx response always surfaces as a
|
|
110
|
+
// BlocksApiError. Returning the raw text keeps the status and hands the
|
|
111
|
+
// caller the body it actually got.
|
|
79
112
|
try {
|
|
80
113
|
return JSON.parse(text);
|
|
81
114
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
export { createBlocksClient } from "./client.js";
|
|
2
2
|
export { BlocksAuthenticationClient } from "./auth/auth-client.js";
|
|
3
3
|
export { BlocksDataClient } from "./data/data-client.js";
|
|
4
|
-
export type { BlocksClient, BlocksClientConfig, BlocksOidcConfig
|
|
4
|
+
export type { BlocksClient, BlocksClientConfig, BlocksOidcConfig, BlocksPublicConfig, BlocksResolvedConfig,
|
|
5
|
+
/** @deprecated Renamed to `BlocksResolvedConfig`. */
|
|
6
|
+
RequiredConfig } from "./client.js";
|
|
5
7
|
export { BlocksApiError } from "./http/errors.js";
|
|
8
|
+
export type { BlocksHttpClient } from "./http/http-client.js";
|
|
6
9
|
export { BlocksIAMClient } from "./iam/iam-client.js";
|
|
7
10
|
export { BlocksLocalizationClient } from "./localization/localization-client.js";
|
|
8
11
|
export { BlocksMailClient } from "./mail/mail-client.js";
|
|
9
12
|
export { BlocksMfaClient } from "./mfa/mfa-client.js";
|
|
10
13
|
export { BlocksNotifierClient } from "./notifier/notifier-client.js";
|
|
11
|
-
export type { BlocksAuthPassThroughResponse, BlocksAuthResponse, BlocksClientCredentialsRequest, BlocksAuthLoginRequest, BlocksIdpCallbackRequest, BlocksIdpInitiateRequest, BlocksIdpInitiateResponse, BlocksLoginOption, BlocksLogoutRequest, BlocksOidcRefreshRequest, BlocksOidcUserInfo, BlocksRefreshRequest, BlocksSocialLoginRequest, BlocksSwitchOrganizationRequest } from "./auth/auth-client.js";
|
|
12
|
-
export type { BlocksRequestOptions } from "./types.js";
|
|
14
|
+
export type { BlocksAuthJsonOptions, BlocksAuthPassThroughResponse, BlocksAuthResponse, BlocksClientCredentialsRequest, BlocksAuthLoginRequest, BlocksIdpCallbackRequest, BlocksIdpInitiateRequest, BlocksIdpInitiateResponse, BlocksLoginOption, BlocksLogoutRequest, BlocksOidcRefreshRequest, BlocksOidcUserInfo, BlocksRefreshRequest, BlocksSocialLoginRequest, BlocksSwitchOrganizationRequest } from "./auth/auth-client.js";
|
|
15
|
+
export type { BlocksExternalRequestOptions, BlocksRequestOptions } from "./types.js";
|
|
13
16
|
export type { BlocksBaseResponse, BlocksGetMyOrganizationsResponse, BlocksGetOrganizationResponse, BlocksGetOrganizationsResponse, BlocksGetPermissionResponse, BlocksGetPermissionsResponse, BlocksGetRoleResponse, BlocksGetRolesResponse, BlocksGetUserResponse, BlocksGetUsersResponse, BlocksIamListRequest, BlocksMeResponse, BlocksOrganization, BlocksPermission, BlocksQueryListResponse, BlocksQueryResponse, BlocksRole, BlocksUser } from "./iam/types.js";
|
|
14
|
-
export type { BlocksDataCollection, BlocksDataListOptions, BlocksDirectoryCreateRequest, BlocksDirectoryDeleteRequest, BlocksDirectoryMoveRequest, BlocksDirectoryUpdateRequest, BlocksFileCopyRequest, BlocksFileCreateVersionRequest, BlocksFileDeleteRequest, BlocksFileGetOptions, BlocksFileInfoListRequest, BlocksFileListRequest, BlocksFileMoveRequest, BlocksFileRenameRequest, BlocksFileUpdateAdditionalInfoRequest, BlocksFileUploadRequest, BlocksFileVersionsRequest, BlocksGraphqlRequest, BlocksLocalStorageUploadRequest, BlocksPagedResult, BlocksRegexGenerateRequest, BlocksSchemaFieldValidationOptions, BlocksSchemaListOptions, BlocksSchemaValidationListOptions, BlocksStorageAccessPolicyRequest, BlocksStorageEffect, BlocksStorageObject, BlocksStorageObjectListRequest, BlocksStorageObjectPageRequest, BlocksStorageObjectSearchRequest, BlocksStorageObjectsResponse, BlocksStorageObjectType, BlocksStoragePermission, BlocksStoragePermissionFlags, BlocksStoragePrincipalType, BlocksStorageResourceRequest, BlocksStorageResourceType, BlocksStorageRevokeAccessRequest, BlocksStorageShareRequest, BlocksStorageToggleInheritanceRequest, BlocksUploadToUrlRequest } from "./data/types.js";
|
|
17
|
+
export type { BlocksDataCollection, BlocksDataCollectionOptions, BlocksDataDeleteOptions, BlocksDataGetOptions, BlocksDataListOptions, BlocksDataSchema, BlocksDirectoryCreateRequest, BlocksDirectoryDeleteRequest, BlocksDirectoryMoveRequest, BlocksDirectoryUpdateRequest, BlocksFileCopyRequest, BlocksFileCreateVersionRequest, BlocksFileDeleteRequest, BlocksFileGetOptions, BlocksFileInfoListRequest, BlocksFileListRequest, BlocksFileMoveRequest, BlocksFileRenameRequest, BlocksFileUpdateAdditionalInfoRequest, BlocksFileUploadRequest, BlocksFileVersionsRequest, BlocksGraphqlRequest, BlocksLocalStorageUploadRequest, BlocksPagedResult, BlocksRegexGenerateRequest, BlocksSchemaFieldValidationOptions, BlocksSchemaListOptions, BlocksSchemaValidationListOptions, BlocksStorageAccessPolicyRequest, BlocksStorageEffect, BlocksStorageObject, BlocksStorageObjectListRequest, BlocksStorageObjectPageRequest, BlocksStorageObjectSearchRequest, BlocksStorageObjectsResponse, BlocksStorageObjectType, BlocksStoragePermission, BlocksStoragePermissionFlags, BlocksStoragePrincipalType, BlocksStorageResourceRequest, BlocksStorageResourceType, BlocksStorageRevokeAccessRequest, BlocksStorageShareRequest, BlocksStorageToggleInheritanceRequest, BlocksUploadToUrlRequest } from "./data/types.js";
|
|
15
18
|
export type { BlocksLocalizationDictionary, BlocksLocalizationKey, BlocksLocalizationKeyResource, BlocksLocalizationKeysByNamesRequest, BlocksLocalizationKeysByNamesResponse, BlocksLocalizationLanguage, BlocksLocalizationModule, BlocksLocalizationTranslationOptions } from "./localization/types.js";
|
|
16
19
|
export type { BlocksMfaBackupCodeUseRequest, BlocksMfaConfig, BlocksMfaConfigSaveRequest, BlocksMfaGenerateRequest, BlocksMfaPassThroughResponse, BlocksMfaResendRequest, BlocksMfaSetMethodRequest, BlocksMfaVerifyRequest, BlocksMfaVerifyTotpSetupRequest } from "./mfa/types.js";
|
|
17
20
|
export type { BlocksMailPassThroughResponse, BlocksSendMailRequest, BlocksSendMailToAnyRequest } from "./mail/types.js";
|
package/dist/mfa/mfa-client.d.ts
CHANGED
|
@@ -58,6 +58,8 @@ export declare class BlocksMfaClient {
|
|
|
58
58
|
* What: sets the signed-in user's active MFA method through `PUT /iam/v4/mfa/method`.
|
|
59
59
|
* Why: users who have enrolled more than one method need to switch which one is active.
|
|
60
60
|
* How: pass the `mfaType` to activate; enroll it first (e.g. via `totp.setup`/`verifySetup`) if it isn't already.
|
|
61
|
+
* Careful: IAM only branches on TOTP (1) and Email (2) here -- every other value falls through to its
|
|
62
|
+
* disable path and turns the user's MFA off. Use `disable()` when that is the intent.
|
|
61
63
|
*/
|
|
62
64
|
setMethod(request: BlocksMfaSetMethodRequest): Promise<BlocksMfaPassThroughResponse>;
|
|
63
65
|
/**
|
package/dist/mfa/mfa-client.js
CHANGED
|
@@ -69,6 +69,8 @@ export class BlocksMfaClient {
|
|
|
69
69
|
* What: sets the signed-in user's active MFA method through `PUT /iam/v4/mfa/method`.
|
|
70
70
|
* Why: users who have enrolled more than one method need to switch which one is active.
|
|
71
71
|
* How: pass the `mfaType` to activate; enroll it first (e.g. via `totp.setup`/`verifySetup`) if it isn't already.
|
|
72
|
+
* Careful: IAM only branches on TOTP (1) and Email (2) here -- every other value falls through to its
|
|
73
|
+
* disable path and turns the user's MFA off. Use `disable()` when that is the intent.
|
|
72
74
|
*/
|
|
73
75
|
setMethod(request) {
|
|
74
76
|
return this.http.request(`${MFA_API}/method`, {
|
package/dist/mfa/types.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ export type BlocksMfaConfigSaveRequest = Record<string, unknown> & {
|
|
|
21
21
|
userMfaType?: number[];
|
|
22
22
|
};
|
|
23
23
|
export type BlocksMfaGenerateRequest = {
|
|
24
|
-
/** IAM
|
|
24
|
+
/** IAM's UserMfaType: 0 None, 1 TOTP, 2 Email, 3 Sms, 4 WhatsApp. Only 1 and 2 have a provider. */
|
|
25
25
|
mfaType: number;
|
|
26
26
|
sendPhoneNumberAsEmailDomain?: string;
|
|
27
27
|
};
|
|
@@ -30,6 +30,7 @@ export type BlocksMfaResendRequest = {
|
|
|
30
30
|
sendPhoneNumberAsEmailDomain?: string;
|
|
31
31
|
};
|
|
32
32
|
export type BlocksMfaVerifyRequest = {
|
|
33
|
+
/** Same UserMfaType enum as `mfaType`: the method that issued this challenge (1 TOTP, 2 Email). */
|
|
33
34
|
authType: number;
|
|
34
35
|
isFromTokenCall?: boolean;
|
|
35
36
|
mfaId: string;
|
package/dist/notifier/types.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export type BlocksNotifyRequest = {
|
|
|
16
16
|
userIds?: string[];
|
|
17
17
|
};
|
|
18
18
|
export type BlocksGetUnreadNotificationsBySubscriptionFilterRequest = {
|
|
19
|
-
/**
|
|
19
|
+
/** 1 = CreatedTime (newest first), 2 = ReadStatus. Any other value (including an omitted 0) returns an empty list. */
|
|
20
20
|
orderBy?: 1 | 2;
|
|
21
21
|
subscriptionFilterData?: BlocksNotifierSubscriptionFilter;
|
|
22
22
|
userId?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seliseblocks/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Framework-neutral TypeScript client SDK for SELISE Blocks frontend applications.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -11,6 +11,16 @@
|
|
|
11
11
|
"typescript",
|
|
12
12
|
"frontend"
|
|
13
13
|
],
|
|
14
|
+
"homepage": "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-client#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/SELISEdigitalplatforms/blocks-cli/issues"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/SELISEdigitalplatforms/blocks-cli.git",
|
|
21
|
+
"directory": "blocks-client"
|
|
22
|
+
},
|
|
23
|
+
"author": "SELISE Digital Platforms",
|
|
14
24
|
"main": "./dist/index.js",
|
|
15
25
|
"types": "./dist/index.d.ts",
|
|
16
26
|
"exports": {
|
|
@@ -27,7 +37,8 @@
|
|
|
27
37
|
"files": [
|
|
28
38
|
"dist",
|
|
29
39
|
"README.md",
|
|
30
|
-
"
|
|
40
|
+
"CHANGELOG.md",
|
|
41
|
+
"AGENT_GUIDE.md",
|
|
31
42
|
"LICENSE"
|
|
32
43
|
],
|
|
33
44
|
"scripts": {
|