@inverted-tech/fragments 0.10.9 → 0.11.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.
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Cross-platform API client utilities
3
+ *
4
+ * Framework-agnostic: works in Next.js (SSR/SSG), browser SPAs, and Node.js.
5
+ * The caller is responsible for resolving the base URL from their environment.
6
+ *
7
+ * @example Next.js
8
+ * ```ts
9
+ * const isServer = typeof window === 'undefined';
10
+ * const baseUrl = isServer
11
+ * ? (process.env.API_BASE_URL ?? process.env.NEXT_PUBLIC_API_BASE_URL ?? '')
12
+ * : (process.env.NEXT_PUBLIC_API_BASE_URL ?? '');
13
+ * export const api = createApiClient(baseUrl);
14
+ * ```
15
+ *
16
+ * @example Vite SPA
17
+ * ```ts
18
+ * export const api = createApiClient(import.meta.env.VITE_API_BASE_URL ?? '');
19
+ * ```
20
+ */
21
+ const DEFAULT_HEADERS = {
22
+ 'Content-Type': 'application/json',
23
+ };
24
+ /**
25
+ * Cross-platform fetch wrapper with error handling.
26
+ *
27
+ * - Merges caller headers on top of the default Content-Type header.
28
+ * - Defaults cache to `no-store` unless `cache` or `next` is explicitly provided
29
+ * (avoids the Next.js 2 MB data-cache write limit).
30
+ * - Passes `next` through transparently for Next.js ISR tag/revalidation support.
31
+ */
32
+ export async function apiCall(url, options = {}) {
33
+ const { next, cache, headers: callerHeaders, ...restOptions } = options;
34
+ const mergedHeaders = {
35
+ ...DEFAULT_HEADERS,
36
+ ...callerHeaders,
37
+ };
38
+ const finalOptions = {
39
+ ...restOptions,
40
+ headers: mergedHeaders,
41
+ };
42
+ // Respect an explicit cache option; otherwise default to no-store to avoid
43
+ // the Next.js 2 MB data-cache limit. Skip the default when `next` is set,
44
+ // since that implies the caller wants ISR caching behaviour.
45
+ if (cache !== undefined) {
46
+ finalOptions['cache'] = cache;
47
+ }
48
+ else if (!next) {
49
+ finalOptions['cache'] = 'no-store';
50
+ }
51
+ if (next !== undefined) {
52
+ finalOptions['next'] = next;
53
+ }
54
+ const response = await fetch(url, finalOptions);
55
+ if (!response.ok) {
56
+ throw new Error(`API call failed: ${response.status} ${response.statusText}`);
57
+ }
58
+ return response.json();
59
+ }
60
+ /**
61
+ * Build the endpoint map for a given base URL.
62
+ * Call once during app initialization with your resolved base URL.
63
+ */
64
+ export function createApiEndpoints(baseUrl) {
65
+ return {
66
+ auth: {
67
+ login: `${baseUrl}/auth/login`,
68
+ logout: `${baseUrl}/auth/logout`,
69
+ createUser: `${baseUrl}/auth/createuser`,
70
+ adminCreateUser: `${baseUrl}/auth/admin/createuser`,
71
+ refresh: `${baseUrl}/auth/renewtoken`,
72
+ changePassword: `${baseUrl}/auth/password`,
73
+ adminChangePassword: `${baseUrl}/auth/admin/password`,
74
+ getCurrentUser: `${baseUrl}/auth/user`,
75
+ editOwnUser: `${baseUrl}/auth/user`,
76
+ getUserById: (userId) => `${baseUrl}/auth/user/${userId}`,
77
+ getUserByName: (userName) => `${baseUrl}/auth/username/${userName}`,
78
+ getUserIds: `${baseUrl}/auth/user/ids`,
79
+ getProfileImage: `${baseUrl}/auth/profileimage`,
80
+ getUserProfileImage: (userId) => `${baseUrl}/auth/user/${userId}/profileimage`,
81
+ uploadProfileImage: `${baseUrl}/auth/profileimage`,
82
+ adminUploadProfileImage: `${baseUrl}/auth/admin/profileimage`,
83
+ totp: `${baseUrl}/auth/totp`,
84
+ disableTotp: (id) => `${baseUrl}/auth/totp/${id}/disable/`,
85
+ verifyTotp: (id) => `${baseUrl}/auth/totp/${id}/verify/`,
86
+ adminGetUsers: `${baseUrl}/auth/admin/user`,
87
+ adminAddUser: `${baseUrl}/auth/admin/user`,
88
+ adminGetUser: (userId) => `${baseUrl}/auth/admin/user/${userId}`,
89
+ adminDisableUser: (userId) => `${baseUrl}/auth/admin/user/${userId}/disable`,
90
+ adminEnableUser: (userId) => `${baseUrl}/auth/admin/user/${userId}/enable`,
91
+ adminSetRoles: `${baseUrl}/auth/admin/user/roles`,
92
+ adminSearch: `${baseUrl}/auth/admin/search`,
93
+ adminGetTotp: (userId) => `${baseUrl}/auth/admin/totp/${userId}`,
94
+ adminCreateTotp: (userId) => `${baseUrl}/auth/admin/totp/${userId}`,
95
+ adminDisableTotp: (userId, totpId) => `${baseUrl}/auth/admin/totp/${userId}/${totpId}/disable`,
96
+ adminVerifyTotp: (userId, totpId) => `${baseUrl}/auth/admin/totp/${userId}/${totpId}/verify`,
97
+ },
98
+ asset: {
99
+ getAssetData: (id) => `${baseUrl}/cms/asset/${id}/data`,
100
+ createAudioAsset: `${baseUrl}/cms/asset/audio`,
101
+ createAsset: `${baseUrl}/cms/admin/asset`,
102
+ getAsset: (id) => `${baseUrl}/cms/asset/${id}`,
103
+ adminGetAsset: (id) => `${baseUrl}/cms/admin/asset/${id}`,
104
+ adminGetAssetByOldId: (id) => `${baseUrl}/cms/admin/asset/old/${id}`,
105
+ adminGetImageAssets: `${baseUrl}/cms/admin/asset/image`,
106
+ searchAssets: `${baseUrl}/cms/admin/asset/search`,
107
+ },
108
+ auditLog: {
109
+ adminGetAuditLog: `${baseUrl}/admin/audit-log`,
110
+ },
111
+ careers: {
112
+ createCareer: `${baseUrl}/admin/careers`,
113
+ getCareersAdmin: `${baseUrl}/admin/careers`,
114
+ getCareer: (id) => `${baseUrl}/careers/${id}`,
115
+ getCareers: `${baseUrl}/careers`,
116
+ adminUpdateCareer: (id) => `${baseUrl}/admin/careers/${id}`,
117
+ adminDeleteCareer: (id) => `${baseUrl}/admin/careers/${id}`,
118
+ },
119
+ category: {
120
+ createCategory: `${baseUrl}/settings/category/create`,
121
+ deleteCategory: (id) => `${baseUrl}/settings/category/delete/${id}`,
122
+ },
123
+ channel: {
124
+ getChannels: `${baseUrl}/settings/channel`,
125
+ createChannel: `${baseUrl}/settings/channel/create`,
126
+ deleteChannel: (id) => `${baseUrl}/settings/channel/delete/${id}`,
127
+ getChannelDetails: (id) => `${baseUrl}/settings/channel/details/${id}`,
128
+ },
129
+ comment: {
130
+ adminDeleteComment: (id) => `${baseUrl}/comment/admin/${id}/delete`,
131
+ adminPinComment: (id) => `${baseUrl}/comment/admin/${id}/pin`,
132
+ adminUndeleteComment: (id) => `${baseUrl}/comment/admin/${id}/undelete`,
133
+ adminUnpinComment: (id) => `${baseUrl}/comment/admin/${id}/unpin`,
134
+ createCommentForContent: (id) => `${baseUrl}/comment/content/${id}/create`,
135
+ createCommentForComment: (id) => `${baseUrl}/comment/${id}/create`,
136
+ deleteOwnComment: (id) => `${baseUrl}/comment/${id}/delete`,
137
+ editOwnComment: (id) => `${baseUrl}/comment/${id}/edit`,
138
+ getCommentForContent: (id) => `${baseUrl}/comment/content/${id}`,
139
+ getCommentsForComment: (id) => `${baseUrl}/comment/${id}`,
140
+ likeComment: (id) => `${baseUrl}/comment/${id}/like`,
141
+ unlikeComment: (id) => `${baseUrl}/comment/${id}/unlike`,
142
+ },
143
+ cms: {
144
+ // Content
145
+ announceContent: (id) => `${baseUrl}/cms/admin/content/${id}/announce`,
146
+ createContent: `${baseUrl}/cms/admin/content`,
147
+ adminListContent: `${baseUrl}/cms/admin/content`,
148
+ deleteContent: (id) => `${baseUrl}/cms/admin/content/${id}`,
149
+ adminGetContentById: (id) => `${baseUrl}/cms/admin/content/${id}`,
150
+ adminUpdateContent: (id) => `${baseUrl}/cms/admin/content/${id}`,
151
+ listContent: `${baseUrl}/cms/content`,
152
+ getContentById: (id) => `${baseUrl}/cms/content/${id}`,
153
+ getContentByUrl: (url) => `${baseUrl}/cms/content/url?ContentUrl=${url}`,
154
+ getRecentCategories: `${baseUrl}/cms/categories/recent`,
155
+ getRecentTags: `${baseUrl}/cms/tags/recent`,
156
+ getContentByChannel: (channelId, pageSize = 10) => `${baseUrl}/cms/content?ChannelIds=[${channelId}]&PageSize=${pageSize}`,
157
+ getRelated: (contentId, pageSize = 5) => `${baseUrl}/cms/content/${contentId}/related/?PageSize=${pageSize}`,
158
+ publishContent: (id) => `${baseUrl}/cms/admin/content/${id}/publish`,
159
+ searchContent: `${baseUrl}/cms/search`,
160
+ unannounceContent: (id) => `${baseUrl}/cms/admin/content/${id}/unannounce`,
161
+ undeleteContent: (id) => `${baseUrl}/cms/admin/content/${id}/undelete`,
162
+ unpublishContent: (id) => `${baseUrl}/cms/admin/content/${id}/unpublish`,
163
+ // Pages
164
+ createPage: `${baseUrl}/cms/admin/page`,
165
+ adminListPages: `${baseUrl}/cms/admin/page`,
166
+ deletePage: (id) => `${baseUrl}/cms/admin/page/${id}`,
167
+ adminGetPageById: (id) => `${baseUrl}/cms/admin/page/${id}`,
168
+ adminUpdatePage: (id) => `${baseUrl}/cms/admin/page/${id}`,
169
+ listPages: `${baseUrl}/cms/page`,
170
+ getPageById: (id) => `${baseUrl}/cms/page/${id}`,
171
+ getPageByUrl: `${baseUrl}/cms/page/url`,
172
+ publishPage: (id) => `${baseUrl}/cms/admin/page/${id}/publish`,
173
+ searchPages: `${baseUrl}/cms/page/search`,
174
+ undeletePage: (id) => `${baseUrl}/cms/admin/page/${id}/undelete`,
175
+ unpublishPage: (id) => `${baseUrl}/cms/admin/page/${id}/unpublish`,
176
+ },
177
+ settings: {
178
+ publicSettings: `${baseUrl}/settings/public`,
179
+ publicSettingsNewer: (version) => `${baseUrl}/settings/public/newer/${version}`,
180
+ adminSettings: `${baseUrl}/settings/admin`,
181
+ adminSettingsNewer: (version) => `${baseUrl}/settings/admin/newer/${version}`,
182
+ ownerSettings: `${baseUrl}/settings/owner`,
183
+ ownerSettingsNewer: (version) => `${baseUrl}/settings/owner/newer/${version}`,
184
+ channels: `${baseUrl}/settings/channel`,
185
+ channelById: (channelId) => `${baseUrl}/settings/channels/details/${channelId}`,
186
+ saveCmsPublic: `${baseUrl}/settings/cms/public`,
187
+ saveCmsPrivate: `${baseUrl}/settings/cms/private`,
188
+ saveCmsOwner: `${baseUrl}/settings/cms/owner`,
189
+ savePersonalizationPublic: `${baseUrl}/settings/personalization/public`,
190
+ savePersonalizationPrivate: `${baseUrl}/settings/personalization/private`,
191
+ savePersonalizationOwner: `${baseUrl}/settings/personalization/owner`,
192
+ saveSubscriptionPublic: `${baseUrl}/settings/subscription/public`,
193
+ saveSubscriptionPrivate: `${baseUrl}/settings/subscription/private`,
194
+ saveSubscriptionOwner: `${baseUrl}/settings/subscription/owner`,
195
+ saveCommentsPublic: `${baseUrl}/settings/comments/public`,
196
+ saveCommentsPrivate: `${baseUrl}/settings/comments/private`,
197
+ saveCommentsOwner: `${baseUrl}/settings/comments/owner`,
198
+ saveNotificationPublic: `${baseUrl}/settings/notification/public`,
199
+ saveNotificationPrivate: `${baseUrl}/settings/notification/private`,
200
+ saveNotificationOwner: `${baseUrl}/settings/notification/owner`,
201
+ saveEventsPublic: `${baseUrl}/settings/events/public`,
202
+ saveEventsPrivate: `${baseUrl}/settings/events/private`,
203
+ saveEventsOwner: `${baseUrl}/settings/events/owner`,
204
+ },
205
+ dashboard: {
206
+ getDashboard: `${baseUrl}/admin/dashboard`,
207
+ },
208
+ events: {
209
+ getEvent: (eventId) => `${baseUrl}/events/${eventId}`,
210
+ getEvents: `${baseUrl}/events`,
211
+ getTicket: (eventId, ticketId) => `${baseUrl}/events/${eventId}/tickets/${ticketId}`,
212
+ getTickets: (eventId) => `${baseUrl}/events/${eventId}/tickets`,
213
+ cancelTicket: (eventId, ticketId) => `${baseUrl}/events/${eventId}/tickets/${ticketId}/cancel`,
214
+ reserveTicket: (eventId) => `${baseUrl}/events/${eventId}/tickets/reserve`,
215
+ useTicket: `${baseUrl}/events/tickets/use`,
216
+ },
217
+ adminEvents: {
218
+ createEvent: `${baseUrl}/admin/events/create`,
219
+ createRecurringEvent: `${baseUrl}/admin/events/create-recurring`,
220
+ getEvent: (eventId) => `${baseUrl}/admin/events/${eventId}`,
221
+ getEvents: `${baseUrl}/admin/events`,
222
+ modifyEvent: `${baseUrl}/admin/events/modify`,
223
+ cancelEvent: `${baseUrl}/admin/events/cancel`,
224
+ cancelAllRecurring: `${baseUrl}/admin/events/cancel-all-recurring`,
225
+ getTicket: (eventId, ticketId) => `${baseUrl}/admin/events/${eventId}/tickets/${ticketId}`,
226
+ getTickets: (eventId) => `${baseUrl}/admin/events/${eventId}/tickets`,
227
+ cancelTicket: (eventId, ticketId) => `${baseUrl}/admin/events/${eventId}/tickets/${ticketId}/cancel`,
228
+ reserveTicket: (eventId) => `${baseUrl}/admin/events/${eventId}/tickets/reserve`,
229
+ },
230
+ payments: {
231
+ getSubscriptions: `${baseUrl}/payment/subscription`,
232
+ getSubscriptionById: (id) => `${baseUrl}/payment/subscription/${id}`,
233
+ reconcileSubscription: `${baseUrl}/payment/subscription/reconcile`,
234
+ newSubscription: (level, postalCode, successUrl, cancelUrl) => `${baseUrl}/payment/new/${level}?PostalCode=${postalCode}&SuccessUrl=${successUrl}&CancelUrl=${cancelUrl}`,
235
+ cancelSubscription: `${baseUrl}/payment/subscription/cancel`,
236
+ getSinglePayments: `${baseUrl}/payment/single`,
237
+ getSinglePayment: (id) => `${baseUrl}/payment/single/${id}`,
238
+ newSinglePayment: `${baseUrl}/payment/single/new`,
239
+ finishStripe: `${baseUrl}/payment/stripe/subscription/finish`,
240
+ finishFortis: `${baseUrl}/payment/fortis/subscription/finish`,
241
+ newPaypal: `${baseUrl}/payment/paypal/subscription/new`,
242
+ },
243
+ adminPayments: {
244
+ bulkCancel: `${baseUrl}/payment/admin/bulk/cancel`,
245
+ bulkStart: `${baseUrl}/payment/admin/bulk/start`,
246
+ getBulk: `${baseUrl}/payment/admin/bulk`,
247
+ cancelUserSubscription: (userId, subscriptionId) => `${baseUrl}/payment/admin/user/${userId}/subscription/${subscriptionId}/cancel`,
248
+ getUserSubscription: (userId, subscriptionId) => `${baseUrl}/payment/admin/user/${userId}/subscription/${subscriptionId}`,
249
+ getUserSubscriptions: (userId) => `${baseUrl}/payment/admin/user/${userId}/subscription`,
250
+ getUserSinglePayment: (userId, paymentId) => `${baseUrl}/payment/admin/user/${userId}/single/${paymentId}`,
251
+ getUserSinglePayments: (userId) => `${baseUrl}/payment/admin/user/${userId}/single`,
252
+ reconcileUserSubscription: (userId, subscriptionId) => `${baseUrl}/payment/admin/user/${userId}/subscription/${subscriptionId}/reconcile`,
253
+ getSubscriptions: `${baseUrl}/payment/admin/subscriptions`,
254
+ },
255
+ manualPayments: {
256
+ adminCancelSubscription: (userId, subscriptionId) => `${baseUrl}/payment/manual/admin/user/${userId}/subscription/${subscriptionId}/cancel`,
257
+ cancelSubscription: (subscriptionId) => `${baseUrl}/payment/manual/subscription/${subscriptionId}/cancel`,
258
+ adminGetSubscription: (userId, subscriptionId) => `${baseUrl}/payment/manual/admin/user/${userId}/subscription/${subscriptionId}`,
259
+ adminGetSubscriptions: (userId) => `${baseUrl}/payment/manual/admin/user/${userId}/subscription`,
260
+ getSubscriptions: `${baseUrl}/payment/manual/subscription`,
261
+ getSubscription: (subscriptionId) => `${baseUrl}/payment/manual/subscription/${subscriptionId}`,
262
+ adminNewSubscription: (userId) => `${baseUrl}/payment/manual/admin/user/${userId}/subscription/new`,
263
+ newSubscription: `${baseUrl}/payment/manual/subscription/new`,
264
+ },
265
+ stats: {
266
+ like: (contentId) => `${baseUrl}/stats/${contentId}/like`,
267
+ unlike: (contentId) => `${baseUrl}/stats/${contentId}/unlike`,
268
+ progress: (contentId) => `${baseUrl}/stats/${contentId}/progress`,
269
+ save: (contentId) => `${baseUrl}/stats/${contentId}/save`,
270
+ unSave: (contentId) => `${baseUrl}/stats/${contentId}/unsave`,
271
+ logShare: (contentId) => `${baseUrl}/stats/${contentId}/logshare`,
272
+ getContentStats: (contentId) => `${baseUrl}/stats/${contentId}`,
273
+ getUserStats: (userId) => `${baseUrl}/stats/user/${userId}`,
274
+ getCurrentUserStats: `${baseUrl}/stats/user`,
275
+ getUserLikes: `${baseUrl}/stats/user/likes`,
276
+ getUserProgress: `${baseUrl}/stats/user/progress`,
277
+ getUserSaves: `${baseUrl}/stats/user/saves`,
278
+ },
279
+ };
280
+ }
281
+ /**
282
+ * Create a complete API client bound to a base URL.
283
+ *
284
+ * Returns `endpoints` (the full URL map) and `call` (the fetch wrapper),
285
+ * both pre-bound to the provided base URL.
286
+ */
287
+ export function createApiClient(baseUrl) {
288
+ return {
289
+ endpoints: createApiEndpoints(baseUrl),
290
+ call: (url, options) => apiCall(url, options),
291
+ };
292
+ }
@@ -0,0 +1,491 @@
1
+ /**
2
+ * Cross-platform API client utilities
3
+ *
4
+ * Framework-agnostic: works in Next.js (SSR/SSG), browser SPAs, and Node.js.
5
+ * The caller is responsible for resolving the base URL from their environment.
6
+ *
7
+ * @example Next.js
8
+ * ```ts
9
+ * const isServer = typeof window === 'undefined';
10
+ * const baseUrl = isServer
11
+ * ? (process.env.API_BASE_URL ?? process.env.NEXT_PUBLIC_API_BASE_URL ?? '')
12
+ * : (process.env.NEXT_PUBLIC_API_BASE_URL ?? '');
13
+ * export const api = createApiClient(baseUrl);
14
+ * ```
15
+ *
16
+ * @example Vite SPA
17
+ * ```ts
18
+ * export const api = createApiClient(import.meta.env.VITE_API_BASE_URL ?? '');
19
+ * ```
20
+ */
21
+ type FetchCacheMode = 'default' | 'force-cache' | 'no-cache' | 'no-store' | 'only-if-cached' | 'reload';
22
+ /** Subset of fetch init options we care about, plus an escape hatch for anything else. */
23
+ export interface FetchInit {
24
+ method?: string;
25
+ headers?: Record<string, string>;
26
+ body?: string | null;
27
+ cache?: FetchCacheMode;
28
+ mode?: string;
29
+ credentials?: string;
30
+ signal?: unknown;
31
+ [key: string]: unknown;
32
+ }
33
+ /** Next.js extended fetch options — passed through as-is; non-Next runtimes ignore them. */
34
+ export interface NextFetchExtensions {
35
+ next?: {
36
+ tags?: string[];
37
+ revalidate?: number | false;
38
+ };
39
+ }
40
+ export type ApiCallOptions = FetchInit & NextFetchExtensions;
41
+ /**
42
+ * Cross-platform fetch wrapper with error handling.
43
+ *
44
+ * - Merges caller headers on top of the default Content-Type header.
45
+ * - Defaults cache to `no-store` unless `cache` or `next` is explicitly provided
46
+ * (avoids the Next.js 2 MB data-cache write limit).
47
+ * - Passes `next` through transparently for Next.js ISR tag/revalidation support.
48
+ */
49
+ export declare function apiCall<T>(url: string, options?: ApiCallOptions): Promise<T>;
50
+ /**
51
+ * Build the endpoint map for a given base URL.
52
+ * Call once during app initialization with your resolved base URL.
53
+ */
54
+ export declare function createApiEndpoints(baseUrl: string): {
55
+ readonly auth: {
56
+ readonly login: `${string}/auth/login`;
57
+ readonly logout: `${string}/auth/logout`;
58
+ readonly createUser: `${string}/auth/createuser`;
59
+ readonly adminCreateUser: `${string}/auth/admin/createuser`;
60
+ readonly refresh: `${string}/auth/renewtoken`;
61
+ readonly changePassword: `${string}/auth/password`;
62
+ readonly adminChangePassword: `${string}/auth/admin/password`;
63
+ readonly getCurrentUser: `${string}/auth/user`;
64
+ readonly editOwnUser: `${string}/auth/user`;
65
+ readonly getUserById: (userId: string) => string;
66
+ readonly getUserByName: (userName: string) => string;
67
+ readonly getUserIds: `${string}/auth/user/ids`;
68
+ readonly getProfileImage: `${string}/auth/profileimage`;
69
+ readonly getUserProfileImage: (userId: string) => string;
70
+ readonly uploadProfileImage: `${string}/auth/profileimage`;
71
+ readonly adminUploadProfileImage: `${string}/auth/admin/profileimage`;
72
+ readonly totp: `${string}/auth/totp`;
73
+ readonly disableTotp: (id: string) => string;
74
+ readonly verifyTotp: (id: string) => string;
75
+ readonly adminGetUsers: `${string}/auth/admin/user`;
76
+ readonly adminAddUser: `${string}/auth/admin/user`;
77
+ readonly adminGetUser: (userId: string) => string;
78
+ readonly adminDisableUser: (userId: string) => string;
79
+ readonly adminEnableUser: (userId: string) => string;
80
+ readonly adminSetRoles: `${string}/auth/admin/user/roles`;
81
+ readonly adminSearch: `${string}/auth/admin/search`;
82
+ readonly adminGetTotp: (userId: string) => string;
83
+ readonly adminCreateTotp: (userId: string) => string;
84
+ readonly adminDisableTotp: (userId: string, totpId: string) => string;
85
+ readonly adminVerifyTotp: (userId: string, totpId: string) => string;
86
+ };
87
+ readonly asset: {
88
+ readonly getAssetData: (id: string) => string;
89
+ readonly createAudioAsset: `${string}/cms/asset/audio`;
90
+ readonly createAsset: `${string}/cms/admin/asset`;
91
+ readonly getAsset: (id: string) => string;
92
+ readonly adminGetAsset: (id: string) => string;
93
+ readonly adminGetAssetByOldId: (id: string) => string;
94
+ readonly adminGetImageAssets: `${string}/cms/admin/asset/image`;
95
+ readonly searchAssets: `${string}/cms/admin/asset/search`;
96
+ };
97
+ readonly auditLog: {
98
+ readonly adminGetAuditLog: `${string}/admin/audit-log`;
99
+ };
100
+ readonly careers: {
101
+ readonly createCareer: `${string}/admin/careers`;
102
+ readonly getCareersAdmin: `${string}/admin/careers`;
103
+ readonly getCareer: (id: string) => string;
104
+ readonly getCareers: `${string}/careers`;
105
+ readonly adminUpdateCareer: (id: string) => string;
106
+ readonly adminDeleteCareer: (id: string) => string;
107
+ };
108
+ readonly category: {
109
+ readonly createCategory: `${string}/settings/category/create`;
110
+ readonly deleteCategory: (id: string) => string;
111
+ };
112
+ readonly channel: {
113
+ readonly getChannels: `${string}/settings/channel`;
114
+ readonly createChannel: `${string}/settings/channel/create`;
115
+ readonly deleteChannel: (id: string) => string;
116
+ readonly getChannelDetails: (id: string) => string;
117
+ };
118
+ readonly comment: {
119
+ readonly adminDeleteComment: (id: string) => string;
120
+ readonly adminPinComment: (id: string) => string;
121
+ readonly adminUndeleteComment: (id: string) => string;
122
+ readonly adminUnpinComment: (id: string) => string;
123
+ readonly createCommentForContent: (id: string) => string;
124
+ readonly createCommentForComment: (id: string) => string;
125
+ readonly deleteOwnComment: (id: string) => string;
126
+ readonly editOwnComment: (id: string) => string;
127
+ readonly getCommentForContent: (id: string) => string;
128
+ readonly getCommentsForComment: (id: string) => string;
129
+ readonly likeComment: (id: string) => string;
130
+ readonly unlikeComment: (id: string) => string;
131
+ };
132
+ readonly cms: {
133
+ readonly announceContent: (id: string) => string;
134
+ readonly createContent: `${string}/cms/admin/content`;
135
+ readonly adminListContent: `${string}/cms/admin/content`;
136
+ readonly deleteContent: (id: string) => string;
137
+ readonly adminGetContentById: (id: string) => string;
138
+ readonly adminUpdateContent: (id: string) => string;
139
+ readonly listContent: `${string}/cms/content`;
140
+ readonly getContentById: (id: string) => string;
141
+ readonly getContentByUrl: (url: string) => string;
142
+ readonly getRecentCategories: `${string}/cms/categories/recent`;
143
+ readonly getRecentTags: `${string}/cms/tags/recent`;
144
+ readonly getContentByChannel: (channelId: string, pageSize?: number) => string;
145
+ readonly getRelated: (contentId: string, pageSize?: number) => string;
146
+ readonly publishContent: (id: string) => string;
147
+ readonly searchContent: `${string}/cms/search`;
148
+ readonly unannounceContent: (id: string) => string;
149
+ readonly undeleteContent: (id: string) => string;
150
+ readonly unpublishContent: (id: string) => string;
151
+ readonly createPage: `${string}/cms/admin/page`;
152
+ readonly adminListPages: `${string}/cms/admin/page`;
153
+ readonly deletePage: (id: string) => string;
154
+ readonly adminGetPageById: (id: string) => string;
155
+ readonly adminUpdatePage: (id: string) => string;
156
+ readonly listPages: `${string}/cms/page`;
157
+ readonly getPageById: (id: string) => string;
158
+ readonly getPageByUrl: `${string}/cms/page/url`;
159
+ readonly publishPage: (id: string) => string;
160
+ readonly searchPages: `${string}/cms/page/search`;
161
+ readonly undeletePage: (id: string) => string;
162
+ readonly unpublishPage: (id: string) => string;
163
+ };
164
+ readonly settings: {
165
+ readonly publicSettings: `${string}/settings/public`;
166
+ readonly publicSettingsNewer: (version: string) => string;
167
+ readonly adminSettings: `${string}/settings/admin`;
168
+ readonly adminSettingsNewer: (version: string) => string;
169
+ readonly ownerSettings: `${string}/settings/owner`;
170
+ readonly ownerSettingsNewer: (version: string) => string;
171
+ readonly channels: `${string}/settings/channel`;
172
+ readonly channelById: (channelId: string) => string;
173
+ readonly saveCmsPublic: `${string}/settings/cms/public`;
174
+ readonly saveCmsPrivate: `${string}/settings/cms/private`;
175
+ readonly saveCmsOwner: `${string}/settings/cms/owner`;
176
+ readonly savePersonalizationPublic: `${string}/settings/personalization/public`;
177
+ readonly savePersonalizationPrivate: `${string}/settings/personalization/private`;
178
+ readonly savePersonalizationOwner: `${string}/settings/personalization/owner`;
179
+ readonly saveSubscriptionPublic: `${string}/settings/subscription/public`;
180
+ readonly saveSubscriptionPrivate: `${string}/settings/subscription/private`;
181
+ readonly saveSubscriptionOwner: `${string}/settings/subscription/owner`;
182
+ readonly saveCommentsPublic: `${string}/settings/comments/public`;
183
+ readonly saveCommentsPrivate: `${string}/settings/comments/private`;
184
+ readonly saveCommentsOwner: `${string}/settings/comments/owner`;
185
+ readonly saveNotificationPublic: `${string}/settings/notification/public`;
186
+ readonly saveNotificationPrivate: `${string}/settings/notification/private`;
187
+ readonly saveNotificationOwner: `${string}/settings/notification/owner`;
188
+ readonly saveEventsPublic: `${string}/settings/events/public`;
189
+ readonly saveEventsPrivate: `${string}/settings/events/private`;
190
+ readonly saveEventsOwner: `${string}/settings/events/owner`;
191
+ };
192
+ readonly dashboard: {
193
+ readonly getDashboard: `${string}/admin/dashboard`;
194
+ };
195
+ readonly events: {
196
+ readonly getEvent: (eventId: string) => string;
197
+ readonly getEvents: `${string}/events`;
198
+ readonly getTicket: (eventId: string, ticketId: string) => string;
199
+ readonly getTickets: (eventId: string) => string;
200
+ readonly cancelTicket: (eventId: string, ticketId: string) => string;
201
+ readonly reserveTicket: (eventId: string) => string;
202
+ readonly useTicket: `${string}/events/tickets/use`;
203
+ };
204
+ readonly adminEvents: {
205
+ readonly createEvent: `${string}/admin/events/create`;
206
+ readonly createRecurringEvent: `${string}/admin/events/create-recurring`;
207
+ readonly getEvent: (eventId: string) => string;
208
+ readonly getEvents: `${string}/admin/events`;
209
+ readonly modifyEvent: `${string}/admin/events/modify`;
210
+ readonly cancelEvent: `${string}/admin/events/cancel`;
211
+ readonly cancelAllRecurring: `${string}/admin/events/cancel-all-recurring`;
212
+ readonly getTicket: (eventId: string, ticketId: string) => string;
213
+ readonly getTickets: (eventId: string) => string;
214
+ readonly cancelTicket: (eventId: string, ticketId: string) => string;
215
+ readonly reserveTicket: (eventId: string) => string;
216
+ };
217
+ readonly payments: {
218
+ readonly getSubscriptions: `${string}/payment/subscription`;
219
+ readonly getSubscriptionById: (id: string) => string;
220
+ readonly reconcileSubscription: `${string}/payment/subscription/reconcile`;
221
+ readonly newSubscription: (level: number, postalCode: string, successUrl: string, cancelUrl: string) => string;
222
+ readonly cancelSubscription: `${string}/payment/subscription/cancel`;
223
+ readonly getSinglePayments: `${string}/payment/single`;
224
+ readonly getSinglePayment: (id: string) => string;
225
+ readonly newSinglePayment: `${string}/payment/single/new`;
226
+ readonly finishStripe: `${string}/payment/stripe/subscription/finish`;
227
+ readonly finishFortis: `${string}/payment/fortis/subscription/finish`;
228
+ readonly newPaypal: `${string}/payment/paypal/subscription/new`;
229
+ };
230
+ readonly adminPayments: {
231
+ readonly bulkCancel: `${string}/payment/admin/bulk/cancel`;
232
+ readonly bulkStart: `${string}/payment/admin/bulk/start`;
233
+ readonly getBulk: `${string}/payment/admin/bulk`;
234
+ readonly cancelUserSubscription: (userId: string, subscriptionId: string) => string;
235
+ readonly getUserSubscription: (userId: string, subscriptionId: string) => string;
236
+ readonly getUserSubscriptions: (userId: string) => string;
237
+ readonly getUserSinglePayment: (userId: string, paymentId: string) => string;
238
+ readonly getUserSinglePayments: (userId: string) => string;
239
+ readonly reconcileUserSubscription: (userId: string, subscriptionId: string) => string;
240
+ readonly getSubscriptions: `${string}/payment/admin/subscriptions`;
241
+ };
242
+ readonly manualPayments: {
243
+ readonly adminCancelSubscription: (userId: string, subscriptionId: string) => string;
244
+ readonly cancelSubscription: (subscriptionId: string) => string;
245
+ readonly adminGetSubscription: (userId: string, subscriptionId: string) => string;
246
+ readonly adminGetSubscriptions: (userId: string) => string;
247
+ readonly getSubscriptions: `${string}/payment/manual/subscription`;
248
+ readonly getSubscription: (subscriptionId: string) => string;
249
+ readonly adminNewSubscription: (userId: string) => string;
250
+ readonly newSubscription: `${string}/payment/manual/subscription/new`;
251
+ };
252
+ readonly stats: {
253
+ readonly like: (contentId: string) => string;
254
+ readonly unlike: (contentId: string) => string;
255
+ readonly progress: (contentId: string) => string;
256
+ readonly save: (contentId: string) => string;
257
+ readonly unSave: (contentId: string) => string;
258
+ readonly logShare: (contentId: string) => string;
259
+ readonly getContentStats: (contentId: string) => string;
260
+ readonly getUserStats: (userId: string) => string;
261
+ readonly getCurrentUserStats: `${string}/stats/user`;
262
+ readonly getUserLikes: `${string}/stats/user/likes`;
263
+ readonly getUserProgress: `${string}/stats/user/progress`;
264
+ readonly getUserSaves: `${string}/stats/user/saves`;
265
+ };
266
+ };
267
+ export type ApiEndpoints = ReturnType<typeof createApiEndpoints>;
268
+ /**
269
+ * Create a complete API client bound to a base URL.
270
+ *
271
+ * Returns `endpoints` (the full URL map) and `call` (the fetch wrapper),
272
+ * both pre-bound to the provided base URL.
273
+ */
274
+ export declare function createApiClient(baseUrl: string): {
275
+ endpoints: {
276
+ readonly auth: {
277
+ readonly login: `${string}/auth/login`;
278
+ readonly logout: `${string}/auth/logout`;
279
+ readonly createUser: `${string}/auth/createuser`;
280
+ readonly adminCreateUser: `${string}/auth/admin/createuser`;
281
+ readonly refresh: `${string}/auth/renewtoken`;
282
+ readonly changePassword: `${string}/auth/password`;
283
+ readonly adminChangePassword: `${string}/auth/admin/password`;
284
+ readonly getCurrentUser: `${string}/auth/user`;
285
+ readonly editOwnUser: `${string}/auth/user`;
286
+ readonly getUserById: (userId: string) => string;
287
+ readonly getUserByName: (userName: string) => string;
288
+ readonly getUserIds: `${string}/auth/user/ids`;
289
+ readonly getProfileImage: `${string}/auth/profileimage`;
290
+ readonly getUserProfileImage: (userId: string) => string;
291
+ readonly uploadProfileImage: `${string}/auth/profileimage`;
292
+ readonly adminUploadProfileImage: `${string}/auth/admin/profileimage`;
293
+ readonly totp: `${string}/auth/totp`;
294
+ readonly disableTotp: (id: string) => string;
295
+ readonly verifyTotp: (id: string) => string;
296
+ readonly adminGetUsers: `${string}/auth/admin/user`;
297
+ readonly adminAddUser: `${string}/auth/admin/user`;
298
+ readonly adminGetUser: (userId: string) => string;
299
+ readonly adminDisableUser: (userId: string) => string;
300
+ readonly adminEnableUser: (userId: string) => string;
301
+ readonly adminSetRoles: `${string}/auth/admin/user/roles`;
302
+ readonly adminSearch: `${string}/auth/admin/search`;
303
+ readonly adminGetTotp: (userId: string) => string;
304
+ readonly adminCreateTotp: (userId: string) => string;
305
+ readonly adminDisableTotp: (userId: string, totpId: string) => string;
306
+ readonly adminVerifyTotp: (userId: string, totpId: string) => string;
307
+ };
308
+ readonly asset: {
309
+ readonly getAssetData: (id: string) => string;
310
+ readonly createAudioAsset: `${string}/cms/asset/audio`;
311
+ readonly createAsset: `${string}/cms/admin/asset`;
312
+ readonly getAsset: (id: string) => string;
313
+ readonly adminGetAsset: (id: string) => string;
314
+ readonly adminGetAssetByOldId: (id: string) => string;
315
+ readonly adminGetImageAssets: `${string}/cms/admin/asset/image`;
316
+ readonly searchAssets: `${string}/cms/admin/asset/search`;
317
+ };
318
+ readonly auditLog: {
319
+ readonly adminGetAuditLog: `${string}/admin/audit-log`;
320
+ };
321
+ readonly careers: {
322
+ readonly createCareer: `${string}/admin/careers`;
323
+ readonly getCareersAdmin: `${string}/admin/careers`;
324
+ readonly getCareer: (id: string) => string;
325
+ readonly getCareers: `${string}/careers`;
326
+ readonly adminUpdateCareer: (id: string) => string;
327
+ readonly adminDeleteCareer: (id: string) => string;
328
+ };
329
+ readonly category: {
330
+ readonly createCategory: `${string}/settings/category/create`;
331
+ readonly deleteCategory: (id: string) => string;
332
+ };
333
+ readonly channel: {
334
+ readonly getChannels: `${string}/settings/channel`;
335
+ readonly createChannel: `${string}/settings/channel/create`;
336
+ readonly deleteChannel: (id: string) => string;
337
+ readonly getChannelDetails: (id: string) => string;
338
+ };
339
+ readonly comment: {
340
+ readonly adminDeleteComment: (id: string) => string;
341
+ readonly adminPinComment: (id: string) => string;
342
+ readonly adminUndeleteComment: (id: string) => string;
343
+ readonly adminUnpinComment: (id: string) => string;
344
+ readonly createCommentForContent: (id: string) => string;
345
+ readonly createCommentForComment: (id: string) => string;
346
+ readonly deleteOwnComment: (id: string) => string;
347
+ readonly editOwnComment: (id: string) => string;
348
+ readonly getCommentForContent: (id: string) => string;
349
+ readonly getCommentsForComment: (id: string) => string;
350
+ readonly likeComment: (id: string) => string;
351
+ readonly unlikeComment: (id: string) => string;
352
+ };
353
+ readonly cms: {
354
+ readonly announceContent: (id: string) => string;
355
+ readonly createContent: `${string}/cms/admin/content`;
356
+ readonly adminListContent: `${string}/cms/admin/content`;
357
+ readonly deleteContent: (id: string) => string;
358
+ readonly adminGetContentById: (id: string) => string;
359
+ readonly adminUpdateContent: (id: string) => string;
360
+ readonly listContent: `${string}/cms/content`;
361
+ readonly getContentById: (id: string) => string;
362
+ readonly getContentByUrl: (url: string) => string;
363
+ readonly getRecentCategories: `${string}/cms/categories/recent`;
364
+ readonly getRecentTags: `${string}/cms/tags/recent`;
365
+ readonly getContentByChannel: (channelId: string, pageSize?: number) => string;
366
+ readonly getRelated: (contentId: string, pageSize?: number) => string;
367
+ readonly publishContent: (id: string) => string;
368
+ readonly searchContent: `${string}/cms/search`;
369
+ readonly unannounceContent: (id: string) => string;
370
+ readonly undeleteContent: (id: string) => string;
371
+ readonly unpublishContent: (id: string) => string;
372
+ readonly createPage: `${string}/cms/admin/page`;
373
+ readonly adminListPages: `${string}/cms/admin/page`;
374
+ readonly deletePage: (id: string) => string;
375
+ readonly adminGetPageById: (id: string) => string;
376
+ readonly adminUpdatePage: (id: string) => string;
377
+ readonly listPages: `${string}/cms/page`;
378
+ readonly getPageById: (id: string) => string;
379
+ readonly getPageByUrl: `${string}/cms/page/url`;
380
+ readonly publishPage: (id: string) => string;
381
+ readonly searchPages: `${string}/cms/page/search`;
382
+ readonly undeletePage: (id: string) => string;
383
+ readonly unpublishPage: (id: string) => string;
384
+ };
385
+ readonly settings: {
386
+ readonly publicSettings: `${string}/settings/public`;
387
+ readonly publicSettingsNewer: (version: string) => string;
388
+ readonly adminSettings: `${string}/settings/admin`;
389
+ readonly adminSettingsNewer: (version: string) => string;
390
+ readonly ownerSettings: `${string}/settings/owner`;
391
+ readonly ownerSettingsNewer: (version: string) => string;
392
+ readonly channels: `${string}/settings/channel`;
393
+ readonly channelById: (channelId: string) => string;
394
+ readonly saveCmsPublic: `${string}/settings/cms/public`;
395
+ readonly saveCmsPrivate: `${string}/settings/cms/private`;
396
+ readonly saveCmsOwner: `${string}/settings/cms/owner`;
397
+ readonly savePersonalizationPublic: `${string}/settings/personalization/public`;
398
+ readonly savePersonalizationPrivate: `${string}/settings/personalization/private`;
399
+ readonly savePersonalizationOwner: `${string}/settings/personalization/owner`;
400
+ readonly saveSubscriptionPublic: `${string}/settings/subscription/public`;
401
+ readonly saveSubscriptionPrivate: `${string}/settings/subscription/private`;
402
+ readonly saveSubscriptionOwner: `${string}/settings/subscription/owner`;
403
+ readonly saveCommentsPublic: `${string}/settings/comments/public`;
404
+ readonly saveCommentsPrivate: `${string}/settings/comments/private`;
405
+ readonly saveCommentsOwner: `${string}/settings/comments/owner`;
406
+ readonly saveNotificationPublic: `${string}/settings/notification/public`;
407
+ readonly saveNotificationPrivate: `${string}/settings/notification/private`;
408
+ readonly saveNotificationOwner: `${string}/settings/notification/owner`;
409
+ readonly saveEventsPublic: `${string}/settings/events/public`;
410
+ readonly saveEventsPrivate: `${string}/settings/events/private`;
411
+ readonly saveEventsOwner: `${string}/settings/events/owner`;
412
+ };
413
+ readonly dashboard: {
414
+ readonly getDashboard: `${string}/admin/dashboard`;
415
+ };
416
+ readonly events: {
417
+ readonly getEvent: (eventId: string) => string;
418
+ readonly getEvents: `${string}/events`;
419
+ readonly getTicket: (eventId: string, ticketId: string) => string;
420
+ readonly getTickets: (eventId: string) => string;
421
+ readonly cancelTicket: (eventId: string, ticketId: string) => string;
422
+ readonly reserveTicket: (eventId: string) => string;
423
+ readonly useTicket: `${string}/events/tickets/use`;
424
+ };
425
+ readonly adminEvents: {
426
+ readonly createEvent: `${string}/admin/events/create`;
427
+ readonly createRecurringEvent: `${string}/admin/events/create-recurring`;
428
+ readonly getEvent: (eventId: string) => string;
429
+ readonly getEvents: `${string}/admin/events`;
430
+ readonly modifyEvent: `${string}/admin/events/modify`;
431
+ readonly cancelEvent: `${string}/admin/events/cancel`;
432
+ readonly cancelAllRecurring: `${string}/admin/events/cancel-all-recurring`;
433
+ readonly getTicket: (eventId: string, ticketId: string) => string;
434
+ readonly getTickets: (eventId: string) => string;
435
+ readonly cancelTicket: (eventId: string, ticketId: string) => string;
436
+ readonly reserveTicket: (eventId: string) => string;
437
+ };
438
+ readonly payments: {
439
+ readonly getSubscriptions: `${string}/payment/subscription`;
440
+ readonly getSubscriptionById: (id: string) => string;
441
+ readonly reconcileSubscription: `${string}/payment/subscription/reconcile`;
442
+ readonly newSubscription: (level: number, postalCode: string, successUrl: string, cancelUrl: string) => string;
443
+ readonly cancelSubscription: `${string}/payment/subscription/cancel`;
444
+ readonly getSinglePayments: `${string}/payment/single`;
445
+ readonly getSinglePayment: (id: string) => string;
446
+ readonly newSinglePayment: `${string}/payment/single/new`;
447
+ readonly finishStripe: `${string}/payment/stripe/subscription/finish`;
448
+ readonly finishFortis: `${string}/payment/fortis/subscription/finish`;
449
+ readonly newPaypal: `${string}/payment/paypal/subscription/new`;
450
+ };
451
+ readonly adminPayments: {
452
+ readonly bulkCancel: `${string}/payment/admin/bulk/cancel`;
453
+ readonly bulkStart: `${string}/payment/admin/bulk/start`;
454
+ readonly getBulk: `${string}/payment/admin/bulk`;
455
+ readonly cancelUserSubscription: (userId: string, subscriptionId: string) => string;
456
+ readonly getUserSubscription: (userId: string, subscriptionId: string) => string;
457
+ readonly getUserSubscriptions: (userId: string) => string;
458
+ readonly getUserSinglePayment: (userId: string, paymentId: string) => string;
459
+ readonly getUserSinglePayments: (userId: string) => string;
460
+ readonly reconcileUserSubscription: (userId: string, subscriptionId: string) => string;
461
+ readonly getSubscriptions: `${string}/payment/admin/subscriptions`;
462
+ };
463
+ readonly manualPayments: {
464
+ readonly adminCancelSubscription: (userId: string, subscriptionId: string) => string;
465
+ readonly cancelSubscription: (subscriptionId: string) => string;
466
+ readonly adminGetSubscription: (userId: string, subscriptionId: string) => string;
467
+ readonly adminGetSubscriptions: (userId: string) => string;
468
+ readonly getSubscriptions: `${string}/payment/manual/subscription`;
469
+ readonly getSubscription: (subscriptionId: string) => string;
470
+ readonly adminNewSubscription: (userId: string) => string;
471
+ readonly newSubscription: `${string}/payment/manual/subscription/new`;
472
+ };
473
+ readonly stats: {
474
+ readonly like: (contentId: string) => string;
475
+ readonly unlike: (contentId: string) => string;
476
+ readonly progress: (contentId: string) => string;
477
+ readonly save: (contentId: string) => string;
478
+ readonly unSave: (contentId: string) => string;
479
+ readonly logShare: (contentId: string) => string;
480
+ readonly getContentStats: (contentId: string) => string;
481
+ readonly getUserStats: (userId: string) => string;
482
+ readonly getCurrentUserStats: `${string}/stats/user`;
483
+ readonly getUserLikes: `${string}/stats/user/likes`;
484
+ readonly getUserProgress: `${string}/stats/user/progress`;
485
+ readonly getUserSaves: `${string}/stats/user/saves`;
486
+ };
487
+ };
488
+ call: <T>(url: string, options?: ApiCallOptions) => Promise<T>;
489
+ };
490
+ export type ApiClient = ReturnType<typeof createApiClient>;
491
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inverted-tech/fragments",
3
- "version": "0.10.9",
3
+ "version": "0.11.0",
4
4
  "description": "Types and JS runtime for Inverted protocol buffers (Fragments)",
