@isi-ui7/bos7-shared 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/dist/api.d.ts +4 -0
- package/dist/auth7/client.d.ts +26 -0
- package/dist/auth7/delegated-proxy.d.ts +33 -0
- package/dist/auth7/hooks/useAuth.d.ts +10 -0
- package/dist/auth7/hooks/useSession.d.ts +12 -0
- package/dist/auth7/index.d.ts +12 -0
- package/dist/auth7/provider.d.ts +13 -0
- package/dist/auth7/scope-guard.d.ts +5 -0
- package/dist/auth7/service-account.d.ts +2 -0
- package/dist/auth7/token-exchange.d.ts +11 -0
- package/dist/auth7/types.d.ts +63 -0
- package/dist/backend.d.ts +20 -0
- package/dist/crud-components.d.ts +47 -0
- package/dist/crud-hooks.d.ts +15 -0
- package/dist/crud-types.d.ts +86 -0
- package/dist/data-table/cursor-adapter.d.ts +74 -0
- package/dist/event-bus/index.d.ts +20 -0
- package/dist/event-bus/useEventBus.d.ts +21 -0
- package/dist/event-bus.d.ts +1 -0
- package/dist/export.d.ts +7 -0
- package/dist/form-layout.d.ts +39 -0
- package/dist/form-numeric.d.ts +35 -0
- package/dist/form-renderer-utils.d.ts +10 -0
- package/dist/form-renderer.d.ts +18 -0
- package/dist/form-rules.d.ts +12 -0
- package/dist/form-types.d.ts +130 -0
- package/dist/html2canvas.esm-d2sM-0Wm.js +4870 -0
- package/dist/i18n.d.ts +35 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.es-Bylk5fh-.js +5649 -0
- package/dist/index.js +20779 -0
- package/dist/jspdf.es.min-Dzm5j8wC.js +9977 -0
- package/dist/jspdf.plugin.autotable-DcntYaes.js +1078 -0
- package/dist/modal-layout.d.ts +45 -0
- package/dist/nats/client.d.ts +54 -0
- package/dist/notif7.d.ts +21 -0
- package/dist/notification/routing.d.ts +4 -0
- package/dist/notifications-bff.d.ts +22 -0
- package/dist/observability/otel-init.d.ts +1 -0
- package/dist/page-layout.d.ts +24 -0
- package/dist/purify.es-CiEWEeUM.js +605 -0
- package/dist/shell/app-shell-layout.d.ts +70 -0
- package/dist/shell/branch.d.ts +6 -0
- package/dist/shell/interaction.d.ts +2 -0
- package/dist/shell/provider.d.ts +15 -0
- package/dist/style-contract.d.ts +72 -0
- package/dist/types/core.d.ts +39 -0
- package/dist/types/notification.d.ts +30 -0
- package/dist/workflow/api-client.d.ts +2 -0
- package/dist/workflow/backend.d.ts +9 -0
- package/dist/workflow/crud-client.d.ts +3 -0
- package/dist/workflow/notif7.d.ts +6 -0
- package/dist/workflow/starter.d.ts +44 -0
- package/dist/workflow/use-crud-form.d.ts +27 -0
- package/dist/workflow/use-workflow-tracker.d.ts +40 -0
- package/package.json +92 -0
- package/src/api.ts +40 -0
- package/src/auth7/client.ts +248 -0
- package/src/auth7/delegated-proxy.ts +80 -0
- package/src/auth7/hooks/useAuth.ts +21 -0
- package/src/auth7/hooks/useSession.ts +75 -0
- package/src/auth7/index.ts +14 -0
- package/src/auth7/provider.tsx +256 -0
- package/src/auth7/scope-guard.ts +54 -0
- package/src/auth7/service-account.ts +71 -0
- package/src/auth7/token-exchange.ts +125 -0
- package/src/auth7/types.ts +72 -0
- package/src/backend.ts +96 -0
- package/src/crud-components.tsx +580 -0
- package/src/crud-hooks.test.ts +32 -0
- package/src/crud-hooks.ts +31 -0
- package/src/crud-types.ts +64 -0
- package/src/data-table/cursor-adapter.ts +239 -0
- package/src/event-bus/index.ts +90 -0
- package/src/event-bus/useEventBus.ts +93 -0
- package/src/event-bus.ts +1 -0
- package/src/export.ts +62 -0
- package/src/form-contract.css +52 -0
- package/src/form-layout.tsx +90 -0
- package/src/form-numeric.ts +173 -0
- package/src/form-renderer-utils.ts +139 -0
- package/src/form-renderer.tsx +624 -0
- package/src/form-rules.ts +54 -0
- package/src/form-types.ts +126 -0
- package/src/i18n.tsx +92 -0
- package/src/index.ts +20 -0
- package/src/modal-layout.tsx +60 -0
- package/src/nats/client.ts +130 -0
- package/src/notif7.ts +76 -0
- package/src/notification/routing.ts +64 -0
- package/src/notifications-bff.ts +273 -0
- package/src/observability/otel-init.ts +41 -0
- package/src/page-layout.tsx +69 -0
- package/src/shell/app-shell-layout.tsx +494 -0
- package/src/shell/branch.ts +48 -0
- package/src/shell/interaction.ts +17 -0
- package/src/shell/provider.tsx +34 -0
- package/src/style-contract.test.ts +59 -0
- package/src/style-contract.ts +132 -0
- package/src/types/core.ts +46 -0
- package/src/types/notification.ts +35 -0
- package/src/workflow/api-client.ts +7 -0
- package/src/workflow/backend.ts +53 -0
- package/src/workflow/crud-client.ts +43 -0
- package/src/workflow/notif7.ts +28 -0
- package/src/workflow/starter.ts +153 -0
- package/src/workflow/use-crud-form.ts +176 -0
- package/src/workflow/use-workflow-tracker.ts +109 -0
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { QueryParams, QueryResult, ServiceAction, ServiceResponse } from './types/core';
|
|
2
|
+
|
|
3
|
+
export declare function queryList<T>(domain: string, params: QueryParams): Promise<QueryResult<T>>;
|
|
4
|
+
export declare function callService<T>(domain: string, action: ServiceAction, payload?: unknown): Promise<ServiceResponse<T>>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TokenSet, UserProfile } from './types';
|
|
2
|
+
|
|
3
|
+
export declare function buildAuthorizationUrl(): Promise<{
|
|
4
|
+
url: string;
|
|
5
|
+
codeVerifier: string;
|
|
6
|
+
state: string;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function exchangeCodeForTokens(code: string, codeVerifier: string): Promise<TokenSet>;
|
|
9
|
+
export declare function refreshAccessToken(_refreshToken: string): Promise<TokenSet>;
|
|
10
|
+
export declare function revokeToken(token: string): Promise<void>;
|
|
11
|
+
export declare function getUserInfo(accessToken: string): Promise<UserProfile>;
|
|
12
|
+
export declare function isTokenExpired(expiresAt: number): boolean;
|
|
13
|
+
export declare function storeTokensToCookies(tokens: TokenSet): void;
|
|
14
|
+
export declare function clearTokensFromCookies(): void;
|
|
15
|
+
export declare function getStoredTokens(): {
|
|
16
|
+
accessToken: string | null;
|
|
17
|
+
refreshToken: string | null;
|
|
18
|
+
expiresAt: number;
|
|
19
|
+
};
|
|
20
|
+
export declare function storeOAuthParams(codeVerifier: string, state: string, returnUrl: string): void;
|
|
21
|
+
export declare function getOAuthParams(): {
|
|
22
|
+
codeVerifier: string | null;
|
|
23
|
+
state: string | null;
|
|
24
|
+
returnUrl: string | null;
|
|
25
|
+
};
|
|
26
|
+
export declare function clearOAuthParams(): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { ExchangeOptions } from './token-exchange';
|
|
2
|
+
|
|
3
|
+
export interface DelegatedProxyOptions extends ExchangeOptions {
|
|
4
|
+
backendUrl?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DelegatedProxy {
|
|
7
|
+
get<T>(path: string, query?: Record<string, string>): Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
data?: T;
|
|
10
|
+
error?: string;
|
|
11
|
+
}>;
|
|
12
|
+
post<T>(path: string, body: unknown): Promise<{
|
|
13
|
+
ok: boolean;
|
|
14
|
+
data?: T;
|
|
15
|
+
error?: string;
|
|
16
|
+
}>;
|
|
17
|
+
put<T>(path: string, body: unknown): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
data?: T;
|
|
20
|
+
error?: string;
|
|
21
|
+
}>;
|
|
22
|
+
delete<T>(path: string): Promise<{
|
|
23
|
+
ok: boolean;
|
|
24
|
+
data?: T;
|
|
25
|
+
error?: string;
|
|
26
|
+
}>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Exchange the user's access token for a delegated service token (RFC 8693),
|
|
30
|
+
* then return a typed proxy client for backend calls.
|
|
31
|
+
* The exchanged token is cached per (userToken, audience) — see token-exchange.ts.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createDelegatedProxy(userToken: string, audience: string, options?: DelegatedProxyOptions): Promise<DelegatedProxy>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function useAuth(): {
|
|
2
|
+
isAuthenticated: boolean;
|
|
3
|
+
isLoading: boolean;
|
|
4
|
+
user: import('..').UserProfile | null;
|
|
5
|
+
accessToken: string | null;
|
|
6
|
+
error: string | null;
|
|
7
|
+
login: () => Promise<void>;
|
|
8
|
+
logout: () => Promise<void>;
|
|
9
|
+
refreshSession: () => Promise<void>;
|
|
10
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { useAuthContext } from '../provider';
|
|
2
|
+
|
|
3
|
+
interface UseSessionReturn {
|
|
4
|
+
isAuthenticated: boolean;
|
|
5
|
+
isLoading: boolean;
|
|
6
|
+
user: ReturnType<typeof useAuthContext>['user'];
|
|
7
|
+
needsRefresh: boolean;
|
|
8
|
+
refreshSession: () => Promise<void>;
|
|
9
|
+
timeUntilExpiry: number | null;
|
|
10
|
+
}
|
|
11
|
+
export declare function useSession(): UseSessionReturn;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { AuthProvider, useAuthContext } from './provider';
|
|
2
|
+
export { useAuth } from './hooks/useAuth';
|
|
3
|
+
export { useSession } from './hooks/useSession';
|
|
4
|
+
export { getServiceToken, clearServiceTokenCache } from './service-account';
|
|
5
|
+
export { exchangeUserToken, clearExchangeCache } from './token-exchange';
|
|
6
|
+
export type { TokenExchangeResult, ExchangeOptions } from './token-exchange';
|
|
7
|
+
export { createDelegatedProxy } from './delegated-proxy';
|
|
8
|
+
export type { DelegatedProxy, DelegatedProxyOptions } from './delegated-proxy';
|
|
9
|
+
export * from './types';
|
|
10
|
+
export * from './client';
|
|
11
|
+
export { requireScope, scopeFromRequest } from './scope-guard';
|
|
12
|
+
export type { ScopeLevel } from './scope-guard';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { AuthState } from './types';
|
|
3
|
+
|
|
4
|
+
interface AuthContextValue extends AuthState {
|
|
5
|
+
login: () => Promise<void>;
|
|
6
|
+
logout: () => Promise<void>;
|
|
7
|
+
refreshSession: () => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function AuthProvider({ children }: {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function useAuthContext(): AuthContextValue;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
export type ScopeLevel = 'read' | 'write' | 'approve';
|
|
4
|
+
export declare function scopeFromRequest(req: NextRequest): ScopeLevel;
|
|
5
|
+
export declare function requireScope(req: NextRequest, required: ScopeLevel): NextResponse | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface TokenExchangeResult {
|
|
2
|
+
accessToken: string;
|
|
3
|
+
expiresIn: number;
|
|
4
|
+
scope: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ExchangeOptions {
|
|
7
|
+
failClosed?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/** Clear the exchange cache. For use in tests. */
|
|
10
|
+
export declare function clearExchangeCache(): void;
|
|
11
|
+
export declare function exchangeUserToken(userToken: string, audience: string, scope?: string, options?: ExchangeOptions): Promise<TokenExchangeResult>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export interface TokenSet {
|
|
2
|
+
access_token: string;
|
|
3
|
+
token_type: 'Bearer';
|
|
4
|
+
expires_in: number;
|
|
5
|
+
refresh_token?: string;
|
|
6
|
+
scope: string;
|
|
7
|
+
id_token?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface StoredTokenInfo {
|
|
10
|
+
access_token: string;
|
|
11
|
+
refresh_token?: string;
|
|
12
|
+
expires_at: number;
|
|
13
|
+
scope: string;
|
|
14
|
+
}
|
|
15
|
+
export interface UserProfile {
|
|
16
|
+
sub: string;
|
|
17
|
+
email?: string;
|
|
18
|
+
email_verified?: boolean;
|
|
19
|
+
name?: string;
|
|
20
|
+
given_name?: string;
|
|
21
|
+
family_name?: string;
|
|
22
|
+
picture?: string;
|
|
23
|
+
locale?: string;
|
|
24
|
+
tenant_id?: string;
|
|
25
|
+
roles?: string[];
|
|
26
|
+
branch_id?: string | null;
|
|
27
|
+
}
|
|
28
|
+
export interface AuthState {
|
|
29
|
+
isAuthenticated: boolean;
|
|
30
|
+
isLoading: boolean;
|
|
31
|
+
user: UserProfile | null;
|
|
32
|
+
accessToken: string | null;
|
|
33
|
+
error: string | null;
|
|
34
|
+
}
|
|
35
|
+
export interface SessionInfo {
|
|
36
|
+
user: UserProfile;
|
|
37
|
+
accessToken: string;
|
|
38
|
+
expiresAt: number;
|
|
39
|
+
scope: string;
|
|
40
|
+
}
|
|
41
|
+
export declare const OAUTH2_COOKIE_NAMES: {
|
|
42
|
+
readonly ACCESS_TOKEN: "access_token";
|
|
43
|
+
readonly REFRESH_TOKEN: "refresh_token";
|
|
44
|
+
readonly ID_TOKEN: "id_token";
|
|
45
|
+
readonly TOKEN_EXPIRES_AT: "token_expires_at";
|
|
46
|
+
readonly TOKEN_SCOPE: "token_scope";
|
|
47
|
+
readonly PKCE_VERIFIER: "auth7_pkce_verifier";
|
|
48
|
+
readonly OAUTH_STATE: "auth7_oauth_state";
|
|
49
|
+
readonly OAUTH_RETURN_URL: "auth7_return_url";
|
|
50
|
+
};
|
|
51
|
+
export declare const OAUTH2_ENDPOINTS: {
|
|
52
|
+
readonly AUTHORIZE: "/oauth2/authorize";
|
|
53
|
+
readonly TOKEN: "/oauth2/token";
|
|
54
|
+
readonly REVOKE: "/oauth2/revoke";
|
|
55
|
+
readonly LOGOUT: "/oauth2/logout";
|
|
56
|
+
readonly USERINFO: "/oauth2/userinfo";
|
|
57
|
+
};
|
|
58
|
+
export declare const AUTH7_SCOPES: {
|
|
59
|
+
readonly OPENID: "openid";
|
|
60
|
+
readonly PROFILE: "profile";
|
|
61
|
+
readonly EMAIL: "email";
|
|
62
|
+
readonly ROLES: "roles";
|
|
63
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export declare function backendGet<T>(path: string, query?: Record<string, string>, accessToken?: string): Promise<{
|
|
2
|
+
ok: boolean;
|
|
3
|
+
data?: T | undefined;
|
|
4
|
+
error?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export declare function backendPost<T>(path: string, body: unknown, accessToken?: string): Promise<{
|
|
7
|
+
ok: boolean;
|
|
8
|
+
data?: T | undefined;
|
|
9
|
+
error?: string;
|
|
10
|
+
}>;
|
|
11
|
+
export declare function backendPut<T>(path: string, body: unknown, accessToken?: string): Promise<{
|
|
12
|
+
ok: boolean;
|
|
13
|
+
data?: T | undefined;
|
|
14
|
+
error?: string;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function backendDelete<T>(path: string, accessToken?: string): Promise<{
|
|
17
|
+
ok: boolean;
|
|
18
|
+
data?: T | undefined;
|
|
19
|
+
error?: string;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { CrudDeleteSchema, CrudListSchema } from './crud-types';
|
|
3
|
+
import { CrudForm, FormMode } from './form-types';
|
|
4
|
+
import { Ui7FormDensity } from './style-contract';
|
|
5
|
+
|
|
6
|
+
export declare function SharedCrudListPage({ schema, tableKey, onAdd, onPopupClick }: {
|
|
7
|
+
schema: CrudListSchema;
|
|
8
|
+
tableKey?: number;
|
|
9
|
+
onAdd: () => void;
|
|
10
|
+
onPopupClick: (row: Record<string, unknown>, actionId: string) => void;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export declare function CrudSchemaListPage<TData extends Record<string, unknown>>({ listSchema, deleteSchema, onAdd, onView, onEdit, deleteApiPath, onCustomAction, }: {
|
|
13
|
+
listSchema: CrudListSchema;
|
|
14
|
+
deleteSchema?: CrudDeleteSchema<TData>;
|
|
15
|
+
onAdd: () => void;
|
|
16
|
+
onView?: (id: string) => void;
|
|
17
|
+
onEdit?: (id: string) => void;
|
|
18
|
+
deleteApiPath?: (id: string) => string;
|
|
19
|
+
/**
|
|
20
|
+
* Level 1: called for any popup action id not handled by built-in logic
|
|
21
|
+
* (view / edit / delete) and not in listSchema.customActionSchemas (Level 2).
|
|
22
|
+
*/
|
|
23
|
+
onCustomAction?: (id: string, row: Record<string, unknown>, actionId: string) => void;
|
|
24
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
25
|
+
export declare function SharedCrudFormPage({ title, subtitle, children, footer }: {
|
|
26
|
+
title: string;
|
|
27
|
+
subtitle?: string;
|
|
28
|
+
children: ReactNode;
|
|
29
|
+
footer: ReactNode;
|
|
30
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function CrudSchemaPage<TData extends Record<string, unknown>>({ schema, mode, params, onBack, onSuccess, density: densityProp, }: {
|
|
32
|
+
schema: CrudForm<TData>;
|
|
33
|
+
mode: FormMode;
|
|
34
|
+
params?: Record<string, string>;
|
|
35
|
+
onBack?: () => void;
|
|
36
|
+
onSuccess?: (instanceId: string) => void;
|
|
37
|
+
/** Override schema.density. Both default to "compact". */
|
|
38
|
+
density?: Ui7FormDensity;
|
|
39
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
40
|
+
export declare function SharedCrudDeleteModal<TData extends Record<string, unknown>>({ open, row, schema, deleting, onClose, onConfirm }: {
|
|
41
|
+
open: boolean;
|
|
42
|
+
row: TData | null;
|
|
43
|
+
schema: CrudDeleteSchema<TData>;
|
|
44
|
+
deleting?: boolean;
|
|
45
|
+
onClose: () => void;
|
|
46
|
+
onConfirm: () => void;
|
|
47
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CrudActionOverrideHooks } from './crud-types';
|
|
2
|
+
|
|
3
|
+
export declare function runCrudHook<TData extends Record<string, unknown>, TResult>(hook: ((data: TData, context: {
|
|
4
|
+
mode: "create" | "edit" | "view" | "delete";
|
|
5
|
+
id?: string;
|
|
6
|
+
}) => Promise<TResult> | TResult) | undefined, data: TData, context: {
|
|
7
|
+
mode: "create" | "edit" | "view" | "delete";
|
|
8
|
+
id?: string;
|
|
9
|
+
}): Promise<TResult | undefined>;
|
|
10
|
+
export declare function applyCrudFieldOverrides<TField extends {
|
|
11
|
+
key: string;
|
|
12
|
+
readonly?: boolean;
|
|
13
|
+
required?: boolean;
|
|
14
|
+
helperText?: unknown;
|
|
15
|
+
}>(fields: TField[], hooks?: CrudActionOverrideHooks<Record<string, unknown>> | CrudActionOverrideHooks<any>): TField[];
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
export type CrudPopupMenuItem = {
|
|
4
|
+
id: string;
|
|
5
|
+
itemType: "item" | "separator";
|
|
6
|
+
caption?: string;
|
|
7
|
+
};
|
|
8
|
+
export type CrudActionMode = "create" | "edit" | "view" | "delete";
|
|
9
|
+
export type CrudActionOverrideHooks<TData extends Record<string, unknown>> = {
|
|
10
|
+
beforeLoad?: (context: {
|
|
11
|
+
mode: CrudActionMode;
|
|
12
|
+
id?: string;
|
|
13
|
+
}) => Promise<void> | void;
|
|
14
|
+
afterLoad?: (data: TData, context: {
|
|
15
|
+
mode: CrudActionMode;
|
|
16
|
+
id?: string;
|
|
17
|
+
}) => Promise<TData> | TData;
|
|
18
|
+
beforeSubmit?: (data: TData, context: {
|
|
19
|
+
mode: Extract<CrudActionMode, "create" | "edit">;
|
|
20
|
+
id?: string;
|
|
21
|
+
}) => Promise<TData> | TData;
|
|
22
|
+
afterSubmit?: (result: unknown, context: {
|
|
23
|
+
mode: Extract<CrudActionMode, "create" | "edit">;
|
|
24
|
+
id?: string;
|
|
25
|
+
}) => Promise<void> | void;
|
|
26
|
+
mapRequest?: (data: TData, context: {
|
|
27
|
+
mode: CrudActionMode;
|
|
28
|
+
id?: string;
|
|
29
|
+
}) => unknown;
|
|
30
|
+
mapResponse?: (data: unknown, context: {
|
|
31
|
+
mode: CrudActionMode;
|
|
32
|
+
id?: string;
|
|
33
|
+
}) => TData;
|
|
34
|
+
fieldOverrides?: Partial<Record<string, {
|
|
35
|
+
readonly?: boolean;
|
|
36
|
+
required?: boolean;
|
|
37
|
+
hidden?: boolean;
|
|
38
|
+
helperText?: ReactNode;
|
|
39
|
+
}>>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Level 2 custom action: schema-driven confirmation modal.
|
|
43
|
+
* Define in CrudListSchema.customActionSchemas keyed by popup menu item id.
|
|
44
|
+
* CrudSchemaListPage will handle the modal and API call automatically.
|
|
45
|
+
*/
|
|
46
|
+
export type CrudCustomActionSchema = {
|
|
47
|
+
title: string;
|
|
48
|
+
description: string | ((row: Record<string, unknown>) => string);
|
|
49
|
+
confirmLabel?: string;
|
|
50
|
+
cancelLabel?: string;
|
|
51
|
+
/** API endpoint — string or function receiving row id. */
|
|
52
|
+
apiPath: string | ((id: string) => string);
|
|
53
|
+
method?: "POST" | "PATCH" | "PUT";
|
|
54
|
+
};
|
|
55
|
+
export type CrudListSchema = {
|
|
56
|
+
title: string;
|
|
57
|
+
subtitle?: string;
|
|
58
|
+
apiPath: string;
|
|
59
|
+
columns: Record<string, unknown>;
|
|
60
|
+
popupMenuItems: CrudPopupMenuItem[];
|
|
61
|
+
addButtonLabel: string;
|
|
62
|
+
/** Enable column sorting. Defaults to true. */
|
|
63
|
+
showSort?: boolean;
|
|
64
|
+
/** Enable search bar. Defaults to true. */
|
|
65
|
+
showSearch?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Level 2: schema-driven confirmation modals for custom popup actions.
|
|
68
|
+
* Keyed by popup menu item id. Actions not listed here fall through to onCustomAction (Level 1).
|
|
69
|
+
*/
|
|
70
|
+
customActionSchemas?: Record<string, CrudCustomActionSchema>;
|
|
71
|
+
};
|
|
72
|
+
export type CrudDeleteSchema<TData extends Record<string, unknown>> = {
|
|
73
|
+
/** Omit to use i18n default ("Konfirmasi Hapus"). */
|
|
74
|
+
title?: string;
|
|
75
|
+
/** Omit to use i18n default ("Data berikut akan dihapus permanen."). */
|
|
76
|
+
description?: string;
|
|
77
|
+
summary: Array<{
|
|
78
|
+
label: string;
|
|
79
|
+
key: keyof TData | string;
|
|
80
|
+
format?: (value: unknown, row: TData) => ReactNode;
|
|
81
|
+
}>;
|
|
82
|
+
/** Omit to use i18n default ("Hapus"). */
|
|
83
|
+
confirmLabel?: string;
|
|
84
|
+
/** Omit to use i18n default ("Batal"). */
|
|
85
|
+
cancelLabel?: string;
|
|
86
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/** Minimal subset of NextRequest used by cursor-adapter. Accepting this interface
|
|
4
|
+
* instead of the concrete NextRequest prevents brand-marker conflicts when the
|
|
5
|
+
* consumer app resolves next/ from a different pnpm instance than this library. */
|
|
6
|
+
interface NextRequestLike {
|
|
7
|
+
cookies: {
|
|
8
|
+
get(name: string): {
|
|
9
|
+
value: string;
|
|
10
|
+
} | undefined;
|
|
11
|
+
};
|
|
12
|
+
nextUrl: {
|
|
13
|
+
searchParams: URLSearchParams;
|
|
14
|
+
};
|
|
15
|
+
json(): Promise<unknown>;
|
|
16
|
+
}
|
|
17
|
+
export type CursorRequest = {
|
|
18
|
+
reqType?: 'next' | 'prev' | 'first' | 'last' | 'apply';
|
|
19
|
+
searchText?: string;
|
|
20
|
+
sortColumn?: {
|
|
21
|
+
columnName: string;
|
|
22
|
+
ascending?: boolean;
|
|
23
|
+
};
|
|
24
|
+
topData?: Record<string, unknown>;
|
|
25
|
+
bottomData?: Record<string, unknown>;
|
|
26
|
+
pageSize?: number;
|
|
27
|
+
};
|
|
28
|
+
/** Backend row shape. Carries an opaque `_cursor` used for next/prev anchors. */
|
|
29
|
+
export type BackendRow = Record<string, unknown> & {
|
|
30
|
+
id?: string;
|
|
31
|
+
_cursor?: string;
|
|
32
|
+
};
|
|
33
|
+
export interface CursorAdapterOptions {
|
|
34
|
+
/** Absolute base URL of the backend (e.g. `http://localhost:8091`). */
|
|
35
|
+
backendUrl: string;
|
|
36
|
+
/** Resource path on the backend, with leading slash (e.g. `/v1/pejabat-cabang`). */
|
|
37
|
+
resourcePath: string;
|
|
38
|
+
/**
|
|
39
|
+
* Query-string filter keys forwarded verbatim from the *route's URL* into
|
|
40
|
+
* the backend query. Used for page-level filters set via
|
|
41
|
+
* `apiPath="/api/x?status=ACTIVE"` so they survive the POST.
|
|
42
|
+
*/
|
|
43
|
+
forwardFilters?: string[];
|
|
44
|
+
/** Column-name → ServerDataTable column type map. */
|
|
45
|
+
columnTypes: Record<string, string>;
|
|
46
|
+
/** Whitelist of columns the user may sort by. */
|
|
47
|
+
altSortColumns: string[];
|
|
48
|
+
/** Whitelist of columns the search input matches against. */
|
|
49
|
+
altSearchColumns: string[];
|
|
50
|
+
/** Cookie name carrying the user JWT. Defaults to `access_token`. */
|
|
51
|
+
accessTokenCookie?: string;
|
|
52
|
+
/**
|
|
53
|
+
* If set, exchange the user token for a delegated token for this audience before
|
|
54
|
+
* calling the backend. Required when the backend mounts RequireDelegatedAuth().
|
|
55
|
+
*/
|
|
56
|
+
audience?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Translate a `<ServerDataTable>` POST cursor body into a backend cursor GET.
|
|
60
|
+
* Reads `bottomData._cursor` / `topData._cursor` to anchor next/prev requests,
|
|
61
|
+
* forwards sort + search + page-level filters, returns the table envelope.
|
|
62
|
+
*/
|
|
63
|
+
export declare function handleCursorTable(req: NextRequestLike, opts: CursorAdapterOptions): Promise<NextResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* Forward a backend GET verbatim. Useful for modal lookups and debug calls
|
|
66
|
+
* that don't need cursor translation.
|
|
67
|
+
*/
|
|
68
|
+
export declare function proxyBackendGet(req: NextRequestLike, opts: {
|
|
69
|
+
backendUrl: string;
|
|
70
|
+
resourcePath: string;
|
|
71
|
+
accessTokenCookie?: string;
|
|
72
|
+
audience?: string;
|
|
73
|
+
}): Promise<NextResponse>;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface EventBusConfig {
|
|
2
|
+
url: string;
|
|
3
|
+
name?: string;
|
|
4
|
+
}
|
|
5
|
+
export interface DomainEvent {
|
|
6
|
+
eventType: string;
|
|
7
|
+
subject: string;
|
|
8
|
+
occurredAt: Date;
|
|
9
|
+
id: string;
|
|
10
|
+
payload: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export type EventHandler = (event: DomainEvent) => void | Promise<void>;
|
|
13
|
+
export interface EventBus {
|
|
14
|
+
publish(event: DomainEvent): Promise<void>;
|
|
15
|
+
subscribe(eventType: string, handler: EventHandler): Promise<void>;
|
|
16
|
+
unsubscribe(eventType: string): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function createEventBus(config: EventBusConfig): Promise<EventBus>;
|
|
19
|
+
export declare function getEventBus(): EventBus | null;
|
|
20
|
+
export declare function useEventBus(): EventBus | null;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { DomainEvent } from './index';
|
|
2
|
+
|
|
3
|
+
export interface UseEventBusOptions {
|
|
4
|
+
autoConnect?: boolean;
|
|
5
|
+
url?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function useEventBus(): {
|
|
8
|
+
isConnected: boolean;
|
|
9
|
+
error: Error | null;
|
|
10
|
+
subscribe: (eventType: string, handler: (event: DomainEvent) => void) => Promise<void>;
|
|
11
|
+
unsubscribe: (eventType: string) => void;
|
|
12
|
+
publish: (event: DomainEvent) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
export interface UseNotificationEventsOptions {
|
|
15
|
+
onNotification?: (event: DomainEvent) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function useNotificationEvents(options?: UseNotificationEventsOptions): {
|
|
18
|
+
notifications: DomainEvent[];
|
|
19
|
+
isConnected: boolean;
|
|
20
|
+
clearNotifications: () => void;
|
|
21
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './event-bus/index';
|
package/dist/export.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface ExportColumn {
|
|
2
|
+
field: string;
|
|
3
|
+
title: string;
|
|
4
|
+
displayFormat?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function exportToExcel<T extends Record<string, unknown>>(data: T[], columns: ExportColumn[], sheetName: string): void;
|
|
7
|
+
export declare function exportToPDF<T extends Record<string, unknown>>(data: T[], columns: ExportColumn[], title: string): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Horizontal label + input row layout for forms. Carbon DS ships only the
|
|
5
|
+
* vertical (stacked) `<Form>` pattern, so this is the shared "label-left,
|
|
6
|
+
* input-right" primitive every bos7-* app should use to keep modals compact
|
|
7
|
+
* and align with the existing master-data screens.
|
|
8
|
+
*
|
|
9
|
+
* Pattern:
|
|
10
|
+
* <HorizontalField label="Kode Cabang" required>
|
|
11
|
+
* <TextInput id="..." labelText="" ... />
|
|
12
|
+
* </HorizontalField>
|
|
13
|
+
*
|
|
14
|
+
* The child input should have its own `labelText` set to an empty string
|
|
15
|
+
* (Carbon inputs render a top label by default; here the label lives in the
|
|
16
|
+
* row's left column instead).
|
|
17
|
+
*
|
|
18
|
+
* Width tuning: pass `labelWidth` to override the default. For tightly
|
|
19
|
+
* grouped forms (e.g. modal `size="sm"`), 8rem usually fits; for descriptive
|
|
20
|
+
* labels in `size="lg"` modals 10–12rem reads better.
|
|
21
|
+
*/
|
|
22
|
+
export interface HorizontalFieldProps {
|
|
23
|
+
label: string;
|
|
24
|
+
/** Marks the row as required and renders a red asterisk next to the label. */
|
|
25
|
+
required?: boolean;
|
|
26
|
+
/** Helper text shown below the input (small, muted). */
|
|
27
|
+
helperText?: string;
|
|
28
|
+
/** Width of the label column. Defaults to 9.5rem. */
|
|
29
|
+
labelWidth?: string;
|
|
30
|
+
/** Horizontal gap between label and input. Defaults to 1rem. */
|
|
31
|
+
gap?: string;
|
|
32
|
+
/** Vertical spacing below the row. Defaults to 0.5rem. */
|
|
33
|
+
marginBlockEnd?: string;
|
|
34
|
+
/** Vertical alignment of the label relative to the input. Defaults to center. */
|
|
35
|
+
align?: "center" | "top";
|
|
36
|
+
className?: string;
|
|
37
|
+
children: ReactNode;
|
|
38
|
+
}
|
|
39
|
+
export declare function HorizontalField({ label, required, helperText, labelWidth, gap, marginBlockEnd, align, className, children, }: HorizontalFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type DecimalParseResult = {
|
|
2
|
+
ok: true;
|
|
3
|
+
value: number;
|
|
4
|
+
normalized: string;
|
|
5
|
+
scale: number;
|
|
6
|
+
} | {
|
|
7
|
+
ok: false;
|
|
8
|
+
reason: "invalid" | "too-many-decimals";
|
|
9
|
+
};
|
|
10
|
+
export type DecimalSanitizeOptions = {
|
|
11
|
+
maxFractionDigits?: number;
|
|
12
|
+
allowNegative?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export type CurrencyPrecisionConfig = {
|
|
15
|
+
precisionByCurrency: Record<string, number>;
|
|
16
|
+
defaultPrecision?: number;
|
|
17
|
+
};
|
|
18
|
+
export type PhoneRule = {
|
|
19
|
+
minDigits: number;
|
|
20
|
+
maxDigits: number;
|
|
21
|
+
allowedPrefixes?: string[];
|
|
22
|
+
};
|
|
23
|
+
export declare function sanitizeDecimalInput(raw: string, options?: DecimalSanitizeOptions): string;
|
|
24
|
+
export declare function parseDecimalStrict(raw: string, options?: DecimalSanitizeOptions): DecimalParseResult;
|
|
25
|
+
export declare function getCurrencyPrecision(currencyCode: string, config: CurrencyPrecisionConfig): number;
|
|
26
|
+
export declare function formatCurrencyAmount(value: number, currencyCode: string, config: CurrencyPrecisionConfig, locale?: "id" | "en"): string;
|
|
27
|
+
export declare function normalizePhoneInput(raw: string): string;
|
|
28
|
+
export declare function isValidPhoneInput(value: string, rule: PhoneRule): boolean;
|
|
29
|
+
export declare function normalizePhoneForSave(raw: string, rule: PhoneRule): string;
|
|
30
|
+
/** Indonesian phone: 08xx / +62xx, 10–15 digits. */
|
|
31
|
+
export declare const INDONESIA_PHONE_RULE: PhoneRule;
|
|
32
|
+
/** International phone: any valid digit sequence, 7–15 digits, no prefix restriction. */
|
|
33
|
+
export declare const GLOBAL_PHONE_RULE: PhoneRule;
|
|
34
|
+
/** Standard currency precision for Indonesian banking (IDR 2 dec, USD 4 dec). */
|
|
35
|
+
export declare const INDONESIA_CURRENCY_CONFIG: CurrencyPrecisionConfig;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ApiPath, FormField, FormLayout, FormMode } from './form-types';
|
|
2
|
+
import { BosSharedLabels } from './i18n';
|
|
3
|
+
|
|
4
|
+
export declare function resolveApiPath(path: ApiPath, params: Record<string, string>): string;
|
|
5
|
+
type ValidationI18n = Pick<BosSharedLabels, "validRequired" | "validMinLength" | "validMaxLength" | "validMin" | "validMax" | "validPattern">;
|
|
6
|
+
export declare function runFieldValidation<TData extends Record<string, unknown>>(fields: FormField<TData>[], data: TData, mode: FormMode, i18n?: Partial<ValidationI18n>): Partial<Record<keyof TData, string>>;
|
|
7
|
+
export declare function collectAllFields<TData extends Record<string, unknown>>(layout: FormLayout<TData>): FormField<TData>[];
|
|
8
|
+
export declare function collectPageFields<TData extends Record<string, unknown>>(layout: FormLayout<TData>, pageIndex: number): FormField<TData>[];
|
|
9
|
+
export declare function getLayoutPageCount<TData extends Record<string, unknown>>(layout: FormLayout<TData>): number;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Ui7FormDensity } from './style-contract';
|
|
2
|
+
import { FormMode, FormSection } from './form-types';
|
|
3
|
+
|
|
4
|
+
export type SchemaFormRendererProps<TData extends Record<string, unknown>> = {
|
|
5
|
+
mode: FormMode;
|
|
6
|
+
value: TData;
|
|
7
|
+
sections: FormSection<TData>[];
|
|
8
|
+
errors?: Partial<Record<keyof TData, string>>;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
onChange?: (patch: Partial<TData>) => void;
|
|
11
|
+
className?: string;
|
|
12
|
+
showSectionHeader?: boolean;
|
|
13
|
+
/** Override the root scope className (includes density + readonly classes). */
|
|
14
|
+
scopeClassName?: string;
|
|
15
|
+
/** Form layout density. Defaults to "compact". */
|
|
16
|
+
density?: Ui7FormDensity;
|
|
17
|
+
};
|
|
18
|
+
export declare function SchemaFormRenderer<TData extends Record<string, unknown>>({ mode, value, sections, errors, disabled, onChange, className, showSectionHeader, scopeClassName, density, }: SchemaFormRendererProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { PhoneRule } from './form-numeric';
|
|
2
|
+
|
|
3
|
+
export type FieldValidatorFn<TData = Record<string, unknown>> = (value: unknown, data: TData) => string | undefined;
|
|
4
|
+
export declare const Rules: {
|
|
5
|
+
readonly email: (msg?: string) => FieldValidatorFn;
|
|
6
|
+
readonly url: (msg?: string) => FieldValidatorFn;
|
|
7
|
+
readonly nik: (msg?: string) => FieldValidatorFn;
|
|
8
|
+
readonly kodePos: (msg?: string) => FieldValidatorFn;
|
|
9
|
+
readonly phone: (rule: PhoneRule, msg?: string) => FieldValidatorFn;
|
|
10
|
+
readonly regex: (pattern: RegExp, msg: string) => FieldValidatorFn;
|
|
11
|
+
};
|
|
12
|
+
export declare function buildValidator<TData extends Record<string, unknown>>(crossField: (form: TData) => Partial<Record<keyof TData, string>>): (form: TData) => Partial<Record<keyof TData, string>>;
|