@ph-cms/client-sdk 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PH-CMS contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,72 @@
1
+ # @ph-cms/client-sdk
2
+
3
+ Unified PH-CMS client SDK for browser and React applications.
4
+
5
+ This package is intended to be published to npm and provides:
6
+
7
+ - A typed API client
8
+ - Auth provider interfaces and implementations
9
+ - React context and hooks for consuming the client in UI code
10
+
11
+ ## Installation
12
+
13
+ Install the SDK itself with its runtime dependencies:
14
+
15
+ ```bash
16
+ npm install @ph-cms/client-sdk @ph-cms/api-contract axios zod
17
+ ```
18
+
19
+ If you use the React bindings, also install the peer dependencies:
20
+
21
+ ```bash
22
+ npm install react @tanstack/react-query
23
+ ```
24
+
25
+ If you use Firebase auth integration:
26
+
27
+ ```bash
28
+ npm install firebase
29
+ ```
30
+
31
+ ## Usage
32
+
33
+ ```ts
34
+ import { PHCMSClient } from '@ph-cms/client-sdk';
35
+
36
+ const client = new PHCMSClient({
37
+ baseURL: 'https://api.example.com',
38
+ });
39
+
40
+ const contents = await client.content.list({
41
+ page: 1,
42
+ limit: 20,
43
+ });
44
+ ```
45
+
46
+ ## React Usage
47
+
48
+ `react` and `@tanstack/react-query` are peer dependencies, so your application must provide them.
49
+
50
+ ```tsx
51
+ import { PHCMSClient, PHCMSProvider, usePHCMS } from '@ph-cms/client-sdk';
52
+
53
+ const client = new PHCMSClient({ baseURL: 'https://api.example.com' });
54
+
55
+ function ContentCount() {
56
+ const sdk = usePHCMS();
57
+ // Use sdk.content / sdk.auth / sdk.channel / sdk.terms here.
58
+ return null;
59
+ }
60
+
61
+ export function App() {
62
+ return (
63
+ <PHCMSProvider client={client}>
64
+ <ContentCount />
65
+ </PHCMSProvider>
66
+ );
67
+ }
68
+ ```
69
+
70
+ ## License
71
+
72
+ MIT
@@ -0,0 +1,17 @@
1
+ import { AuthProvider } from "./interfaces";
2
+ import type { Auth } from "firebase/auth";
3
+ export declare class FirebaseAuthProvider implements AuthProvider {
4
+ private readonly auth;
5
+ private readonly storageKeyPrefix;
6
+ readonly type = "FIREBASE";
7
+ private accessToken;
8
+ private refreshToken;
9
+ private onExpiredCallback;
10
+ constructor(auth: Auth, storageKeyPrefix?: string);
11
+ setTokens(accessToken: string, refreshToken: string): void;
12
+ getToken(): Promise<string | null>;
13
+ onTokenExpired(callback: () => Promise<void>): void;
14
+ logout(): Promise<void>;
15
+ getRefreshToken(): string | null;
16
+ getIdToken(): Promise<string | null>;
17
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FirebaseAuthProvider = void 0;
4
+ class FirebaseAuthProvider {
5
+ constructor(auth, storageKeyPrefix = 'ph_cms_fb_') {
6
+ this.auth = auth;
7
+ this.storageKeyPrefix = storageKeyPrefix;
8
+ this.type = 'FIREBASE';
9
+ this.accessToken = null;
10
+ this.refreshToken = null;
11
+ this.onExpiredCallback = null;
12
+ if (typeof window !== 'undefined') {
13
+ this.accessToken = localStorage.getItem(`${this.storageKeyPrefix}access_token`);
14
+ this.refreshToken = localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);
15
+ }
16
+ }
17
+ setTokens(accessToken, refreshToken) {
18
+ this.accessToken = accessToken;
19
+ this.refreshToken = refreshToken;
20
+ if (typeof window !== 'undefined') {
21
+ localStorage.setItem(`${this.storageKeyPrefix}access_token`, accessToken);
22
+ localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);
23
+ }
24
+ }
25
+ async getToken() {
26
+ // If we have a local access token, use it for PH-CMS API calls.
27
+ if (this.accessToken) {
28
+ return this.accessToken;
29
+ }
30
+ // Fallback to Firebase ID token if no local token is set yet.
31
+ // This might be useful if the server starts supporting Firebase tokens directly
32
+ // or for the initial exchange call if we want to automate it (though currently it's manual).
33
+ const user = this.auth.currentUser;
34
+ if (!user)
35
+ return null;
36
+ return user.getIdToken();
37
+ }
38
+ onTokenExpired(callback) {
39
+ this.onExpiredCallback = callback;
40
+ }
41
+ async logout() {
42
+ this.accessToken = null;
43
+ this.refreshToken = null;
44
+ if (typeof window !== 'undefined') {
45
+ localStorage.removeItem(`${this.storageKeyPrefix}access_token`);
46
+ localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);
47
+ }
48
+ await this.auth.signOut();
49
+ }
50
+ getRefreshToken() {
51
+ return this.refreshToken;
52
+ }
53
+ async getIdToken() {
54
+ const user = this.auth.currentUser;
55
+ if (!user)
56
+ return null;
57
+ return user.getIdToken();
58
+ }
59
+ }
60
+ exports.FirebaseAuthProvider = FirebaseAuthProvider;
@@ -0,0 +1,16 @@
1
+ export interface AuthProvider {
2
+ type: 'FIREBASE' | 'LOCAL';
3
+ /**
4
+ * Returns the current valid access token.
5
+ * Should handle refreshing if necessary (or return null/throw if expired and can't refresh).
6
+ */
7
+ getToken(): Promise<string | null>;
8
+ /**
9
+ * Sets a callback to be called when the token is known to be expired by the external world (e.g. 401 response).
10
+ */
11
+ onTokenExpired(callback: () => Promise<void>): void;
12
+ /**
13
+ * Clears the session.
14
+ */
15
+ logout(): Promise<void>;
16
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,18 @@
1
+ import { AuthProvider } from "./interfaces";
2
+ export declare class LocalAuthProvider implements AuthProvider {
3
+ private readonly storageKeyPrefix;
4
+ private readonly refreshFn?;
5
+ readonly type = "LOCAL";
6
+ private accessToken;
7
+ private refreshToken;
8
+ private onExpiredCallback;
9
+ constructor(storageKeyPrefix?: string, refreshFn?: ((refreshToken: string) => Promise<{
10
+ accessToken: string;
11
+ refreshToken: string;
12
+ }>) | undefined);
13
+ setTokens(accessToken: string, refreshToken: string): void;
14
+ getToken(): Promise<string | null>;
15
+ onTokenExpired(callback: () => Promise<void>): void;
16
+ logout(): Promise<void>;
17
+ getRefreshToken(): string | null;
18
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalAuthProvider = void 0;
4
+ class LocalAuthProvider {
5
+ constructor(storageKeyPrefix = 'ph_cms_', refreshFn) {
6
+ this.storageKeyPrefix = storageKeyPrefix;
7
+ this.refreshFn = refreshFn;
8
+ this.type = 'LOCAL';
9
+ this.accessToken = null;
10
+ this.refreshToken = null;
11
+ this.onExpiredCallback = null;
12
+ if (typeof window !== 'undefined') {
13
+ this.accessToken = localStorage.getItem(`${this.storageKeyPrefix}access_token`);
14
+ this.refreshToken = localStorage.getItem(`${this.storageKeyPrefix}refresh_token`);
15
+ }
16
+ }
17
+ setTokens(accessToken, refreshToken) {
18
+ this.accessToken = accessToken;
19
+ this.refreshToken = refreshToken;
20
+ if (typeof window !== 'undefined') {
21
+ localStorage.setItem(`${this.storageKeyPrefix}access_token`, accessToken);
22
+ localStorage.setItem(`${this.storageKeyPrefix}refresh_token`, refreshToken);
23
+ }
24
+ }
25
+ async getToken() {
26
+ // Ideally check expiration here using jwt-decode, but for now return what we have.
27
+ // If it's expired, the API will return 401, triggering the interceptor which calls onTokenExpired.
28
+ return this.accessToken;
29
+ }
30
+ onTokenExpired(callback) {
31
+ this.onExpiredCallback = callback;
32
+ }
33
+ async logout() {
34
+ this.accessToken = null;
35
+ this.refreshToken = null;
36
+ if (typeof window !== 'undefined') {
37
+ localStorage.removeItem(`${this.storageKeyPrefix}access_token`);
38
+ localStorage.removeItem(`${this.storageKeyPrefix}refresh_token`);
39
+ }
40
+ }
41
+ // Helper for the client to trigger refresh manually if needed
42
+ getRefreshToken() {
43
+ return this.refreshToken;
44
+ }
45
+ }
46
+ exports.LocalAuthProvider = LocalAuthProvider;
@@ -0,0 +1,21 @@
1
+ import { AxiosInstance } from 'axios';
2
+ import { AuthProvider } from './auth/interfaces';
3
+ import { AuthModule } from './modules/auth';
4
+ import { ContentModule } from './modules/content';
5
+ import { ChannelModule } from './modules/channel';
6
+ import { TermsModule } from './modules/terms';
7
+ export interface PHCMSClientConfig {
8
+ baseURL: string;
9
+ apiPrefix?: string;
10
+ auth?: AuthProvider;
11
+ timeout?: number;
12
+ }
13
+ export declare class PHCMSClient {
14
+ private config;
15
+ readonly axiosInstance: AxiosInstance;
16
+ readonly auth: AuthModule;
17
+ readonly content: ContentModule;
18
+ readonly channel: ChannelModule;
19
+ readonly terms: TermsModule;
20
+ constructor(config: PHCMSClientConfig);
21
+ }
package/dist/client.js ADDED
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.PHCMSClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const errors_1 = require("./errors");
9
+ const auth_1 = require("./modules/auth");
10
+ const content_1 = require("./modules/content");
11
+ const channel_1 = require("./modules/channel");
12
+ const terms_1 = require("./modules/terms");
13
+ class PHCMSClient {
14
+ constructor(config) {
15
+ this.config = config;
16
+ const normalizedApiPrefix = `/${(config.apiPrefix || '/api').replace(/^\/+|\/+$/g, '')}`;
17
+ this.axiosInstance = axios_1.default.create({
18
+ baseURL: config.baseURL,
19
+ timeout: config.timeout || 10000,
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ },
23
+ });
24
+ // Request Interceptor: Add Auth Token
25
+ this.axiosInstance.interceptors.request.use(async (reqConfig) => {
26
+ if (typeof reqConfig.url === 'string') {
27
+ if (reqConfig.url === '/api') {
28
+ reqConfig.url = normalizedApiPrefix;
29
+ }
30
+ else if (reqConfig.url.startsWith('/api/')) {
31
+ reqConfig.url = `${normalizedApiPrefix}${reqConfig.url.slice('/api'.length)}`;
32
+ }
33
+ }
34
+ if (this.config.auth) {
35
+ const token = await this.config.auth.getToken();
36
+ if (token) {
37
+ reqConfig.headers.Authorization = `Bearer ${token}`;
38
+ }
39
+ }
40
+ return reqConfig;
41
+ });
42
+ // Response Interceptor: Unwrap Data & Handle Errors
43
+ this.axiosInstance.interceptors.response.use((response) => {
44
+ // Return the data directly, stripping Axios wrapper
45
+ return response.data;
46
+ }, async (error) => {
47
+ if (error.response) {
48
+ // Server responded with a status code outside 2xx
49
+ const { status, data } = error.response;
50
+ const message = data?.message || error.message;
51
+ // Handle 401 Token Expiry if provider supports it
52
+ if (status === 401 && this.config.auth) {
53
+ // Logic to handle token refresh could be here or triggered by the app.
54
+ // For now just throw.
55
+ }
56
+ throw new errors_1.ApiError(message, status, data);
57
+ }
58
+ else if (error.request) {
59
+ // Request made but no response
60
+ throw new errors_1.PHCMSError('No response received from server');
61
+ }
62
+ else {
63
+ // Something happened in setting up the request
64
+ throw new errors_1.PHCMSError(error.message);
65
+ }
66
+ });
67
+ // Initialize Modules
68
+ this.auth = new auth_1.AuthModule(this.axiosInstance, config.auth);
69
+ this.content = new content_1.ContentModule(this.axiosInstance);
70
+ this.channel = new channel_1.ChannelModule(this.axiosInstance);
71
+ this.terms = new terms_1.TermsModule(this.axiosInstance);
72
+ }
73
+ }
74
+ exports.PHCMSClient = PHCMSClient;
@@ -0,0 +1,8 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { PHCMSClient } from './client';
3
+ export interface PHCMSProviderProps {
4
+ client: PHCMSClient;
5
+ children: ReactNode;
6
+ }
7
+ export declare const PHCMSProvider: React.FC<PHCMSProviderProps>;
8
+ export declare const usePHCMS: () => PHCMSClient;
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.usePHCMS = exports.PHCMSProvider = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const PHCMSContext = (0, react_1.createContext)(null);
39
+ const PHCMSProvider = ({ client, children }) => {
40
+ return (react_1.default.createElement(PHCMSContext.Provider, { value: { client } }, children));
41
+ };
42
+ exports.PHCMSProvider = PHCMSProvider;
43
+ const usePHCMS = () => {
44
+ const context = (0, react_1.useContext)(PHCMSContext);
45
+ if (!context) {
46
+ throw new Error('usePHCMS must be used within a PHCMSProvider');
47
+ }
48
+ return context.client;
49
+ };
50
+ exports.usePHCMS = usePHCMS;
@@ -0,0 +1,12 @@
1
+ export declare class PHCMSError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class ValidationError extends PHCMSError {
5
+ errors: any[];
6
+ constructor(message: string, errors: any[]);
7
+ }
8
+ export declare class ApiError extends PHCMSError {
9
+ statusCode: number;
10
+ originalError: any;
11
+ constructor(message: string, statusCode: number, originalError: any);
12
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiError = exports.ValidationError = exports.PHCMSError = void 0;
4
+ class PHCMSError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = 'PHCMSError';
8
+ }
9
+ }
10
+ exports.PHCMSError = PHCMSError;
11
+ class ValidationError extends PHCMSError {
12
+ constructor(message, errors) {
13
+ super(message);
14
+ this.name = 'ValidationError';
15
+ this.errors = errors;
16
+ }
17
+ }
18
+ exports.ValidationError = ValidationError;
19
+ class ApiError extends PHCMSError {
20
+ constructor(message, statusCode, originalError) {
21
+ super(message);
22
+ this.name = 'ApiError';
23
+ this.statusCode = statusCode;
24
+ this.originalError = originalError;
25
+ }
26
+ }
27
+ exports.ApiError = ApiError;
@@ -0,0 +1,98 @@
1
+ export declare const useLogin: () => import("@tanstack/react-query").UseMutationResult<{
2
+ refreshToken: string;
3
+ user: {
4
+ uid: string;
5
+ email: string;
6
+ username: string | null;
7
+ display_name: string;
8
+ avatar_url: string | null;
9
+ phone_number: string | null;
10
+ email_verified_at: string | null;
11
+ phone_verified_at: string | null;
12
+ locale: string;
13
+ timezone: string;
14
+ status: string;
15
+ role: string[];
16
+ profile_data: Record<string, any>;
17
+ last_login_at: string | null;
18
+ created_at: string;
19
+ updated_at: string;
20
+ };
21
+ accessToken: string;
22
+ }, Error, {
23
+ email: string;
24
+ password: string;
25
+ }, unknown>;
26
+ export declare const useLoginWithFirebase: () => import("@tanstack/react-query").UseMutationResult<{
27
+ refreshToken: string;
28
+ user: {
29
+ uid: string;
30
+ email: string;
31
+ username: string | null;
32
+ display_name: string;
33
+ avatar_url: string | null;
34
+ phone_number: string | null;
35
+ email_verified_at: string | null;
36
+ phone_verified_at: string | null;
37
+ locale: string;
38
+ timezone: string;
39
+ status: string;
40
+ role: string[];
41
+ profile_data: Record<string, any>;
42
+ last_login_at: string | null;
43
+ created_at: string;
44
+ updated_at: string;
45
+ };
46
+ accessToken: string;
47
+ }, Error, {
48
+ idToken: string;
49
+ }, unknown>;
50
+ export declare const useRegister: () => import("@tanstack/react-query").UseMutationResult<{
51
+ refreshToken: string;
52
+ user: {
53
+ uid: string;
54
+ email: string;
55
+ username: string | null;
56
+ display_name: string;
57
+ avatar_url: string | null;
58
+ phone_number: string | null;
59
+ email_verified_at: string | null;
60
+ phone_verified_at: string | null;
61
+ locale: string;
62
+ timezone: string;
63
+ status: string;
64
+ role: string[];
65
+ profile_data: Record<string, any>;
66
+ last_login_at: string | null;
67
+ created_at: string;
68
+ updated_at: string;
69
+ };
70
+ accessToken: string;
71
+ }, Error, {
72
+ email: string;
73
+ display_name: string;
74
+ username?: string | null | undefined;
75
+ password?: string | undefined;
76
+ provider?: string | undefined;
77
+ provider_subject?: string | undefined;
78
+ termCodes?: string[] | undefined;
79
+ }, unknown>;
80
+ export declare const useLogout: () => import("@tanstack/react-query").UseMutationResult<void, Error, void, unknown>;
81
+ export declare const useUser: () => import("@tanstack/react-query").UseQueryResult<{
82
+ uid: string;
83
+ email: string;
84
+ username: string | null;
85
+ display_name: string;
86
+ avatar_url: string | null;
87
+ phone_number: string | null;
88
+ email_verified_at: string | null;
89
+ phone_verified_at: string | null;
90
+ locale: string;
91
+ timezone: string;
92
+ status: string;
93
+ role: string[];
94
+ profile_data: Record<string, any>;
95
+ last_login_at: string | null;
96
+ created_at: string;
97
+ updated_at: string;
98
+ }, Error>;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useUser = exports.useLogout = exports.useRegister = exports.useLoginWithFirebase = exports.useLogin = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const context_1 = require("../context");
6
+ const useLogin = () => {
7
+ const client = (0, context_1.usePHCMS)();
8
+ const queryClient = (0, react_query_1.useQueryClient)();
9
+ return (0, react_query_1.useMutation)({
10
+ mutationFn: (data) => client.auth.login(data),
11
+ onSuccess: (data) => {
12
+ // Invalidate user query to fetch fresh user data
13
+ queryClient.invalidateQueries({ queryKey: ['auth', 'me'] });
14
+ },
15
+ });
16
+ };
17
+ exports.useLogin = useLogin;
18
+ const useLoginWithFirebase = () => {
19
+ const client = (0, context_1.usePHCMS)();
20
+ const queryClient = (0, react_query_1.useQueryClient)();
21
+ return (0, react_query_1.useMutation)({
22
+ mutationFn: (data) => client.auth.loginWithFirebase(data),
23
+ onSuccess: (data) => {
24
+ // Invalidate user query to fetch fresh user data
25
+ queryClient.invalidateQueries({ queryKey: ['auth', 'me'] });
26
+ },
27
+ });
28
+ };
29
+ exports.useLoginWithFirebase = useLoginWithFirebase;
30
+ const useRegister = () => {
31
+ const client = (0, context_1.usePHCMS)();
32
+ const queryClient = (0, react_query_1.useQueryClient)();
33
+ return (0, react_query_1.useMutation)({
34
+ mutationFn: (data) => client.auth.register(data),
35
+ onSuccess: () => {
36
+ queryClient.invalidateQueries({ queryKey: ['auth', 'me'] });
37
+ },
38
+ });
39
+ };
40
+ exports.useRegister = useRegister;
41
+ const useLogout = () => {
42
+ const client = (0, context_1.usePHCMS)();
43
+ const queryClient = (0, react_query_1.useQueryClient)();
44
+ return (0, react_query_1.useMutation)({
45
+ mutationFn: () => client.auth.logout(),
46
+ onSuccess: () => {
47
+ queryClient.setQueryData(['auth', 'me'], null);
48
+ queryClient.invalidateQueries();
49
+ },
50
+ });
51
+ };
52
+ exports.useLogout = useLogout;
53
+ const useUser = () => {
54
+ const client = (0, context_1.usePHCMS)();
55
+ return (0, react_query_1.useQuery)({
56
+ queryKey: ['auth', 'me'],
57
+ queryFn: () => client.auth.me(),
58
+ retry: false, // Don't retry if 401
59
+ staleTime: 1000 * 60 * 5, // 5 minutes
60
+ });
61
+ };
62
+ exports.useUser = useUser;
@@ -0,0 +1,65 @@
1
+ import { ListChannelQuery } from '@ph-cms/api-contract';
2
+ export declare const channelKeys: {
3
+ all: readonly ["channels"];
4
+ lists: () => readonly ["channels", "list"];
5
+ list: (params: ListChannelQuery) => readonly ["channels", "list", {
6
+ status?: string | undefined;
7
+ limit?: number | undefined;
8
+ offset?: number | undefined;
9
+ ownerUid?: string | undefined;
10
+ }];
11
+ };
12
+ export declare const useChannelList: (params: ListChannelQuery) => import("@tanstack/react-query").UseQueryResult<{
13
+ items: {
14
+ uid: string;
15
+ status: string;
16
+ created_at: string;
17
+ updated_at: string;
18
+ name: string;
19
+ description: string | null;
20
+ slug: string;
21
+ hierarchySet: {
22
+ uid: string;
23
+ created_at: string;
24
+ updated_at: string;
25
+ name: string;
26
+ description: string | null;
27
+ } | null;
28
+ permissionPolicySet: {
29
+ uid: string;
30
+ name: string;
31
+ description: string | null;
32
+ } | null;
33
+ }[];
34
+ total: number;
35
+ page: number;
36
+ limit: number;
37
+ totalPages: number;
38
+ }, Error>;
39
+ export declare const useCreateChannel: () => import("@tanstack/react-query").UseMutationResult<{
40
+ uid: string;
41
+ status: string;
42
+ created_at: string;
43
+ updated_at: string;
44
+ name: string;
45
+ description: string | null;
46
+ slug: string;
47
+ hierarchySet: {
48
+ uid: string;
49
+ created_at: string;
50
+ updated_at: string;
51
+ name: string;
52
+ description: string | null;
53
+ } | null;
54
+ permissionPolicySet: {
55
+ uid: string;
56
+ name: string;
57
+ description: string | null;
58
+ } | null;
59
+ }, Error, {
60
+ name: string;
61
+ slug: string;
62
+ hierarchySetUid: string;
63
+ description?: string | undefined;
64
+ permissionPolicySetUid?: string | undefined;
65
+ }, unknown>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useCreateChannel = exports.useChannelList = exports.channelKeys = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const context_1 = require("../context");
6
+ exports.channelKeys = {
7
+ all: ['channels'],
8
+ lists: () => [...exports.channelKeys.all, 'list'],
9
+ list: (params) => [...exports.channelKeys.lists(), params],
10
+ };
11
+ const useChannelList = (params) => {
12
+ const client = (0, context_1.usePHCMS)();
13
+ return (0, react_query_1.useQuery)({
14
+ queryKey: exports.channelKeys.list(params),
15
+ queryFn: () => client.channel.list(params),
16
+ staleTime: 1000 * 60 * 5, // 5 minutes
17
+ });
18
+ };
19
+ exports.useChannelList = useChannelList;
20
+ const useCreateChannel = () => {
21
+ const client = (0, context_1.usePHCMS)();
22
+ const queryClient = (0, react_query_1.useQueryClient)();
23
+ return (0, react_query_1.useMutation)({
24
+ mutationFn: (data) => client.channel.create(data),
25
+ onSuccess: () => {
26
+ queryClient.invalidateQueries({ queryKey: exports.channelKeys.lists() });
27
+ },
28
+ });
29
+ };
30
+ exports.useCreateChannel = useCreateChannel;
@@ -0,0 +1,71 @@
1
+ import { UpdateContentRequest, ListContentQuery, ContentDto, BoundsQuery } from '@ph-cms/api-contract';
2
+ export declare const contentKeys: {
3
+ all: readonly ["contents"];
4
+ lists: () => readonly ["contents", "list"];
5
+ list: (params: ListContentQuery) => readonly ["contents", "list", {
6
+ page: number;
7
+ limit: number;
8
+ status?: string | undefined;
9
+ type?: string | undefined;
10
+ tags?: string[] | undefined;
11
+ channelUid?: string | undefined;
12
+ channelSlug?: string | undefined;
13
+ parentUid?: string | undefined;
14
+ rootUid?: string | undefined;
15
+ keyword?: string | undefined;
16
+ orderBy?: "created_at" | "updated_at" | "published_at" | "title" | "view_count" | "like_count" | undefined;
17
+ orderDir?: "asc" | "desc" | undefined;
18
+ withDetail?: boolean | undefined;
19
+ includeDeleted?: boolean | undefined;
20
+ }];
21
+ geoLists: () => readonly ["contents", "geo-list"];
22
+ geoList: (bounds: BoundsQuery) => readonly ["contents", "geo-list", {
23
+ minLat: number;
24
+ maxLat: number;
25
+ minLng: number;
26
+ maxLng: number;
27
+ }];
28
+ details: () => readonly ["contents", "detail"];
29
+ detail: (uid: string) => readonly ["contents", "detail", string];
30
+ };
31
+ export declare const useContentList: (params: ListContentQuery, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<{
32
+ number: number;
33
+ totalPages: number;
34
+ size: number;
35
+ content: ContentDto[];
36
+ totalElements: number;
37
+ first: boolean;
38
+ last: boolean;
39
+ empty: boolean;
40
+ }, Error>;
41
+ export declare const useContentGeoList: (bounds: BoundsQuery) => import("@tanstack/react-query").UseQueryResult<ContentDto[], Error>;
42
+ export declare const useContentDetail: (uid: string) => import("@tanstack/react-query").UseQueryResult<ContentDto, Error>;
43
+ export declare const useCreateContent: () => import("@tanstack/react-query").UseMutationResult<ContentDto, Error, {
44
+ type: string;
45
+ title: string;
46
+ status?: string | undefined;
47
+ geometry?: {
48
+ type: "Point" | "LineString" | "Polygon" | "MultiPoint" | "MultiLineString" | "MultiPolygon" | "GeometryCollection" | "Feature" | "FeatureCollection";
49
+ coordinates?: any[] | undefined;
50
+ geometries?: any[] | undefined;
51
+ features?: any[] | undefined;
52
+ properties?: Record<string, any> | undefined;
53
+ geometry?: any;
54
+ } | undefined;
55
+ image?: string | null | undefined;
56
+ text?: string | null | undefined;
57
+ attributes?: Record<string, any> | undefined;
58
+ summary?: string | null | undefined;
59
+ slug?: string | null | undefined;
60
+ tags?: string[] | undefined;
61
+ channelUid?: string | undefined;
62
+ channelSlug?: string | undefined;
63
+ parentUid?: string | undefined;
64
+ sortOrder?: number | undefined;
65
+ mediaAttachments?: string[] | undefined;
66
+ }, unknown>;
67
+ export declare const useUpdateContent: () => import("@tanstack/react-query").UseMutationResult<ContentDto, Error, {
68
+ uid: string;
69
+ data: UpdateContentRequest;
70
+ }, unknown>;
71
+ export declare const useDeleteContent: () => import("@tanstack/react-query").UseMutationResult<void, Error, string, unknown>;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useDeleteContent = exports.useUpdateContent = exports.useCreateContent = exports.useContentDetail = exports.useContentGeoList = exports.useContentList = exports.contentKeys = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const context_1 = require("../context");
6
+ exports.contentKeys = {
7
+ all: ['contents'],
8
+ lists: () => [...exports.contentKeys.all, 'list'],
9
+ list: (params) => [...exports.contentKeys.lists(), params],
10
+ geoLists: () => [...exports.contentKeys.all, 'geo-list'],
11
+ geoList: (bounds) => [...exports.contentKeys.geoLists(), bounds],
12
+ details: () => [...exports.contentKeys.all, 'detail'],
13
+ detail: (uid) => [...exports.contentKeys.details(), uid],
14
+ };
15
+ const useContentList = (params, enabled = true) => {
16
+ const client = (0, context_1.usePHCMS)();
17
+ return (0, react_query_1.useQuery)({
18
+ queryKey: exports.contentKeys.list(params),
19
+ queryFn: () => client.content.list(params),
20
+ staleTime: 1000 * 60, // 1 minute
21
+ enabled,
22
+ });
23
+ };
24
+ exports.useContentList = useContentList;
25
+ const useContentGeoList = (bounds) => {
26
+ const client = (0, context_1.usePHCMS)();
27
+ return (0, react_query_1.useQuery)({
28
+ queryKey: exports.contentKeys.geoList(bounds),
29
+ queryFn: () => client.content.listGeo(bounds),
30
+ enabled: !!(bounds.minLat && bounds.maxLat && bounds.minLng && bounds.maxLng),
31
+ });
32
+ };
33
+ exports.useContentGeoList = useContentGeoList;
34
+ const useContentDetail = (uid) => {
35
+ const client = (0, context_1.usePHCMS)();
36
+ return (0, react_query_1.useQuery)({
37
+ queryKey: exports.contentKeys.detail(uid),
38
+ queryFn: () => client.content.get(uid),
39
+ enabled: !!uid,
40
+ });
41
+ };
42
+ exports.useContentDetail = useContentDetail;
43
+ const useCreateContent = () => {
44
+ const client = (0, context_1.usePHCMS)();
45
+ const queryClient = (0, react_query_1.useQueryClient)();
46
+ return (0, react_query_1.useMutation)({
47
+ mutationFn: (data) => client.content.create(data),
48
+ onSuccess: () => {
49
+ queryClient.invalidateQueries({ queryKey: exports.contentKeys.lists() });
50
+ },
51
+ });
52
+ };
53
+ exports.useCreateContent = useCreateContent;
54
+ const useUpdateContent = () => {
55
+ const client = (0, context_1.usePHCMS)();
56
+ const queryClient = (0, react_query_1.useQueryClient)();
57
+ return (0, react_query_1.useMutation)({
58
+ mutationFn: ({ uid, data }) => client.content.update(uid, data),
59
+ onSuccess: (data, variables) => {
60
+ queryClient.invalidateQueries({ queryKey: exports.contentKeys.detail(variables.uid) });
61
+ queryClient.invalidateQueries({ queryKey: exports.contentKeys.lists() });
62
+ },
63
+ });
64
+ };
65
+ exports.useUpdateContent = useUpdateContent;
66
+ const useDeleteContent = () => {
67
+ const client = (0, context_1.usePHCMS)();
68
+ const queryClient = (0, react_query_1.useQueryClient)();
69
+ return (0, react_query_1.useMutation)({
70
+ mutationFn: (uid) => client.content.delete(uid),
71
+ onSuccess: () => {
72
+ queryClient.invalidateQueries({ queryKey: exports.contentKeys.lists() });
73
+ },
74
+ });
75
+ };
76
+ exports.useDeleteContent = useDeleteContent;
@@ -0,0 +1,26 @@
1
+ import { ListTermsQuery } from '@ph-cms/api-contract';
2
+ export declare const termsKeys: {
3
+ all: readonly ["terms"];
4
+ lists: () => readonly ["terms", "list"];
5
+ list: (params?: ListTermsQuery) => readonly ["terms", "list", {
6
+ code?: string | undefined;
7
+ limit?: number | undefined;
8
+ offset?: number | undefined;
9
+ isActive?: boolean | undefined;
10
+ } | undefined];
11
+ };
12
+ export declare const useTermsList: (params?: ListTermsQuery) => import("@tanstack/react-query").UseQueryResult<{
13
+ items: {
14
+ code: string;
15
+ title: string;
16
+ content: string;
17
+ id: number;
18
+ version: string;
19
+ isActive: boolean;
20
+ createdAt: string;
21
+ }[];
22
+ total: number;
23
+ page: number;
24
+ limit: number;
25
+ totalPages: number;
26
+ }, Error>;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useTermsList = exports.termsKeys = void 0;
4
+ const react_query_1 = require("@tanstack/react-query");
5
+ const context_1 = require("../context");
6
+ exports.termsKeys = {
7
+ all: ['terms'],
8
+ lists: () => [...exports.termsKeys.all, 'list'],
9
+ list: (params) => [...exports.termsKeys.lists(), params],
10
+ };
11
+ const useTermsList = (params) => {
12
+ const client = (0, context_1.usePHCMS)();
13
+ return (0, react_query_1.useQuery)({
14
+ queryKey: exports.termsKeys.list(params),
15
+ queryFn: () => client.terms.list(params),
16
+ staleTime: 1000 * 60 * 60, // 1 hour
17
+ });
18
+ };
19
+ exports.useTermsList = useTermsList;
@@ -0,0 +1,15 @@
1
+ export * from './auth/interfaces';
2
+ export * from './auth/local-provider';
3
+ export * from './auth/firebase-provider';
4
+ export * from './errors';
5
+ export * from './client';
6
+ export * from './modules/auth';
7
+ export * from './modules/content';
8
+ export * from './modules/channel';
9
+ export * from './modules/terms';
10
+ export * from './context';
11
+ export * from './hooks/useAuth';
12
+ export * from './hooks/useContent';
13
+ export * from './hooks/useChannel';
14
+ export * from './hooks/useTerms';
15
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./auth/interfaces"), exports);
18
+ __exportStar(require("./auth/local-provider"), exports);
19
+ __exportStar(require("./auth/firebase-provider"), exports);
20
+ __exportStar(require("./errors"), exports);
21
+ __exportStar(require("./client"), exports);
22
+ __exportStar(require("./modules/auth"), exports);
23
+ __exportStar(require("./modules/content"), exports);
24
+ __exportStar(require("./modules/channel"), exports);
25
+ __exportStar(require("./modules/terms"), exports);
26
+ __exportStar(require("./context"), exports);
27
+ __exportStar(require("./hooks/useAuth"), exports);
28
+ __exportStar(require("./hooks/useContent"), exports);
29
+ __exportStar(require("./hooks/useChannel"), exports);
30
+ __exportStar(require("./hooks/useTerms"), exports);
31
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,23 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { AuthProvider } from "../auth/interfaces";
3
+ import { LoginRequest, RegisterRequest, AuthResponse, UserDto, FirebaseExchangeRequest } from "@ph-cms/api-contract";
4
+ export declare class AuthModule {
5
+ private client;
6
+ private provider?;
7
+ constructor(client: AxiosInstance, provider?: AuthProvider | undefined);
8
+ /**
9
+ * Logs in the user and updates the AuthProvider if it's a LocalAuthProvider.
10
+ */
11
+ login(data: LoginRequest): Promise<AuthResponse>;
12
+ /**
13
+ * Exchanges a Firebase ID token for application tokens.
14
+ */
15
+ loginWithFirebase(data: FirebaseExchangeRequest): Promise<AuthResponse>;
16
+ register(data: RegisterRequest): Promise<AuthResponse>;
17
+ me(): Promise<UserDto>;
18
+ refresh(refreshToken: string): Promise<{
19
+ accessToken: string;
20
+ refreshToken: string;
21
+ }>;
22
+ logout(): Promise<void>;
23
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthModule = void 0;
4
+ const api_contract_1 = require("@ph-cms/api-contract");
5
+ const errors_1 = require("../errors");
6
+ class AuthModule {
7
+ constructor(client, provider) {
8
+ this.client = client;
9
+ this.provider = provider;
10
+ }
11
+ /**
12
+ * Logs in the user and updates the AuthProvider if it's a LocalAuthProvider.
13
+ */
14
+ async login(data) {
15
+ const validation = api_contract_1.LoginSchema.safeParse(data);
16
+ if (!validation.success) {
17
+ throw new errors_1.ValidationError("Invalid login data", validation.error.errors);
18
+ }
19
+ const response = await this.client.post('/api/auth/login', data);
20
+ // If using Local Provider, update tokens automatically
21
+ if (this.provider && (this.provider.type === 'LOCAL' || this.provider.type === 'FIREBASE')) {
22
+ // We need to cast to LocalAuthProvider to access setTokens,
23
+ // but strictly speaking we shouldn't assume implementation details here.
24
+ // However, for this SDK, it's a practical coupling.
25
+ // Or we assume the user handles it.
26
+ // Let's assume the user handles it via the response for now,
27
+ // OR we can try to update it if the method exists.
28
+ if ('setTokens' in this.provider) {
29
+ this.provider.setTokens(response.accessToken, response.refreshToken);
30
+ }
31
+ }
32
+ return response;
33
+ }
34
+ /**
35
+ * Exchanges a Firebase ID token for application tokens.
36
+ */
37
+ async loginWithFirebase(data) {
38
+ const validation = api_contract_1.FirebaseExchangeSchema.safeParse(data);
39
+ if (!validation.success) {
40
+ throw new errors_1.ValidationError("Invalid Firebase token data", validation.error.errors);
41
+ }
42
+ const response = await this.client.post('/api/auth/firebase/exchange', data);
43
+ // If using a Provider, update tokens automatically
44
+ if (this.provider && ('setTokens' in this.provider)) {
45
+ this.provider.setTokens(response.accessToken, response.refreshToken);
46
+ }
47
+ return response;
48
+ }
49
+ async register(data) {
50
+ const validation = api_contract_1.RegisterSchema.safeParse(data);
51
+ if (!validation.success) {
52
+ throw new errors_1.ValidationError("Invalid register data", validation.error.errors);
53
+ }
54
+ return this.client.post('/api/auth/register', data);
55
+ }
56
+ async me() {
57
+ return this.client.get('/api/auth/me');
58
+ }
59
+ async refresh(refreshToken) {
60
+ // Validate refreshToken string? It's just a string.
61
+ return this.client.post('/api/auth/refresh', { refreshToken });
62
+ }
63
+ async logout() {
64
+ if (this.provider) {
65
+ await this.provider.logout();
66
+ }
67
+ // Also call API endpoint if needed?
68
+ // Usually client-side logout just clears token.
69
+ // But if we want to invalidate on server (blacklist), we call endpoint.
70
+ // Routes has /api/auth/logout.
71
+ await this.client.post('/api/auth/logout').catch(() => { }); // Ignore error on logout
72
+ }
73
+ }
74
+ exports.AuthModule = AuthModule;
@@ -0,0 +1,15 @@
1
+ import { ChannelDto, CheckHierarchyQuery, CreateChannelDto, ListChannelQuery, PagedChannelListResponse } from "@ph-cms/api-contract";
2
+ import { AxiosInstance } from "axios";
3
+ export declare class ChannelModule {
4
+ private client;
5
+ constructor(client: AxiosInstance);
6
+ list(params: ListChannelQuery): Promise<PagedChannelListResponse>;
7
+ getByUid(uid: string): Promise<ChannelDto>;
8
+ getBySlug(slug: string): Promise<ChannelDto>;
9
+ create(data: CreateChannelDto): Promise<ChannelDto>;
10
+ update(uid: string, data: any): Promise<ChannelDto>;
11
+ checkHierarchy(params: CheckHierarchyQuery): Promise<{
12
+ allowed: boolean;
13
+ message?: string;
14
+ }>;
15
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChannelModule = void 0;
4
+ const api_contract_1 = require("@ph-cms/api-contract");
5
+ const errors_1 = require("../errors");
6
+ class ChannelModule {
7
+ constructor(client) {
8
+ this.client = client;
9
+ }
10
+ async list(params) {
11
+ const validation = api_contract_1.ListChannelQuerySchema.safeParse(params);
12
+ if (!validation.success) {
13
+ throw new errors_1.ValidationError("Invalid list channel params", validation.error.errors);
14
+ }
15
+ return this.client.get('/api/channels', { params });
16
+ }
17
+ async getByUid(uid) {
18
+ if (!uid)
19
+ throw new errors_1.ValidationError("UID is required", []);
20
+ return this.client.get(`/api/channels/u/${uid}`);
21
+ }
22
+ async getBySlug(slug) {
23
+ if (!slug)
24
+ throw new errors_1.ValidationError("Slug is required", []);
25
+ return this.client.get(`/api/channels/s/${slug}`);
26
+ }
27
+ async create(data) {
28
+ const validation = api_contract_1.CreateChannelSchema.safeParse(data);
29
+ if (!validation.success) {
30
+ throw new errors_1.ValidationError("Invalid create channel params", validation.error.errors);
31
+ }
32
+ return this.client.post('/api/channels', data);
33
+ }
34
+ async update(uid, data) {
35
+ // TODO: Add schema validation for update channel
36
+ if (!uid)
37
+ throw new errors_1.ValidationError("UID is required", []);
38
+ return this.client.patch(`/api/channels/u/${uid}`, data);
39
+ }
40
+ async checkHierarchy(params) {
41
+ const validation = api_contract_1.CheckHierarchyQuerySchema.safeParse(params);
42
+ if (!validation.success) {
43
+ throw new errors_1.ValidationError("Invalid check hierarchy params", validation.error.errors);
44
+ }
45
+ return this.client.get('/api/contents/check-hierarchy', { params });
46
+ }
47
+ }
48
+ exports.ChannelModule = ChannelModule;
@@ -0,0 +1,12 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { CreateContentRequest, UpdateContentRequest, ListContentQuery, ContentDto, PagedContentListResponse, BoundsQuery } from "@ph-cms/api-contract";
3
+ export declare class ContentModule {
4
+ private client;
5
+ constructor(client: AxiosInstance);
6
+ list(params: ListContentQuery): Promise<PagedContentListResponse>;
7
+ listGeo(bounds: BoundsQuery): Promise<ContentDto[]>;
8
+ get(uid: string): Promise<ContentDto>;
9
+ create(data: CreateContentRequest): Promise<ContentDto>;
10
+ update(uid: string, data: UpdateContentRequest): Promise<ContentDto>;
11
+ delete(uid: string): Promise<void>;
12
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ContentModule = void 0;
4
+ const api_contract_1 = require("@ph-cms/api-contract");
5
+ const errors_1 = require("../errors");
6
+ class ContentModule {
7
+ constructor(client) {
8
+ this.client = client;
9
+ }
10
+ async list(params) {
11
+ const validation = api_contract_1.ListContentQuerySchema.safeParse(params);
12
+ if (!validation.success) {
13
+ throw new errors_1.ValidationError("Invalid list params", validation.error.errors);
14
+ }
15
+ return this.client.get('/api/contents', { params });
16
+ }
17
+ async listGeo(bounds) {
18
+ const validation = api_contract_1.BoundsQuerySchema.safeParse(bounds);
19
+ if (!validation.success) {
20
+ throw new errors_1.ValidationError("Invalid bounds params", validation.error.errors);
21
+ }
22
+ return this.client.get('/api/contents/geo', { params: bounds });
23
+ }
24
+ async get(uid) {
25
+ if (!uid)
26
+ throw new errors_1.ValidationError("UID is required", []);
27
+ return this.client.get(`/api/contents/${uid}`);
28
+ }
29
+ async create(data) {
30
+ const validation = api_contract_1.CreateContentSchema.safeParse(data);
31
+ if (!validation.success) {
32
+ throw new errors_1.ValidationError("Invalid create content data", validation.error.errors);
33
+ }
34
+ return this.client.post('/api/contents', data);
35
+ }
36
+ async update(uid, data) {
37
+ if (!uid)
38
+ throw new errors_1.ValidationError("UID is required", []);
39
+ const validation = api_contract_1.UpdateContentSchema.safeParse(data);
40
+ if (!validation.success) {
41
+ throw new errors_1.ValidationError("Invalid update content data", validation.error.errors);
42
+ }
43
+ return this.client.put(`/api/contents/${uid}`, data);
44
+ }
45
+ async delete(uid) {
46
+ if (!uid)
47
+ throw new errors_1.ValidationError("UID is required", []);
48
+ return this.client.delete(`/api/contents/${uid}`);
49
+ }
50
+ }
51
+ exports.ContentModule = ContentModule;
@@ -0,0 +1,8 @@
1
+ import { AxiosInstance } from "axios";
2
+ import { TermDto, ListTermsQuery, PagedTermListResponse } from "@ph-cms/api-contract";
3
+ export declare class TermsModule {
4
+ private client;
5
+ constructor(client: AxiosInstance);
6
+ list(params?: ListTermsQuery): Promise<PagedTermListResponse>;
7
+ get(id: number): Promise<TermDto>;
8
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TermsModule = void 0;
4
+ class TermsModule {
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+ async list(params) {
9
+ return this.client.get('/api/terms', { params });
10
+ }
11
+ async get(id) {
12
+ return this.client.get(`/api/terms/${id}`);
13
+ }
14
+ }
15
+ exports.TermsModule = TermsModule;
@@ -0,0 +1 @@
1
+ export * from '@ph-cms/api-contract';
package/dist/types.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("@ph-cms/api-contract"), exports);
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ph-cms/client-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Unified PH-CMS Client SDK (React + Core)",
5
+ "keywords": [],
6
+ "license": "MIT",
7
+ "author": "854dev",
8
+ "type": "commonjs",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "require": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist",
20
+ "README.md",
21
+ "LICENSE"
22
+ ],
23
+ "dependencies": {
24
+ "@ph-cms/api-contract": "^0.1.0",
25
+ "axios": "^1.6.0",
26
+ "zod": "^3.22.4"
27
+ },
28
+ "devDependencies": {
29
+ "@tanstack/react-query": "^5.0.0",
30
+ "@types/react": "^18.3.1",
31
+ "@types/react-dom": "^18.3.1",
32
+ "firebase": "^10.0.0",
33
+ "react": "^18.3.1",
34
+ "react-dom": "^18.3.1",
35
+ "typescript": "^5.3.3"
36
+ },
37
+ "peerDependencies": {
38
+ "@tanstack/react-query": "^5.0.0",
39
+ "react": ">=18.0.0",
40
+ "firebase": "^10.0.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "firebase": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "publishConfig": {
48
+ "access": "public"
49
+ },
50
+ "scripts": {
51
+ "clean": "rm -rf dist",
52
+ "build": "npm run clean && tsc"
53
+ }
54
+ }