5
5
  "types": "dist/protos/index.d.ts",
6
6
  "module": "dist/esm/index.js",
@@ -297,9 +297,9 @@
297
297
  "types": "./dist/protos/validation.d.ts",
298
298
  "import": "./dist/esm/validation.js"
299
299
  },
300
- "./client": {
301
- "types": "./dist/protos/client.d.ts",
302
- "import": "./dist/esm/client.js"
300
+ "./api": {
301
+ "types": "./dist/protos/api.d.ts",
302
+ "import": "./dist/esm/api.js"
303
303
  },
304
304
  "./*": {
305
305
  "types": "./dist/*",
@@ -330,7 +330,8 @@
330
330
  "dependencies": {
331
331
  "@bufbuild/protobuf": "^2.10.0",
332
332
  "@bufbuild/protovalidate": "^1.0.0",
333
- "@connectrpc/connect": "^1.7.0"
333
+ "@connectrpc/connect": "^1.7.0",
334
+ "pino": "^10.3.1"
334
335
  },
335
336
  "scripts": {
336
337
  "gen": "node ./generate-ts.mjs && node ./scripts/fix-empty-indexes.mjs",
@@ -347,7 +348,7 @@
347
348
  "lint": "eslint . --ext .ts",
348
349
  "lint:gen": "eslint ts-gen --ext .ts",
349
350
  "lint:gen:fix": "eslint ts-gen --ext .ts --fix",
350
- "clean": "node -e \"const fs=require('fs'),path=require('path'); const rm=(p)=>fs.rmSync(p,{recursive:true,force:true}); if(fs.existsSync('dist')) rm('dist'); const base='ts-gen'; if(fs.existsSync(base)){ for(const ent of fs.readdirSync(base,{withFileTypes:true})) { if(ent.name==='validation.ts' || ent.name==='client.ts') continue; rm(path.join(base, ent.name)); } }\"",
351
+ "clean": "node -e \"const fs=require('fs'),path=require('path'); const rm=(p)=>fs.rmSync(p,{recursive:true,force:true}); if(fs.existsSync('dist')) rm('dist'); const base='ts-gen'; if(fs.existsSync(base)){ for(const ent of fs.readdirSync(base,{withFileTypes:true})) { if(ent.name==='validation.ts' || ent.name==='api.ts') continue; rm(path.join(base, ent.name)); } }\"",
351
352
  "clean:pack": "node -e \"const fs=require('fs'); const path=require('path'); fs.rmSync('__pack_extract__',{recursive:true,force:true}); fs.readdirSync('.').filter(f=>f.endsWith('.tgz')).forEach(f=>fs.rmSync(path.join('.',f),{force:true})); console.log('Removed __pack_extract__ and *.tgz');\"",
352
353
  "clean:dist": "node -e \"const fs=require('fs'); fs.rmSync('dist',{recursive:true,force:true});\"",
353
354
  "rebuild": "npm run clean:dist && node ./scripts/ensure-gen.mjs && npm run build",
@@ -1,297 +0,0 @@
1
- import { create, toJsonString } from '@bufbuild/protobuf';
2
- import { getValidator } from './validation.js';
3
- // Safe logging function that works in all environments
4
- const safeLog = {
5
- error: (...args) => {
6
- // Use globalThis to safely access console in all environments
7
- const globalConsole = globalThis?.console;
8
- if (globalConsole && globalConsole.error) {
9
- globalConsole.error(...args);
10
- }
11
- }
12
- };
13
- /**
14
- * Shared client class for standardized API communication with protobuf serialization
15
- *
16
- * This client encapsulates common patterns found in action functions like:
17
- * - Token retrieval and authentication headers
18
- * - Protobuf serialization using create() and toJsonString()
19
- * - Consistent error handling with protobuf error responses
20
- * - Next.js cache invalidation support (framework-agnostic)
21
- * - Pre-request validation using protovalidate
22
- */
23
- export class FragmentsClient {
24
- config;
25
- validator;
26
- // Expose config for testing purposes
27
- get _config() {
28
- return this.config;
29
- }
30
- constructor(config = {}) {
31
- this.config = {
32
- baseUrl: config.baseUrl ?? 'http://localhost:8001',
33
- getToken: config.getToken ?? (() => undefined),
34
- onCacheInvalidate: config.onCacheInvalidate ?? (() => { }),
35
- validateRequests: config.validateRequests ?? false,
36
- };
37
- }
38
- /**
39
- * Create a new client instance with modified configuration
40
- * @param config Partial configuration to override
41
- * @returns New FragmentsClient instance
42
- */
43
- withConfig(config) {
44
- return new FragmentsClient({
45
- ...this.config,
46
- ...config,
47
- });
48
- }
49
- /**
50
- * Generic request method that handles all HTTP operations
51
- * @param endpoint API endpoint (relative to baseUrl)
52
- * @param reqSchema Request protobuf schema
53
- * @param resSchema Response protobuf schema
54
- * @param data Request data (optional for GET requests)
55
- * @param options Request options
56
- * @returns Promise resolving to typed response
57
- */
58
- async request(endpoint, reqSchema, resSchema, data, options = {}) {
59
- const method = options.method ?? 'POST';
60
- const shouldValidate = options.validate ?? this.config.validateRequests;
61
- // Get authentication token
62
- const token = await this.config.getToken();
63
- // Create request message if data is provided
64
- let requestMessage;
65
- let requestBody;
66
- if (data && method !== 'GET') {
67
- requestMessage = create(reqSchema, data);
68
- // Validate request if enabled
69
- if (shouldValidate) {
70
- const validationResult = await this.validateMessage(reqSchema, requestMessage);
71
- if (!validationResult.success) {
72
- // Return error response instead of making HTTP request
73
- return this.createValidationErrorResponse(resSchema, validationResult.violations);
74
- }
75
- }
76
- requestBody = toJsonString(reqSchema, requestMessage);
77
- }
78
- // Prepare fetch options
79
- const fetchOptions = {
80
- method,
81
- headers: {
82
- 'Content-Type': 'application/json',
83
- ...(token && { Authorization: `Bearer ${token}` }),
84
- },
85
- ...(requestBody && { body: requestBody }),
86
- };
87
- // Add Next.js cache options if provided
88
- if (options.cacheTags || options.revalidate !== undefined) {
89
- fetchOptions.next = {
90
- ...(options.cacheTags && { tags: options.cacheTags }),
91
- ...(options.revalidate !== undefined && { revalidate: options.revalidate }),
92
- };
93
- }
94
- try {
95
- const url = `${this.config.baseUrl}${endpoint}`;
96
- const response = await fetch(url, fetchOptions);
97
- // Handle null response like existing action functions
98
- if (!response) {
99
- safeLog.error('FragmentsClient: Network request failed - no response received');
100
- return this.createNetworkErrorResponse(resSchema);
101
- }
102
- // Handle HTTP errors like existing action functions
103
- if (!response.ok) {
104
- safeLog.error(`FragmentsClient: HTTP error ${response.status}: ${response.statusText}`);
105
- return this.createHttpErrorResponse(resSchema, response.status, response.statusText);
106
- }
107
- const responseData = await response.json();
108
- // Handle cache invalidation for successful mutations
109
- if (method !== 'GET' && (options.cacheTags || options.revalidatePaths)) {
110
- this.config.onCacheInvalidate(options.cacheTags ?? [], options.revalidatePaths ?? []);
111
- }
112
- return responseData;
113
- }
114
- catch (error) {
115
- // Log errors like existing action functions using console.error
116
- safeLog.error('FragmentsClient request failed:', error);
117
- // Return error response instead of throwing, matching existing patterns
118
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
119
- return this.createErrorResponse(resSchema, errorMessage);
120
- }
121
- }
122
- /**
123
- * Convenience method for GET requests
124
- * @param endpoint API endpoint
125
- * @param resSchema Response protobuf schema
126
- * @param options Request options
127
- * @returns Promise resolving to typed response
128
- */
129
- async get(endpoint, resSchema, options = {}) {
130
- return this.request(endpoint, {}, resSchema, undefined, {
131
- ...options,
132
- method: 'GET',
133
- });
134
- }
135
- /**
136
- * Convenience method for POST requests
137
- * @param endpoint API endpoint
138
- * @param reqSchema Request protobuf schema
139
- * @param resSchema Response protobuf schema
140
- * @param data Request data
141
- * @param options Request options
142
- * @returns Promise resolving to typed response
143
- */
144
- async post(endpoint, reqSchema, resSchema, data, options = {}) {
145
- return this.request(endpoint, reqSchema, resSchema, data, {
146
- ...options,
147
- method: 'POST',
148
- });
149
- }
150
- /**
151
- * Static utility method to create protobuf request messages
152
- * @param schema Protobuf message schema
153
- * @param data Optional partial data to initialize the message
154
- * @returns Created message instance
155
- */
156
- static createRequest(schema, data) {
157
- return create(schema, data);
158
- }
159
- /**
160
- * Static utility method to create protobuf response messages
161
- * @param schema Protobuf message schema
162
- * @param data Optional partial data to initialize the message
163
- * @returns Created message instance
164
- */
165
- static createResponse(schema, data) {
166
- return create(schema, data);
167
- }
168
- /**
169
- * Static utility method to serialize protobuf messages to JSON strings
170
- * @param schema Protobuf message schema
171
- * @param data Message data to serialize
172
- * @returns JSON string representation
173
- */
174
- static serialize(schema, data) {
175
- return toJsonString(schema, data);
176
- }
177
- /**
178
- * Static utility method to validate protobuf messages using protovalidate
179
- * @param schema Protobuf message schema
180
- * @param data Message data to validate
181
- * @returns Promise resolving to validation result
182
- */
183
- static async validate(schema, data) {
184
- try {
185
- const validator = await getValidator();
186
- const result = validator.validate(schema, data);
187
- return {
188
- success: result.kind === 'valid',
189
- violations: result.kind === 'invalid' ? result.violations : undefined,
190
- };
191
- }
192
- catch (error) {
193
- safeLog.error('Validation error:', error);
194
- return {
195
- success: false,
196
- violations: [{ message: 'Validation system error' }],
197
- };
198
- }
199
- }
200
- /**
201
- * Private method to validate messages using the instance validator
202
- */
203
- async validateMessage(schema, data) {
204
- if (!this.validator) {
205
- this.validator = await getValidator();
206
- }
207
- try {
208
- const result = this.validator.validate(schema, data);
209
- return {
210
- success: result.kind === 'valid',
211
- violations: result.kind === 'invalid' ? result.violations : undefined,
212
- };
213
- }
214
- catch (error) {
215
- safeLog.error('Validation error:', error);
216
- return {
217
- success: false,
218
- violations: [{ message: 'Validation system error' }],
219
- };
220
- }
221
- }
222
- /**
223
- * Private method to create error responses matching existing action function patterns
224
- * This creates a generic error response structure that matches the patterns used in
225
- * existing action functions like modifyPublicSubscriptionSettings
226
- */
227
- createErrorResponse(schema, message) {
228
- // Create error response matching existing action function patterns
229
- // The structure matches what's used in functions like modifyPublicSubscriptionSettings
230
- return create(schema, {
231
- Error: {
232
- Message: message,
233
- Type: 'SETTINGS_ERROR_UNKNOWN', // Matches SettingsErrorReason.SETTINGS_ERROR_UNKNOWN
234
- },
235
- });
236
- }
237
- /**
238
- * Private method to create validation error responses
239
- * This preserves ValidationIssue[] arrays in error responses as required
240
- */
241
- createValidationErrorResponse(schema, violations) {
242
- return create(schema, {
243
- Error: {
244
- Message: 'Request validation failed',
245
- Type: 'SETTINGS_ERROR_VALIDATION_FAILED', // Matches validation error type
246
- Validation: violations ?? [], // Preserve ValidationIssue[] arrays
247
- },
248
- });
249
- }
250
- /**
251
- * Private method to create HTTP error responses
252
- * Handles HTTP errors uniformly like existing action functions
253
- */
254
- createHttpErrorResponse(schema, status, statusText) {
255
- const message = `HTTP ${status}: ${statusText}`;
256
- return create(schema, {
257
- Error: {
258
- Message: message,
259
- Type: 'SETTINGS_ERROR_UNKNOWN',
260
- },
261
- });
262
- }
263
- /**
264
- * Private method to create network error responses
265
- * Handles network failures like existing action functions
266
- */
267
- createNetworkErrorResponse(schema) {
268
- return create(schema, {
269
- Error: {
270
- Message: 'Network request failed',
271
- Type: 'SETTINGS_ERROR_UNKNOWN',
272
- },
273
- });
274
- }
275
- /**
276
- * Static method to create error responses for use in action functions
277
- * This allows consumers to create consistent error responses outside of the client
278
- * @param schema Response schema to create error for
279
- * @param message Error message
280
- * @param errorType Error type (defaults to SETTINGS_ERROR_UNKNOWN)
281
- * @param validationIssues Optional validation issues array
282
- * @returns Error response matching existing action function patterns
283
- */
284
- static createErrorResponse(schema, message, errorType = 'SETTINGS_ERROR_UNKNOWN', validationIssues) {
285
- const errorData = {
286
- Message: message,
287
- Type: errorType,
288
- };
289
- // Include validation issues if provided (preserves ValidationIssue[] arrays)
290
- if (validationIssues && validationIssues.length > 0) {
291
- errorData.Validation = validationIssues;
292
- }
293
- return create(schema, {
294
- Error: errorData,
295
- });
296
- }
297
- }
@@ -1,185 +0,0 @@
1
- import { type Message } from '@bufbuild/protobuf';
2
- import { type GenMessage } from '@bufbuild/protobuf/codegenv2';
3
- declare global {
4
- function fetch(input: string, init?: any): Promise<any>;
5
- }
6
- /**
7
- * HTTP methods supported by the client
8
- */
9
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
10
- /**
11
- * Token getter function type - can be sync or async
12
- */
13
- export type TokenGetter = () => Promise<string | undefined> | string | undefined;
14
- /**
15
- * Cache invalidation callback function type
16
- */
17
- export type CacheInvalidator = (tags: string[], paths: string[]) => void;
18
- /**
19
- * Simplified validation result interface
20
- */
21
- export interface SimpleValidationResult {
22
- success: boolean;
23
- violations?: any[];
24
- }
25
- /**
26
- * Configuration interface for the FragmentsClient
27
- */
28
- export interface ClientConfig {
29
- /**
30
- * Base URL for API requests
31
- * @default 'http://localhost:8001'
32
- */
33
- baseUrl?: string;
34
- /**
35
- * Function to retrieve authentication tokens (sync or async)
36
- */
37
- getToken?: TokenGetter;
38
- /**
39
- * Callback for cache invalidation (Next.js can pass revalidateTag/revalidatePath)
40
- */
41
- onCacheInvalidate?: CacheInvalidator;
42
- /**
43
- * Enable pre-request validation using protovalidate
44
- * @default false
45
- */
46
- validateRequests?: boolean;
47
- }
48
- /**
49
- * Per-request options that can override client configuration
50
- */
51
- export interface RequestOptions {
52
- /**
53
- * HTTP method for the request
54
- */
55
- method?: HttpMethod;
56
- /**
57
- * Cache tags for Next.js caching
58
- */
59
- cacheTags?: string[];
60
- /**
61
- * Paths to revalidate after mutations
62
- */
63
- revalidatePaths?: string[];
64
- /**
65
- * Cache revalidation time in seconds
66
- */
67
- revalidate?: number;
68
- /**
69
- * Override client-level validation setting for this request
70
- */
71
- validate?: boolean;
72
- }
73
- /**
74
- * Shared client class for standardized API communication with protobuf serialization
75
- *
76
- * This client encapsulates common patterns found in action functions like:
77
- * - Token retrieval and authentication headers
78
- * - Protobuf serialization using create() and toJsonString()
79
- * - Consistent error handling with protobuf error responses
80
- * - Next.js cache invalidation support (framework-agnostic)
81
- * - Pre-request validation using protovalidate
82
- */
83
- export declare class FragmentsClient {
84
- private readonly config;
85
- private validator?;
86
- get _config(): Required<ClientConfig>;
87
- constructor(config?: ClientConfig);
88
- /**
89
- * Create a new client instance with modified configuration
90
- * @param config Partial configuration to override
91
- * @returns New FragmentsClient instance
92
- */
93
- withConfig(config: Partial<ClientConfig>): FragmentsClient;
94
- /**
95
- * Generic request method that handles all HTTP operations
96
- * @param endpoint API endpoint (relative to baseUrl)
97
- * @param reqSchema Request protobuf schema
98
- * @param resSchema Response protobuf schema
99
- * @param data Request data (optional for GET requests)
100
- * @param options Request options
101
- * @returns Promise resolving to typed response
102
- */
103
- request<TReq extends Message, TRes extends Message>(endpoint: string, reqSchema: GenMessage<TReq>, resSchema: GenMessage<TRes>, data?: Partial<TReq>, options?: RequestOptions): Promise<TRes>;
104
- /**
105
- * Convenience method for GET requests
106
- * @param endpoint API endpoint
107
- * @param resSchema Response protobuf schema
108
- * @param options Request options
109
- * @returns Promise resolving to typed response
110
- */
111
- get<TRes extends Message>(endpoint: string, resSchema: GenMessage<TRes>, options?: Omit<RequestOptions, 'method'>): Promise<TRes>;
112
- /**
113
- * Convenience method for POST requests
114
- * @param endpoint API endpoint
115
- * @param reqSchema Request protobuf schema
116
- * @param resSchema Response protobuf schema
117
- * @param data Request data
118
- * @param options Request options
119
- * @returns Promise resolving to typed response
120
- */
121
- post<TReq extends Message, TRes extends Message>(endpoint: string, reqSchema: GenMessage<TReq>, resSchema: GenMessage<TRes>, data: Partial<TReq>, options?: Omit<RequestOptions, 'method'>): Promise<TRes>;
122
- /**
123
- * Static utility method to create protobuf request messages
124
- * @param schema Protobuf message schema
125
- * @param data Optional partial data to initialize the message
126
- * @returns Created message instance
127
- */
128
- static createRequest<T extends Message>(schema: GenMessage<T>, data?: Partial<T>): T;
129
- /**
130
- * Static utility method to create protobuf response messages
131
- * @param schema Protobuf message schema
132
- * @param data Optional partial data to initialize the message
133
- * @returns Created message instance
134
- */
135
- static createResponse<T extends Message>(schema: GenMessage<T>, data?: Partial<T>): T;
136
- /**
137
- * Static utility method to serialize protobuf messages to JSON strings
138
- * @param schema Protobuf message schema
139
- * @param data Message data to serialize
140
- * @returns JSON string representation
141
- */
142
- static serialize<T extends Message>(schema: GenMessage<T>, data: T): string;
143
- /**
144
- * Static utility method to validate protobuf messages using protovalidate
145
- * @param schema Protobuf message schema
146
- * @param data Message data to validate
147
- * @returns Promise resolving to validation result
148
- */
149
- static validate<T extends Message>(schema: GenMessage<T>, data: T): Promise<SimpleValidationResult>;
150
- /**
151
- * Private method to validate messages using the instance validator
152
- */
153
- private validateMessage;
154
- /**
155
- * Private method to create error responses matching existing action function patterns
156
- * This creates a generic error response structure that matches the patterns used in
157
- * existing action functions like modifyPublicSubscriptionSettings
158
- */
159
- private createErrorResponse;
160
- /**
161
- * Private method to create validation error responses
162
- * This preserves ValidationIssue[] arrays in error responses as required
163
- */
164
- private createValidationErrorResponse;
165
- /**
166
- * Private method to create HTTP error responses
167
- * Handles HTTP errors uniformly like existing action functions
168
- */
169
- private createHttpErrorResponse;
170
- /**
171
- * Private method to create network error responses
172
- * Handles network failures like existing action functions
173
- */
174
- private createNetworkErrorResponse;
175
- /**
176
- * Static method to create error responses for use in action functions
177
- * This allows consumers to create consistent error responses outside of the client
178
- * @param schema Response schema to create error for
179
- * @param message Error message
180
- * @param errorType Error type (defaults to SETTINGS_ERROR_UNKNOWN)
181
- * @param validationIssues Optional validation issues array
182
- * @returns Error response matching existing action function patterns
183
- */
184
- static createErrorResponse<T extends Message>(schema: GenMessage<T>, message: string, errorType?: string, validationIssues?: any[]): T;
185
- }