@startsimpli/api 0.1.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,2092 @@
1
+ 'use strict';
2
+
3
+ var DOMPurify = require('isomorphic-dompurify');
4
+ var zod = require('zod');
5
+ var react = require('react');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var DOMPurify__default = /*#__PURE__*/_interopDefault(DOMPurify);
10
+
11
+ // src/utils/url-builder.ts
12
+ function buildUrl({ baseUrl, endpoint, params, id }) {
13
+ const cleanBase = baseUrl.replace(/\/$/, "");
14
+ const cleanEndpoint = endpoint.replace(/^\//, "");
15
+ let path = `${cleanBase}/${cleanEndpoint}`;
16
+ if (id !== void 0) {
17
+ path += `/${id}`;
18
+ }
19
+ if (!path.endsWith("/")) {
20
+ path += "/";
21
+ }
22
+ if (params && Object.keys(params).length > 0) {
23
+ const queryString = buildQueryString(params);
24
+ if (queryString) {
25
+ path += `?${queryString}`;
26
+ }
27
+ }
28
+ return path;
29
+ }
30
+ function buildQueryString(params) {
31
+ const searchParams = new URLSearchParams();
32
+ Object.entries(params).forEach(([key, value]) => {
33
+ if (value === void 0 || value === null) {
34
+ return;
35
+ }
36
+ if (Array.isArray(value)) {
37
+ value.forEach((item) => {
38
+ searchParams.append(key, String(item));
39
+ });
40
+ } else if (typeof value === "object") {
41
+ searchParams.append(key, JSON.stringify(value));
42
+ } else {
43
+ searchParams.append(key, String(value));
44
+ }
45
+ });
46
+ return searchParams.toString();
47
+ }
48
+ function resolveApiUrl(path, baseUrl = "") {
49
+ if (/^https?:\/\//i.test(path)) return path;
50
+ const normalized = path.startsWith("/") ? path : `/${path}`;
51
+ if (!baseUrl) return normalized;
52
+ if (/^https?:\/\//i.test(baseUrl)) {
53
+ return new URL(normalized, baseUrl).toString();
54
+ }
55
+ const cleanBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
56
+ return `${cleanBase}${normalized}`;
57
+ }
58
+ function normalizeId(id) {
59
+ if (typeof id === "string" && id.includes("/")) {
60
+ const parts = id.split("/").filter(Boolean);
61
+ return parts[parts.length - 1];
62
+ }
63
+ return id;
64
+ }
65
+
66
+ // src/utils/query-params.ts
67
+ function buildFilterParams(filters) {
68
+ const params = {};
69
+ Object.entries(filters).forEach(([key, value]) => {
70
+ if (value === void 0 || value === null) {
71
+ return;
72
+ }
73
+ if (typeof value === "boolean") {
74
+ params[key] = value;
75
+ return;
76
+ }
77
+ if (Array.isArray(value)) {
78
+ if (value.length > 0) {
79
+ params[`${key}__in`] = value.join(",");
80
+ }
81
+ return;
82
+ }
83
+ if (key.endsWith("_gte") || key.endsWith("_lte") || key.endsWith("_gt") || key.endsWith("_lt")) {
84
+ params[key] = value;
85
+ return;
86
+ }
87
+ params[key] = value;
88
+ });
89
+ return params;
90
+ }
91
+ function buildOrderingParam(field, direction = "asc") {
92
+ if (!field) {
93
+ return void 0;
94
+ }
95
+ return direction === "desc" ? `-${field}` : field;
96
+ }
97
+ function mergeQueryParams(pagination, sorting, filters) {
98
+ return {
99
+ ...filters,
100
+ ...pagination,
101
+ ...sorting
102
+ };
103
+ }
104
+
105
+ // src/utils/validate-response.ts
106
+ function validateApiResponse(data, schema, context) {
107
+ const result = schema.safeParse(data);
108
+ if (!result.success) {
109
+ const label = context ? `[${context}]` : "[API validation]";
110
+ console.warn(
111
+ `${label} Schema mismatch \u2014 returning raw data.`,
112
+ result.error.flatten().fieldErrors
113
+ );
114
+ return data;
115
+ }
116
+ return result.data;
117
+ }
118
+
119
+ // src/utils/entity-query-builder.ts
120
+ var EntityQueryBuilder = class {
121
+ constructor() {
122
+ this.params = /* @__PURE__ */ new Map();
123
+ }
124
+ /**
125
+ * Filter by entity type
126
+ */
127
+ entityType(type) {
128
+ this.params.set("entity_type", type);
129
+ return this;
130
+ }
131
+ /**
132
+ * Add tag filters (compact format: "category:name")
133
+ *
134
+ * @example
135
+ * .withTags('quality:tier_1', 'status:prospect')
136
+ * // produces: tags=quality:tier_1,status:prospect
137
+ */
138
+ withTags(...tags) {
139
+ if (tags.length > 0) {
140
+ const existing = this.params.get("tags");
141
+ const combined = existing ? `${existing},${tags.join(",")}` : tags.join(",");
142
+ this.params.set("tags", combined);
143
+ }
144
+ return this;
145
+ }
146
+ /**
147
+ * Add metric filters (compact format: "type:subtype__operator:value")
148
+ *
149
+ * @example
150
+ * .withMetrics('financial:aum__gte:100000000', 'check_size:min__gte:1000000')
151
+ */
152
+ withMetrics(...metrics) {
153
+ if (metrics.length > 0) {
154
+ const existing = this.params.get("metrics");
155
+ const combined = existing ? `${existing},${metrics.join(",")}` : metrics.join(",");
156
+ this.params.set("metrics", combined);
157
+ }
158
+ return this;
159
+ }
160
+ /**
161
+ * Add profile filters (compact format: "type:subtype")
162
+ *
163
+ * @example
164
+ * .withProfiles('professional:linkedin', 'social:twitter')
165
+ */
166
+ withProfiles(...profiles) {
167
+ if (profiles.length > 0) {
168
+ const existing = this.params.get("profiles");
169
+ const combined = existing ? `${existing},${profiles.join(",")}` : profiles.join(",");
170
+ this.params.set("profiles", combined);
171
+ }
172
+ return this;
173
+ }
174
+ /**
175
+ * Add attribute filters (compact format: "type:subtype:value")
176
+ *
177
+ * @example
178
+ * .withAttributes('demographic:location:san_francisco')
179
+ */
180
+ withAttributes(...attrs) {
181
+ if (attrs.length > 0) {
182
+ const existing = this.params.get("attributes");
183
+ const combined = existing ? `${existing},${attrs.join(",")}` : attrs.join(",");
184
+ this.params.set("attributes", combined);
185
+ }
186
+ return this;
187
+ }
188
+ /**
189
+ * Set pagination parameters
190
+ */
191
+ paginate(page, pageSize) {
192
+ this.params.set("page", String(page));
193
+ this.params.set("page_size", String(pageSize));
194
+ return this;
195
+ }
196
+ /**
197
+ * Set search query
198
+ */
199
+ search(query) {
200
+ const trimmed = query.trim();
201
+ if (trimmed) {
202
+ this.params.set("search", trimmed);
203
+ }
204
+ return this;
205
+ }
206
+ /**
207
+ * Set sort field and direction (maps to Django's `ordering` param)
208
+ */
209
+ sort(field, direction = "asc") {
210
+ const prefix = direction === "desc" ? "-" : "";
211
+ this.params.set("ordering", `${prefix}${field}`);
212
+ return this;
213
+ }
214
+ /**
215
+ * Add a date range filter on a given field
216
+ *
217
+ * @example
218
+ * .withDateRange('created', new Date('2024-01-01'), new Date('2024-12-31'))
219
+ * // produces: created_after=2024-01-01&created_before=2024-12-31
220
+ */
221
+ withDateRange(field, from, to) {
222
+ if (from) {
223
+ this.params.set(`${field}_after`, from.toISOString().split("T")[0]);
224
+ }
225
+ if (to) {
226
+ this.params.set(`${field}_before`, to.toISOString().split("T")[0]);
227
+ }
228
+ return this;
229
+ }
230
+ /**
231
+ * Set an arbitrary query parameter
232
+ */
233
+ param(key, value) {
234
+ this.params.set(key, value);
235
+ return this;
236
+ }
237
+ /**
238
+ * Build as a plain object (suitable for URLSearchParams or fetch helpers)
239
+ */
240
+ build() {
241
+ const result = {};
242
+ this.params.forEach((value, key) => {
243
+ result[key] = value;
244
+ });
245
+ return result;
246
+ }
247
+ /**
248
+ * Build as a query string (includes leading `?`)
249
+ * Returns empty string if no params.
250
+ */
251
+ toQueryString() {
252
+ if (this.params.size === 0) return "";
253
+ const searchParams = new URLSearchParams();
254
+ this.params.forEach((value, key) => {
255
+ searchParams.set(key, value);
256
+ });
257
+ return `?${searchParams.toString()}`;
258
+ }
259
+ /**
260
+ * Reset all parameters
261
+ */
262
+ clear() {
263
+ this.params.clear();
264
+ return this;
265
+ }
266
+ };
267
+
268
+ // src/utils/drf-transforms.ts
269
+ function normalizePaginated(response, page, pageSize) {
270
+ const total = response.count || 0;
271
+ return {
272
+ items: response.results || [],
273
+ total,
274
+ page,
275
+ pageSize,
276
+ hasNext: response.next !== null,
277
+ hasPrev: response.previous !== null
278
+ };
279
+ }
280
+ function isDRFPaginatedResponse(response) {
281
+ return typeof response === "object" && response !== null && "results" in response && "count" in response;
282
+ }
283
+
284
+ // src/lib/error-handler.ts
285
+ var ApiException = class extends Error {
286
+ constructor(message, options) {
287
+ super(message);
288
+ this.name = "ApiException";
289
+ this.status = options?.status;
290
+ this.statusText = options?.statusText;
291
+ this.errors = options?.errors;
292
+ this.detail = options?.detail;
293
+ }
294
+ toJSON() {
295
+ return {
296
+ message: this.message,
297
+ detail: this.detail,
298
+ status: this.status,
299
+ statusText: this.statusText,
300
+ errors: this.errors
301
+ };
302
+ }
303
+ };
304
+ async function parseErrorResponse(response) {
305
+ const contentType = response.headers?.get("content-type");
306
+ if (contentType?.includes("application/json")) {
307
+ try {
308
+ const data = await response.json();
309
+ if (data.detail) {
310
+ return {
311
+ detail: data.detail,
312
+ message: data.detail,
313
+ status: response.status,
314
+ statusText: response.statusText
315
+ };
316
+ }
317
+ if (typeof data === "object") {
318
+ return {
319
+ errors: data,
320
+ message: "Validation error",
321
+ status: response.status,
322
+ statusText: response.statusText
323
+ };
324
+ }
325
+ return {
326
+ message: JSON.stringify(data),
327
+ status: response.status,
328
+ statusText: response.statusText
329
+ };
330
+ } catch {
331
+ }
332
+ }
333
+ const text = await response.text().catch(() => response.statusText);
334
+ return {
335
+ message: text || response.statusText || "Unknown error",
336
+ status: response.status,
337
+ statusText: response.statusText
338
+ };
339
+ }
340
+ function handleFetchError(error) {
341
+ if (error instanceof ApiException) {
342
+ throw error;
343
+ }
344
+ if (error instanceof TypeError && error.message.includes("fetch")) {
345
+ throw new ApiException("Network error - please check your connection", {
346
+ status: 0,
347
+ statusText: "Network Error"
348
+ });
349
+ }
350
+ if (error instanceof Error) {
351
+ throw new ApiException(error.message, {
352
+ status: 0,
353
+ statusText: "Client Error"
354
+ });
355
+ }
356
+ throw new ApiException("Unknown error occurred", {
357
+ status: 0,
358
+ statusText: "Unknown Error"
359
+ });
360
+ }
361
+ function isApiException(error) {
362
+ return error instanceof ApiException;
363
+ }
364
+ function isValidationError(error) {
365
+ return isApiException(error) && error.status === 400 && !!error.errors;
366
+ }
367
+ function isAuthError(error) {
368
+ return isApiException(error) && (error.status === 401 || error.status === 403);
369
+ }
370
+ function isNotFoundError(error) {
371
+ return isApiException(error) && error.status === 404;
372
+ }
373
+
374
+ // src/lib/fetch-wrapper.ts
375
+ var FetchWrapper = class _FetchWrapper {
376
+ constructor(config) {
377
+ this.isRefreshing = false;
378
+ this.refreshPromise = null;
379
+ this.config = config;
380
+ }
381
+ /**
382
+ * Build headers with auth token
383
+ */
384
+ async buildHeaders(customHeaders) {
385
+ const headers = new Headers(this.config.defaultHeaders);
386
+ if (customHeaders) {
387
+ const customHeadersObj = new Headers(customHeaders);
388
+ customHeadersObj.forEach((value, key) => {
389
+ headers.set(key, value);
390
+ });
391
+ }
392
+ if (this.config.getToken) {
393
+ const token = await this.config.getToken();
394
+ if (token) {
395
+ headers.set("Authorization", `Bearer ${token}`);
396
+ }
397
+ }
398
+ if (!headers.has("Content-Type")) {
399
+ headers.set("Content-Type", "application/json");
400
+ }
401
+ return headers;
402
+ }
403
+ /**
404
+ * Execute fetch request
405
+ */
406
+ async execute(method, endpoint, options) {
407
+ try {
408
+ const { params, headers: customHeaders, ...fetchOptions } = options || {};
409
+ const url = buildUrl({
410
+ baseUrl: this.config.baseUrl ?? "",
411
+ endpoint,
412
+ params
413
+ });
414
+ const headers = await this.buildHeaders(customHeaders);
415
+ let response = await fetch(url, {
416
+ method,
417
+ headers,
418
+ credentials: "include",
419
+ ...fetchOptions
420
+ });
421
+ if (response.status === 401) {
422
+ if (this.config.onTokenRefresh) {
423
+ if (!this.isRefreshing) {
424
+ this.isRefreshing = true;
425
+ this.refreshPromise = this.config.onTokenRefresh().finally(() => {
426
+ this.isRefreshing = false;
427
+ this.refreshPromise = null;
428
+ });
429
+ }
430
+ const newToken = await this.refreshPromise;
431
+ if (newToken) {
432
+ const retryHeaders = new Headers(headers);
433
+ retryHeaders.set("Authorization", `Bearer ${newToken}`);
434
+ response = await fetch(url, {
435
+ method,
436
+ headers: retryHeaders,
437
+ credentials: "include",
438
+ ...fetchOptions
439
+ });
440
+ } else if (this.config.onUnauthorized) {
441
+ this.config.onUnauthorized();
442
+ }
443
+ } else if (this.config.onUnauthorized) {
444
+ this.config.onUnauthorized();
445
+ }
446
+ }
447
+ if (!response.ok) {
448
+ const error = await parseErrorResponse(response);
449
+ throw new ApiException(error.message || "Request failed", error);
450
+ }
451
+ if (response.status === 204) {
452
+ return void 0;
453
+ }
454
+ return await response.json();
455
+ } catch (error) {
456
+ handleFetchError(error);
457
+ }
458
+ }
459
+ /**
460
+ * Return a new FetchWrapper with selected config fields overridden.
461
+ */
462
+ reconfigure(partial) {
463
+ return new _FetchWrapper({ ...this.config, ...partial });
464
+ }
465
+ /**
466
+ * GET request
467
+ */
468
+ async get(endpoint, options) {
469
+ return this.execute("GET", endpoint, options);
470
+ }
471
+ /**
472
+ * POST request
473
+ */
474
+ async post(endpoint, data, options) {
475
+ return this.execute("POST", endpoint, {
476
+ ...options,
477
+ body: data ? JSON.stringify(data) : void 0
478
+ });
479
+ }
480
+ /**
481
+ * PUT request
482
+ */
483
+ async put(endpoint, data, options) {
484
+ return this.execute("PUT", endpoint, {
485
+ ...options,
486
+ body: data ? JSON.stringify(data) : void 0
487
+ });
488
+ }
489
+ /**
490
+ * PATCH request
491
+ */
492
+ async patch(endpoint, data, options) {
493
+ return this.execute("PATCH", endpoint, {
494
+ ...options,
495
+ body: data ? JSON.stringify(data) : void 0
496
+ });
497
+ }
498
+ /**
499
+ * DELETE request
500
+ */
501
+ async delete(endpoint, options) {
502
+ return this.execute("DELETE", endpoint, options);
503
+ }
504
+ };
505
+
506
+ // src/lib/api-client.ts
507
+ var ApiClient = class {
508
+ constructor(config) {
509
+ this.baseUrl = config.baseUrl ?? "";
510
+ this.fetcher = new FetchWrapper({
511
+ baseUrl: config.baseUrl,
512
+ getToken: config.getToken,
513
+ onUnauthorized: config.onUnauthorized,
514
+ onTokenRefresh: config.onTokenRefresh,
515
+ defaultHeaders: {
516
+ "Content-Type": "application/json",
517
+ "Accept": "application/json"
518
+ }
519
+ });
520
+ }
521
+ /**
522
+ * Get the fetch wrapper instance for direct access
523
+ */
524
+ get fetch() {
525
+ return this.fetcher;
526
+ }
527
+ /**
528
+ * Update auth token getter
529
+ */
530
+ setTokenGetter(getToken) {
531
+ this.fetcher = this.fetcher.reconfigure({ getToken });
532
+ }
533
+ /**
534
+ * Update unauthorized handler
535
+ */
536
+ setUnauthorizedHandler(onUnauthorized) {
537
+ this.fetcher = this.fetcher.reconfigure({ onUnauthorized });
538
+ }
539
+ /**
540
+ * Convenience HTTP methods that delegate to FetchWrapper
541
+ */
542
+ async get(endpoint, options) {
543
+ return this.fetcher.get(endpoint, options);
544
+ }
545
+ async post(endpoint, data, options) {
546
+ return this.fetcher.post(endpoint, data, options);
547
+ }
548
+ async patch(endpoint, data, options) {
549
+ return this.fetcher.patch(endpoint, data, options);
550
+ }
551
+ async delete(endpoint, options) {
552
+ return this.fetcher.delete(endpoint, options);
553
+ }
554
+ };
555
+ function createApiClient(config) {
556
+ return new ApiClient(config);
557
+ }
558
+
559
+ // src/constants/endpoints.ts
560
+ var ENDPOINTS = {
561
+ // Contacts
562
+ CONTACTS: "contacts",
563
+ CONTACTS_BULK: "contacts/bulk",
564
+ CONTACT: (id) => `contacts/${id}`,
565
+ // Organizations
566
+ ORGANIZATIONS: "organizations",
567
+ ORGANIZATIONS_BULK: "organizations/bulk",
568
+ ORGANIZATION: (id) => `organizations/${id}`,
569
+ // Core entities
570
+ TAGS: "core/tags",
571
+ TAG: (id) => `core/tags/${id}`,
572
+ ENTITY_TAGS: "core/entity-tags",
573
+ ENTITY_TAG: (id) => `core/entity-tags/${id}`,
574
+ METRICS: "core/metrics",
575
+ METRIC: (id) => `core/metrics/${id}`,
576
+ PROFILES: "core/profiles",
577
+ PROFILE: (id) => `core/profiles/${id}`,
578
+ ATTRIBUTES: "core/attributes",
579
+ ATTRIBUTE: (id) => `core/attributes/${id}`,
580
+ RELATIONSHIPS: "core/relationships",
581
+ RELATIONSHIP: (id) => `core/relationships/${id}`,
582
+ // Workflows
583
+ WORKFLOWS: "workflows",
584
+ WORKFLOW: (id) => `workflows/${id}`,
585
+ WORKFLOW_EXECUTE: (id) => `workflows/${id}/execute`,
586
+ // Messages
587
+ MESSAGES: "messages",
588
+ MESSAGE: (id) => `messages/${id}`,
589
+ MESSAGE_SEND: (id) => `messages/${id}/send`,
590
+ // Funnels
591
+ FUNNELS: "funnels",
592
+ FUNNEL: (id) => `funnels/${id}`,
593
+ FUNNEL_RUN: (id) => `funnels/${id}/run`,
594
+ FUNNEL_RUNS: (id) => `funnels/${id}/runs`,
595
+ FUNNEL_RUN_ITEM: (funnelId, runId) => `funnels/${funnelId}/runs/${runId}`,
596
+ FUNNEL_PREVIEW: (id) => `funnels/${id}/preview`,
597
+ FUNNEL_RESULTS: (id) => `funnels/${id}/results`,
598
+ FUNNEL_TEMPLATES: "funnels/templates",
599
+ FUNNEL_RUN_BY_ID: (runId) => `funnel-runs/${runId}`,
600
+ FUNNEL_RUN_CANCEL: (runId) => `funnel-runs/${runId}/cancel`,
601
+ FUNNEL_RUNS_GLOBAL: "funnel-runs"
602
+ };
603
+
604
+ // src/lib/contacts-api.ts
605
+ var ContactsApi = class {
606
+ constructor(client) {
607
+ this.client = client;
608
+ }
609
+ /**
610
+ * List contacts with pagination and filters
611
+ */
612
+ async list(filters, pagination, sorting) {
613
+ const params = mergeQueryParams(
614
+ pagination,
615
+ sorting,
616
+ filters ? buildFilterParams(filters) : void 0
617
+ );
618
+ return this.client.fetch.get(ENDPOINTS.CONTACTS, { params });
619
+ }
620
+ /**
621
+ * Get contact by ID
622
+ */
623
+ async get(id) {
624
+ return this.client.fetch.get(ENDPOINTS.CONTACT(id));
625
+ }
626
+ /**
627
+ * Create new contact
628
+ */
629
+ async create(data) {
630
+ return this.client.fetch.post(ENDPOINTS.CONTACTS, data);
631
+ }
632
+ /**
633
+ * Update contact
634
+ */
635
+ async update(id, data) {
636
+ return this.client.fetch.patch(ENDPOINTS.CONTACT(id), data);
637
+ }
638
+ /**
639
+ * Delete contact
640
+ */
641
+ async delete(id) {
642
+ return this.client.fetch.delete(ENDPOINTS.CONTACT(id));
643
+ }
644
+ /**
645
+ * Bulk create contacts
646
+ */
647
+ async bulkCreate(data) {
648
+ return this.client.fetch.post(ENDPOINTS.CONTACTS_BULK, data);
649
+ }
650
+ /**
651
+ * Search contacts by name, email, or company
652
+ */
653
+ async search(query, pagination) {
654
+ return this.list({ search: query }, pagination);
655
+ }
656
+ /**
657
+ * Get contacts by tier
658
+ */
659
+ async getByTier(tier, pagination) {
660
+ return this.list({ tier }, pagination);
661
+ }
662
+ /**
663
+ * Get contacts by firm
664
+ */
665
+ async getByFirm(firmId, pagination) {
666
+ return this.list({ firmId }, pagination);
667
+ }
668
+ /**
669
+ * Get contacts with LinkedIn profiles
670
+ */
671
+ async getWithLinkedIn(pagination) {
672
+ return this.list({ hasLinkedin: true }, pagination);
673
+ }
674
+ };
675
+
676
+ // src/lib/organizations-api.ts
677
+ var OrganizationsApi = class {
678
+ constructor(client) {
679
+ this.client = client;
680
+ }
681
+ /**
682
+ * List organizations with pagination and filters
683
+ */
684
+ async list(filters, pagination, sorting) {
685
+ const params = mergeQueryParams(
686
+ pagination,
687
+ sorting,
688
+ filters ? buildFilterParams(filters) : void 0
689
+ );
690
+ return this.client.fetch.get(ENDPOINTS.ORGANIZATIONS, {
691
+ params
692
+ });
693
+ }
694
+ /**
695
+ * Get organization by ID
696
+ */
697
+ async get(id) {
698
+ return this.client.fetch.get(ENDPOINTS.ORGANIZATION(id));
699
+ }
700
+ /**
701
+ * Create new organization
702
+ */
703
+ async create(data) {
704
+ return this.client.fetch.post(ENDPOINTS.ORGANIZATIONS, data);
705
+ }
706
+ /**
707
+ * Update organization
708
+ */
709
+ async update(id, data) {
710
+ return this.client.fetch.patch(ENDPOINTS.ORGANIZATION(id), data);
711
+ }
712
+ /**
713
+ * Delete organization
714
+ */
715
+ async delete(id) {
716
+ return this.client.fetch.delete(ENDPOINTS.ORGANIZATION(id));
717
+ }
718
+ /**
719
+ * Bulk create organizations
720
+ */
721
+ async bulkCreate(data) {
722
+ return this.client.fetch.post(ENDPOINTS.ORGANIZATIONS_BULK, data);
723
+ }
724
+ /**
725
+ * Search organizations by name, domain, or location
726
+ */
727
+ async search(query, pagination) {
728
+ return this.list({ search: query }, pagination);
729
+ }
730
+ /**
731
+ * Get organizations by tier
732
+ */
733
+ async getByTier(tier, pagination) {
734
+ return this.list({ tier }, pagination);
735
+ }
736
+ /**
737
+ * Get organizations by stage
738
+ */
739
+ async getByStage(stage, pagination) {
740
+ return this.list({ stage }, pagination);
741
+ }
742
+ /**
743
+ * Get organizations by focus area
744
+ */
745
+ async getByFocusArea(focusArea, pagination) {
746
+ return this.list({ focusArea }, pagination);
747
+ }
748
+ /**
749
+ * Get organizations by check size range
750
+ */
751
+ async getByCheckSizeRange(min, max, pagination) {
752
+ const filters = {};
753
+ if (min !== void 0) {
754
+ filters.checkSizeMinGte = min;
755
+ }
756
+ if (max !== void 0) {
757
+ filters.checkSizeMaxLte = max;
758
+ }
759
+ return this.list(filters, pagination);
760
+ }
761
+ };
762
+
763
+ // src/lib/entities-api.ts
764
+ var EntitiesApi = class {
765
+ constructor(client) {
766
+ this.client = client;
767
+ }
768
+ /**
769
+ * Tags
770
+ */
771
+ async listTags(pagination) {
772
+ const params = mergeQueryParams(pagination);
773
+ return this.client.fetch.get(ENDPOINTS.TAGS, { params });
774
+ }
775
+ async getTag(id) {
776
+ return this.client.fetch.get(ENDPOINTS.TAG(String(id)));
777
+ }
778
+ async createTag(data) {
779
+ return this.client.fetch.post(ENDPOINTS.TAGS, data);
780
+ }
781
+ /**
782
+ * Entity Tags
783
+ */
784
+ async listEntityTags(pagination, filters) {
785
+ const params = mergeQueryParams(pagination, void 0, filters);
786
+ return this.client.fetch.get(ENDPOINTS.ENTITY_TAGS, {
787
+ params
788
+ });
789
+ }
790
+ async getEntityTag(id) {
791
+ return this.client.fetch.get(ENDPOINTS.ENTITY_TAG(String(id)));
792
+ }
793
+ /**
794
+ * Metrics
795
+ */
796
+ async listMetrics(pagination, filters) {
797
+ const params = mergeQueryParams(pagination, void 0, filters);
798
+ return this.client.fetch.get(ENDPOINTS.METRICS, { params });
799
+ }
800
+ async getMetric(id) {
801
+ return this.client.fetch.get(ENDPOINTS.METRIC(String(id)));
802
+ }
803
+ /**
804
+ * Profiles
805
+ */
806
+ async listProfiles(pagination, filters) {
807
+ const params = mergeQueryParams(pagination, void 0, filters);
808
+ return this.client.fetch.get(ENDPOINTS.PROFILES, { params });
809
+ }
810
+ async getProfile(id) {
811
+ return this.client.fetch.get(ENDPOINTS.PROFILE(String(id)));
812
+ }
813
+ /**
814
+ * Attributes
815
+ */
816
+ async listAttributes(pagination, filters) {
817
+ const params = mergeQueryParams(pagination, void 0, filters);
818
+ return this.client.fetch.get(ENDPOINTS.ATTRIBUTES, {
819
+ params
820
+ });
821
+ }
822
+ async getAttribute(id) {
823
+ return this.client.fetch.get(ENDPOINTS.ATTRIBUTE(String(id)));
824
+ }
825
+ /**
826
+ * Relationships
827
+ */
828
+ async listRelationships(pagination, filters) {
829
+ const params = mergeQueryParams(pagination, void 0, filters);
830
+ return this.client.fetch.get(ENDPOINTS.RELATIONSHIPS, {
831
+ params
832
+ });
833
+ }
834
+ async getRelationship(id) {
835
+ return this.client.fetch.get(ENDPOINTS.RELATIONSHIP(String(id)));
836
+ }
837
+ };
838
+
839
+ // src/lib/workflows-api.ts
840
+ var WorkflowsApi = class {
841
+ constructor(client) {
842
+ this.client = client;
843
+ }
844
+ /**
845
+ * List workflows with optional filters
846
+ */
847
+ async list(filters) {
848
+ const params = new URLSearchParams();
849
+ if (filters?.team) params.append("team", filters.team);
850
+ if (filters?.isActive !== void 0) params.append("isActive", String(filters.isActive));
851
+ if (filters?.isTemplate !== void 0) params.append("isTemplate", String(filters.isTemplate));
852
+ if (filters?.page) params.append("page", String(filters.page));
853
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
854
+ if (filters?.ordering) params.append("ordering", filters.ordering);
855
+ return this.client.get(
856
+ `/api/v1/workflows/?${params.toString()}`
857
+ );
858
+ }
859
+ /**
860
+ * Get workflow by ID
861
+ */
862
+ async get(id) {
863
+ return this.client.get(`/api/v1/workflows/${id}/`);
864
+ }
865
+ /**
866
+ * Create a new workflow
867
+ */
868
+ async create(data) {
869
+ return this.client.post("/api/v1/workflows/", data);
870
+ }
871
+ /**
872
+ * Update workflow
873
+ */
874
+ async update(id, data) {
875
+ return this.client.patch(`/api/v1/workflows/${id}/`, data);
876
+ }
877
+ /**
878
+ * Delete workflow
879
+ */
880
+ async delete(id) {
881
+ return this.client.delete(`/api/v1/workflows/${id}/`);
882
+ }
883
+ /**
884
+ * Execute workflow
885
+ */
886
+ async execute(id, input) {
887
+ return this.client.post(
888
+ `/api/v1/workflows/${id}/execute/`,
889
+ input || {}
890
+ );
891
+ }
892
+ /**
893
+ * Get workflow templates
894
+ */
895
+ async templates() {
896
+ return this.client.get("/api/v1/workflows/templates/");
897
+ }
898
+ /**
899
+ * List workflow executions
900
+ */
901
+ async listExecutions(filters) {
902
+ const params = new URLSearchParams();
903
+ if (filters?.workflow) params.append("workflow", filters.workflow);
904
+ if (filters?.status) params.append("status", filters.status);
905
+ if (filters?.page) params.append("page", String(filters.page));
906
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
907
+ return this.client.get(
908
+ `/api/v1/workflow-executions/?${params.toString()}`
909
+ );
910
+ }
911
+ /**
912
+ * Get workflow execution details
913
+ */
914
+ async getExecution(id) {
915
+ return this.client.get(`/api/v1/workflow-executions/${id}/`);
916
+ }
917
+ };
918
+
919
+ // src/lib/messages-api.ts
920
+ var MessagesApi = class {
921
+ constructor(client) {
922
+ this.client = client;
923
+ }
924
+ /**
925
+ * List messages with optional filters
926
+ */
927
+ async list(filters) {
928
+ const params = new URLSearchParams();
929
+ if (filters?.status) params.append("status", filters.status);
930
+ if (filters?.contentType) params.append("contentType", filters.contentType);
931
+ if (filters?.scheduledAfter) params.append("scheduledAfter", filters.scheduledAfter);
932
+ if (filters?.scheduledBefore) params.append("scheduledBefore", filters.scheduledBefore);
933
+ if (filters?.sentAfter) params.append("sentAfter", filters.sentAfter);
934
+ if (filters?.sentBefore) params.append("sentBefore", filters.sentBefore);
935
+ if (filters?.search) params.append("search", filters.search);
936
+ if (filters?.page) params.append("page", String(filters.page));
937
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
938
+ if (filters?.ordering) params.append("ordering", filters.ordering);
939
+ return this.client.get(
940
+ `/api/v1/messages/?${params.toString()}`
941
+ );
942
+ }
943
+ /**
944
+ * Get message by ID
945
+ */
946
+ async get(id) {
947
+ return this.client.get(`/api/v1/messages/${id}/`);
948
+ }
949
+ /**
950
+ * Create a new message
951
+ */
952
+ async create(data) {
953
+ return this.client.post("/api/v1/messages/", data);
954
+ }
955
+ /**
956
+ * Update message (draft only)
957
+ */
958
+ async update(id, data) {
959
+ return this.client.patch(`/api/v1/messages/${id}/`, data);
960
+ }
961
+ /**
962
+ * Delete message (draft only)
963
+ */
964
+ async delete(id) {
965
+ return this.client.delete(`/api/v1/messages/${id}/`);
966
+ }
967
+ /**
968
+ * Schedule message for future sending
969
+ */
970
+ async schedule(id, input) {
971
+ return this.client.post(
972
+ `/api/v1/messages/${id}/schedule/`,
973
+ input
974
+ );
975
+ }
976
+ /**
977
+ * Send message immediately
978
+ */
979
+ async sendNow(id) {
980
+ return this.client.post(
981
+ `/api/v1/messages/${id}/send_now/`,
982
+ {}
983
+ );
984
+ }
985
+ /**
986
+ * Send test message
987
+ */
988
+ async sendTest(id, input) {
989
+ return this.client.post(
990
+ `/api/v1/messages/${id}/send_test/`,
991
+ input || {}
992
+ );
993
+ }
994
+ /**
995
+ * Preview message rendering
996
+ */
997
+ async preview(id) {
998
+ return this.client.get(`/api/v1/messages/${id}/preview/`);
999
+ }
1000
+ /**
1001
+ * List recipients for a message
1002
+ */
1003
+ async getRecipients(id, page, pageSize) {
1004
+ const params = new URLSearchParams();
1005
+ if (page) params.append("page", String(page));
1006
+ if (pageSize) params.append("pageSize", String(pageSize));
1007
+ return this.client.get(
1008
+ `/api/v1/messages/${id}/recipients/?${params.toString()}`
1009
+ );
1010
+ }
1011
+ /**
1012
+ * Add recipients to a message
1013
+ */
1014
+ async addRecipients(id, recipients) {
1015
+ return this.client.post(`/api/v1/messages/${id}/add_recipients/`, { recipients });
1016
+ }
1017
+ /**
1018
+ * Get available messaging channels
1019
+ */
1020
+ async getChannels() {
1021
+ return this.client.get("/api/v1/messages/channels/");
1022
+ }
1023
+ };
1024
+
1025
+ // src/lib/funnels-api.ts
1026
+ function isFunnelRunConflict(error) {
1027
+ return isApiException(error) && error.status === 409;
1028
+ }
1029
+ function isFunnelValidationError(error) {
1030
+ return isApiException(error) && error.status === 400 && !!error.errors;
1031
+ }
1032
+ var FunnelsApi = class {
1033
+ constructor(client) {
1034
+ this.client = client;
1035
+ }
1036
+ /**
1037
+ * List funnels with optional filters.
1038
+ * Tags are passed as repeated query params: ?tags=campaign:abc&tags=product:market-simpli
1039
+ */
1040
+ async list(filters) {
1041
+ const params = new URLSearchParams();
1042
+ if (filters?.status) params.append("status", filters.status);
1043
+ if (filters?.entityType) params.append("entityType", filters.entityType);
1044
+ if (filters?.search) params.append("search", filters.search);
1045
+ if (filters?.createdBy) params.append("createdBy", filters.createdBy);
1046
+ if (filters?.page) params.append("page", String(filters.page));
1047
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
1048
+ if (filters?.ordering) params.append("ordering", filters.ordering);
1049
+ if (filters?.tags?.length) {
1050
+ for (const tag of filters.tags) {
1051
+ params.append("tags", tag);
1052
+ }
1053
+ }
1054
+ const query = params.toString();
1055
+ const endpoint = query ? `${ENDPOINTS.FUNNELS}?${query}` : ENDPOINTS.FUNNELS;
1056
+ return this.client.get(endpoint);
1057
+ }
1058
+ /**
1059
+ * Get funnel by ID
1060
+ */
1061
+ async get(id) {
1062
+ return this.client.get(ENDPOINTS.FUNNEL(id));
1063
+ }
1064
+ /**
1065
+ * Create a new funnel
1066
+ */
1067
+ async create(data) {
1068
+ return this.client.post(ENDPOINTS.FUNNELS, data);
1069
+ }
1070
+ /**
1071
+ * Update funnel (partial)
1072
+ */
1073
+ async update(id, data) {
1074
+ return this.client.patch(ENDPOINTS.FUNNEL(id), data);
1075
+ }
1076
+ /**
1077
+ * Delete funnel
1078
+ */
1079
+ async delete(id) {
1080
+ return this.client.delete(ENDPOINTS.FUNNEL(id));
1081
+ }
1082
+ /**
1083
+ * Execute a funnel run
1084
+ */
1085
+ async run(id, input) {
1086
+ return this.client.post(ENDPOINTS.FUNNEL_RUN(id), input ?? {});
1087
+ }
1088
+ /**
1089
+ * List run history for a funnel
1090
+ */
1091
+ async getRuns(funnelId, filters) {
1092
+ const params = new URLSearchParams();
1093
+ if (filters?.page) params.append("page", String(filters.page));
1094
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
1095
+ if (filters?.status) params.append("status", filters.status);
1096
+ if (filters?.ordering) params.append("ordering", filters.ordering);
1097
+ const query = params.toString();
1098
+ const endpoint = query ? `${ENDPOINTS.FUNNEL_RUNS(funnelId)}?${query}` : ENDPOINTS.FUNNEL_RUNS(funnelId);
1099
+ return this.client.get(endpoint);
1100
+ }
1101
+ /**
1102
+ * Get a specific run by ID. funnelId param is ignored (runs are accessed globally).
1103
+ */
1104
+ async getRun(_funnelId, runId) {
1105
+ return this.client.get(ENDPOINTS.FUNNEL_RUN_BY_ID(runId));
1106
+ }
1107
+ // BEAD: fund-your-startup-rgi4 - funnels/{id}/results endpoint missing from Django FunnelViewSet
1108
+ async getResults(_funnelId, _pagination) {
1109
+ throw new Error("Not implemented - BEAD: fund-your-startup-rgi4. funnels/{id}/results action does not exist in Django.");
1110
+ }
1111
+ // BEAD: fund-your-startup-rgi4 - funnels/{id}/preview endpoint missing. Django has /funnels/preview-icp/ (different signature).
1112
+ async preview(_funnelId, _stages) {
1113
+ throw new Error("Not implemented - BEAD: fund-your-startup-rgi4. funnels/{id}/preview action does not exist in Django.");
1114
+ }
1115
+ /**
1116
+ * List all funnel runs globally (across all funnels, scoped to current user)
1117
+ */
1118
+ async listRunsGlobal(filters) {
1119
+ const params = new URLSearchParams();
1120
+ if (filters?.funnel) params.append("funnel", filters.funnel);
1121
+ if (filters?.status) params.append("status", filters.status);
1122
+ if (filters?.page) params.append("page", String(filters.page));
1123
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
1124
+ if (filters?.startedAfter) params.append("startedAfter", filters.startedAfter);
1125
+ if (filters?.startedBefore) params.append("startedBefore", filters.startedBefore);
1126
+ const query = params.toString();
1127
+ const endpoint = query ? `${ENDPOINTS.FUNNEL_RUNS_GLOBAL}?${query}` : ENDPOINTS.FUNNEL_RUNS_GLOBAL;
1128
+ return this.client.get(endpoint);
1129
+ }
1130
+ /**
1131
+ * Cancel a running funnel run.
1132
+ */
1133
+ async cancelRun(runId) {
1134
+ return this.client.post(ENDPOINTS.FUNNEL_RUN_CANCEL(runId), {});
1135
+ }
1136
+ /**
1137
+ * List available funnel templates
1138
+ */
1139
+ async listTemplates(filters) {
1140
+ const params = new URLSearchParams();
1141
+ if (filters?.category) params.append("category", filters.category);
1142
+ if (filters?.page) params.append("page", String(filters.page));
1143
+ if (filters?.pageSize) params.append("pageSize", String(filters.pageSize));
1144
+ const query = params.toString();
1145
+ const endpoint = query ? `${ENDPOINTS.FUNNEL_TEMPLATES}?${query}` : ENDPOINTS.FUNNEL_TEMPLATES;
1146
+ return this.client.get(endpoint);
1147
+ }
1148
+ };
1149
+
1150
+ // src/lib/errors.ts
1151
+ var AppErrorCode = /* @__PURE__ */ ((AppErrorCode2) => {
1152
+ AppErrorCode2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
1153
+ AppErrorCode2["AUTHENTICATION_REQUIRED"] = "AUTHENTICATION_REQUIRED";
1154
+ AppErrorCode2["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
1155
+ AppErrorCode2["SESSION_EXPIRED"] = "SESSION_EXPIRED";
1156
+ AppErrorCode2["FORBIDDEN"] = "FORBIDDEN";
1157
+ AppErrorCode2["INSUFFICIENT_PERMISSIONS"] = "INSUFFICIENT_PERMISSIONS";
1158
+ AppErrorCode2["NOT_FOUND"] = "NOT_FOUND";
1159
+ AppErrorCode2["RESOURCE_NOT_FOUND"] = "RESOURCE_NOT_FOUND";
1160
+ AppErrorCode2["CONFLICT"] = "CONFLICT";
1161
+ AppErrorCode2["DUPLICATE_RESOURCE"] = "DUPLICATE_RESOURCE";
1162
+ AppErrorCode2["RATE_LIMITED"] = "RATE_LIMITED";
1163
+ AppErrorCode2["BAD_REQUEST"] = "BAD_REQUEST";
1164
+ AppErrorCode2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
1165
+ AppErrorCode2["DATABASE_ERROR"] = "DATABASE_ERROR";
1166
+ AppErrorCode2["EXTERNAL_SERVICE_ERROR"] = "EXTERNAL_SERVICE_ERROR";
1167
+ AppErrorCode2["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
1168
+ return AppErrorCode2;
1169
+ })(AppErrorCode || {});
1170
+ var AppError = class _AppError extends Error {
1171
+ constructor(message, code = "INTERNAL_ERROR" /* INTERNAL_ERROR */, statusCode = 500, details, isOperational = true) {
1172
+ super(message);
1173
+ this.name = "AppError";
1174
+ this.code = code;
1175
+ this.statusCode = statusCode;
1176
+ this.details = details;
1177
+ this.isOperational = isOperational;
1178
+ Error.captureStackTrace(this, this.constructor);
1179
+ }
1180
+ /**
1181
+ * Serialize error for API response
1182
+ */
1183
+ toResponse() {
1184
+ return {
1185
+ error: {
1186
+ code: this.code,
1187
+ message: this.message,
1188
+ ...this.details && { details: this.details }
1189
+ }
1190
+ };
1191
+ }
1192
+ /**
1193
+ * Check if an error is an operational error (expected) vs programming error
1194
+ */
1195
+ static isOperationalError(error) {
1196
+ return error instanceof _AppError && error.isOperational;
1197
+ }
1198
+ };
1199
+ var ValidationError = class _ValidationError extends AppError {
1200
+ constructor(message = "Validation failed", fieldErrors = {}) {
1201
+ super(
1202
+ message,
1203
+ "VALIDATION_ERROR" /* VALIDATION_ERROR */,
1204
+ 400,
1205
+ { fields: fieldErrors }
1206
+ );
1207
+ this.name = "ValidationError";
1208
+ this.fieldErrors = fieldErrors;
1209
+ }
1210
+ /**
1211
+ * Create from Zod error
1212
+ */
1213
+ static fromZodError(zodError) {
1214
+ const fieldErrors = {};
1215
+ for (const error of zodError.errors) {
1216
+ const path = error.path.join(".");
1217
+ if (!fieldErrors[path]) {
1218
+ fieldErrors[path] = [];
1219
+ }
1220
+ fieldErrors[path].push(error.message);
1221
+ }
1222
+ const message = Object.entries(fieldErrors).map(([field, errors]) => `${field}: ${errors.join(", ")}`).join("; ");
1223
+ return new _ValidationError(`Validation failed: ${message}`, fieldErrors);
1224
+ }
1225
+ };
1226
+ var AuthenticationError = class _AuthenticationError extends AppError {
1227
+ constructor(message = "Authentication required", code = "AUTHENTICATION_REQUIRED" /* AUTHENTICATION_REQUIRED */) {
1228
+ super(message, code, 401);
1229
+ this.name = "AuthenticationError";
1230
+ }
1231
+ /**
1232
+ * Create for invalid credentials
1233
+ */
1234
+ static invalidCredentials() {
1235
+ return new _AuthenticationError("Invalid credentials", "INVALID_CREDENTIALS" /* INVALID_CREDENTIALS */);
1236
+ }
1237
+ /**
1238
+ * Create for expired session
1239
+ */
1240
+ static sessionExpired() {
1241
+ return new _AuthenticationError("Session has expired", "SESSION_EXPIRED" /* SESSION_EXPIRED */);
1242
+ }
1243
+ };
1244
+ var AuthorizationError = class _AuthorizationError extends AppError {
1245
+ constructor(message = "Access denied", code = "FORBIDDEN" /* FORBIDDEN */) {
1246
+ super(message, code, 403);
1247
+ this.name = "AuthorizationError";
1248
+ }
1249
+ /**
1250
+ * Create for insufficient permissions
1251
+ */
1252
+ static insufficientPermissions(requiredPermission) {
1253
+ const message = requiredPermission ? `Insufficient permissions. Required: ${requiredPermission}` : "Insufficient permissions";
1254
+ return new _AuthorizationError(message, "INSUFFICIENT_PERMISSIONS" /* INSUFFICIENT_PERMISSIONS */);
1255
+ }
1256
+ };
1257
+ var NotFoundError = class _NotFoundError extends AppError {
1258
+ constructor(message = "Resource not found", resourceType, resourceId) {
1259
+ super(
1260
+ message,
1261
+ "NOT_FOUND" /* NOT_FOUND */,
1262
+ 404,
1263
+ resourceType || resourceId ? { resourceType, resourceId } : void 0
1264
+ );
1265
+ this.name = "NotFoundError";
1266
+ this.resourceType = resourceType;
1267
+ this.resourceId = resourceId;
1268
+ }
1269
+ /**
1270
+ * Create for a specific resource
1271
+ */
1272
+ static forResource(resourceType, resourceId) {
1273
+ const message = resourceId ? `${resourceType} with ID '${resourceId}' not found` : `${resourceType} not found`;
1274
+ return new _NotFoundError(message, resourceType, resourceId);
1275
+ }
1276
+ };
1277
+ var ConflictError = class _ConflictError extends AppError {
1278
+ constructor(message = "Resource conflict", conflictingField) {
1279
+ super(
1280
+ message,
1281
+ "CONFLICT" /* CONFLICT */,
1282
+ 409,
1283
+ conflictingField ? { field: conflictingField } : void 0
1284
+ );
1285
+ this.name = "ConflictError";
1286
+ this.conflictingField = conflictingField;
1287
+ }
1288
+ /**
1289
+ * Create for duplicate resource
1290
+ */
1291
+ static duplicate(resourceType, field) {
1292
+ const message = field ? `A ${resourceType} with this ${field} already exists` : `A ${resourceType} with these values already exists`;
1293
+ return new _ConflictError(message, field);
1294
+ }
1295
+ };
1296
+ var RateLimitError = class extends AppError {
1297
+ constructor(message = "Too many requests", retryAfter) {
1298
+ super(
1299
+ message,
1300
+ "RATE_LIMITED" /* RATE_LIMITED */,
1301
+ 429,
1302
+ retryAfter ? { retryAfter } : void 0
1303
+ );
1304
+ this.name = "RateLimitError";
1305
+ this.retryAfter = retryAfter;
1306
+ }
1307
+ };
1308
+ var DatabaseError = class _DatabaseError extends AppError {
1309
+ constructor(message = "Database operation failed", details) {
1310
+ const safeDetails = process.env.NODE_ENV === "development" ? details : void 0;
1311
+ super(message, "DATABASE_ERROR" /* DATABASE_ERROR */, 500, safeDetails);
1312
+ this.name = "DatabaseError";
1313
+ }
1314
+ /**
1315
+ * Create from Prisma error
1316
+ */
1317
+ static fromPrismaError(error) {
1318
+ const code = error.code;
1319
+ switch (code) {
1320
+ case "P2002":
1321
+ throw ConflictError.duplicate("record", error.meta?.target?.[0]);
1322
+ case "P2025":
1323
+ throw new NotFoundError("Record not found");
1324
+ case "P2003":
1325
+ throw new ConflictError("Cannot perform operation due to related records");
1326
+ default:
1327
+ return new _DatabaseError("Database operation failed", { code });
1328
+ }
1329
+ }
1330
+ };
1331
+ var ExternalServiceError = class extends AppError {
1332
+ constructor(serviceName, message = "External service error", details) {
1333
+ super(
1334
+ message,
1335
+ "EXTERNAL_SERVICE_ERROR" /* EXTERNAL_SERVICE_ERROR */,
1336
+ 502,
1337
+ { service: serviceName, ...details }
1338
+ );
1339
+ this.name = "ExternalServiceError";
1340
+ this.serviceName = serviceName;
1341
+ }
1342
+ };
1343
+ function isPrismaError(error) {
1344
+ return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string";
1345
+ }
1346
+ function toAppError(error) {
1347
+ if (error instanceof AppError) {
1348
+ return error;
1349
+ }
1350
+ if (isPrismaError(error)) {
1351
+ return DatabaseError.fromPrismaError(error);
1352
+ }
1353
+ if (error instanceof Error) {
1354
+ return new AppError(
1355
+ error.message,
1356
+ "INTERNAL_ERROR" /* INTERNAL_ERROR */,
1357
+ 500,
1358
+ process.env.NODE_ENV === "development" ? { stack: error.stack } : void 0
1359
+ );
1360
+ }
1361
+ return new AppError(
1362
+ "An unexpected error occurred",
1363
+ "INTERNAL_ERROR" /* INTERNAL_ERROR */,
1364
+ 500
1365
+ );
1366
+ }
1367
+ function sanitizeHtml(input) {
1368
+ return DOMPurify__default.default.sanitize(input, {
1369
+ ALLOWED_TAGS: ["b", "i", "em", "strong", "a", "p", "br"],
1370
+ ALLOWED_ATTR: ["href"],
1371
+ ALLOW_DATA_ATTR: false
1372
+ });
1373
+ }
1374
+ function sanitizeSearchQuery(query) {
1375
+ if (!query || typeof query !== "string") {
1376
+ return "";
1377
+ }
1378
+ return query.trim().replace(/[.*+?^${}()|[\]\\]/g, "\\$&").substring(0, 100);
1379
+ }
1380
+ function validateIdentifier(input) {
1381
+ return /^[a-zA-Z0-9_-]+$/.test(input);
1382
+ }
1383
+
1384
+ // src/lib/llm-sanitize.ts
1385
+ var MAX_PROMPT_LENGTH = 2e3;
1386
+ var MAX_CHAT_MESSAGE_LENGTH = 1e3;
1387
+ var INJECTION_PATTERNS = [
1388
+ // System/role injection attempts
1389
+ /\bSYSTEM\s*:/gi,
1390
+ /\bASSISTANT\s*:/gi,
1391
+ /\bUSER\s*:/gi,
1392
+ /\bHUMAN\s*:/gi,
1393
+ /\bAI\s*:/gi,
1394
+ // Instruction override attempts
1395
+ /\bignore\s+(previous|above|all)\s+instructions?\b/gi,
1396
+ /\bdisregard\s+(previous|above|all)\s+instructions?\b/gi,
1397
+ /\bforget\s+(previous|above|all)\s+instructions?\b/gi,
1398
+ /\bnew\s+instructions?\s*:/gi,
1399
+ /\boverride\s*:/gi,
1400
+ // Role-playing attempts
1401
+ /\byou\s+are\s+now\b/gi,
1402
+ /\bact\s+as\s+(if|a|an|the)\b/gi,
1403
+ /\bpretend\s+(to\s+be|you\s+are)\b/gi,
1404
+ // JSON/schema manipulation
1405
+ /\b(output|respond|return)\s+only\s*:/gi,
1406
+ /\bformat\s*:\s*json\b/gi
1407
+ ];
1408
+ var FORMATTING_MARKERS = [
1409
+ "```",
1410
+ // Code blocks
1411
+ "---",
1412
+ // Horizontal rules (when at line start)
1413
+ "***",
1414
+ // Alternative horizontal rules
1415
+ "##",
1416
+ // Headers (when at line start)
1417
+ ">>"
1418
+ // Potential quote injection
1419
+ ];
1420
+ var CONTROL_CHAR_REGEX = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
1421
+ function sanitizeUserInput(input, maxLength = MAX_PROMPT_LENGTH) {
1422
+ if (!input || typeof input !== "string") {
1423
+ return "";
1424
+ }
1425
+ let sanitized = input;
1426
+ sanitized = sanitized.replace(CONTROL_CHAR_REGEX, "");
1427
+ sanitized = sanitized.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\n{3,}/g, "\n\n").replace(/[ \t]{3,}/g, " ").trim();
1428
+ for (const pattern of INJECTION_PATTERNS) {
1429
+ sanitized = sanitized.replace(pattern, (match) => {
1430
+ return `[${match.replace(/:/g, "")}]`;
1431
+ });
1432
+ }
1433
+ for (const marker of FORMATTING_MARKERS) {
1434
+ const escapeRegex = new RegExp(`(^|\\n)(${escapeRegexChars(marker)})`, "g");
1435
+ sanitized = sanitized.replace(escapeRegex, (_, prefix, match) => {
1436
+ return `${prefix}[${match}]`;
1437
+ });
1438
+ }
1439
+ if (sanitized.length > maxLength) {
1440
+ sanitized = truncateAtWordBoundary(sanitized, maxLength);
1441
+ }
1442
+ return sanitized;
1443
+ }
1444
+ function sanitizeChatMessage(input) {
1445
+ return sanitizeUserInput(input, MAX_CHAT_MESSAGE_LENGTH);
1446
+ }
1447
+ function truncateAtWordBoundary(text, maxLength) {
1448
+ if (text.length <= maxLength) {
1449
+ return text;
1450
+ }
1451
+ const truncated = text.slice(0, maxLength);
1452
+ const lastSpace = truncated.lastIndexOf(" ");
1453
+ if (lastSpace > maxLength * 0.8) {
1454
+ return truncated.slice(0, lastSpace).trim();
1455
+ }
1456
+ return truncated.trim();
1457
+ }
1458
+ function escapeRegexChars(str) {
1459
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1460
+ }
1461
+
1462
+ // src/lib/cors.ts
1463
+ var DEFAULT_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"];
1464
+ var DEFAULT_HEADERS = ["Content-Type", "Authorization", "X-Requested-With", "Accept", "X-CSRF-Token"];
1465
+ function isAllowed(origin, options) {
1466
+ if (!origin) return false;
1467
+ if (options.origins === "*") return true;
1468
+ return options.origins.includes(origin);
1469
+ }
1470
+ function getCorsHeaders(origin, options) {
1471
+ if (!isAllowed(origin, options)) {
1472
+ return {};
1473
+ }
1474
+ const methods = options.methods ?? DEFAULT_METHODS;
1475
+ const headers = options.headers ?? DEFAULT_HEADERS;
1476
+ const credentials = options.credentials ?? options.origins !== "*";
1477
+ const maxAge = options.maxAge ?? 86400;
1478
+ const result = {
1479
+ "Access-Control-Allow-Origin": options.origins === "*" ? "*" : origin,
1480
+ "Access-Control-Allow-Methods": methods.join(", "),
1481
+ "Access-Control-Allow-Headers": headers.join(", "),
1482
+ "Access-Control-Max-Age": String(maxAge)
1483
+ };
1484
+ if (credentials && options.origins !== "*") {
1485
+ result["Access-Control-Allow-Credentials"] = "true";
1486
+ }
1487
+ return result;
1488
+ }
1489
+ function applyCorsHeaders(responseHeaders, origin, options) {
1490
+ const corsHeaders = getCorsHeaders(origin, options);
1491
+ for (const [key, value] of Object.entries(corsHeaders)) {
1492
+ responseHeaders.set(key, value);
1493
+ }
1494
+ }
1495
+ function createCorsMiddleware(options) {
1496
+ return function corsMiddleware(request) {
1497
+ const origin = request.headers.get("origin");
1498
+ if (request.method === "OPTIONS") {
1499
+ const corsHeaders = getCorsHeaders(origin, options);
1500
+ return new Response(null, { status: 204, headers: corsHeaders });
1501
+ }
1502
+ return null;
1503
+ };
1504
+ }
1505
+
1506
+ // src/types/response.ts
1507
+ var ErrorCodes = /* @__PURE__ */ ((ErrorCodes2) => {
1508
+ ErrorCodes2["UNAUTHORIZED"] = "UNAUTHORIZED";
1509
+ ErrorCodes2["FORBIDDEN"] = "FORBIDDEN";
1510
+ ErrorCodes2["NOT_FOUND"] = "NOT_FOUND";
1511
+ ErrorCodes2["VALIDATION_ERROR"] = "VALIDATION_ERROR";
1512
+ ErrorCodes2["CONFLICT"] = "CONFLICT";
1513
+ ErrorCodes2["INTERNAL_ERROR"] = "INTERNAL_ERROR";
1514
+ ErrorCodes2["SERVICE_UNAVAILABLE"] = "SERVICE_UNAVAILABLE";
1515
+ ErrorCodes2["RATE_LIMITED"] = "RATE_LIMITED";
1516
+ return ErrorCodes2;
1517
+ })(ErrorCodes || {});
1518
+ var FieldErrorSchema = zod.z.object({
1519
+ field: zod.z.string(),
1520
+ messages: zod.z.array(zod.z.string()),
1521
+ code: zod.z.string().optional()
1522
+ });
1523
+ var StandardErrorResponseSchema = zod.z.object({
1524
+ error: zod.z.string(),
1525
+ code: zod.z.string(),
1526
+ statusCode: zod.z.number().int().min(400).max(599),
1527
+ fieldErrors: zod.z.array(FieldErrorSchema).optional(),
1528
+ details: zod.z.record(zod.z.unknown()).optional(),
1529
+ requestId: zod.z.string().optional(),
1530
+ timestamp: zod.z.string().datetime().optional()
1531
+ });
1532
+ var ErrorCode = /* @__PURE__ */ ((ErrorCode2) => {
1533
+ ErrorCode2["BAD_REQUEST"] = "bad_request";
1534
+ ErrorCode2["UNAUTHORIZED"] = "unauthorized";
1535
+ ErrorCode2["FORBIDDEN"] = "forbidden";
1536
+ ErrorCode2["NOT_FOUND"] = "not_found";
1537
+ ErrorCode2["METHOD_NOT_ALLOWED"] = "method_not_allowed";
1538
+ ErrorCode2["VALIDATION_ERROR"] = "validation_error";
1539
+ ErrorCode2["CONFLICT"] = "conflict";
1540
+ ErrorCode2["RATE_LIMITED"] = "rate_limited";
1541
+ ErrorCode2["INTERNAL_ERROR"] = "internal_error";
1542
+ ErrorCode2["SERVICE_UNAVAILABLE"] = "service_unavailable";
1543
+ ErrorCode2["GATEWAY_TIMEOUT"] = "gateway_timeout";
1544
+ ErrorCode2["NETWORK_ERROR"] = "network_error";
1545
+ ErrorCode2["TIMEOUT"] = "timeout";
1546
+ ErrorCode2["UNKNOWN"] = "unknown";
1547
+ return ErrorCode2;
1548
+ })(ErrorCode || {});
1549
+ function getErrorCodeFromStatus(status) {
1550
+ const codeMap = {
1551
+ 400: "bad_request" /* BAD_REQUEST */,
1552
+ 401: "unauthorized" /* UNAUTHORIZED */,
1553
+ 403: "forbidden" /* FORBIDDEN */,
1554
+ 404: "not_found" /* NOT_FOUND */,
1555
+ 405: "method_not_allowed" /* METHOD_NOT_ALLOWED */,
1556
+ 409: "conflict" /* CONFLICT */,
1557
+ 422: "validation_error" /* VALIDATION_ERROR */,
1558
+ 429: "rate_limited" /* RATE_LIMITED */,
1559
+ 500: "internal_error" /* INTERNAL_ERROR */,
1560
+ 503: "service_unavailable" /* SERVICE_UNAVAILABLE */,
1561
+ 504: "gateway_timeout" /* GATEWAY_TIMEOUT */
1562
+ };
1563
+ return codeMap[status] || "unknown" /* UNKNOWN */;
1564
+ }
1565
+ var ErrorMessages = {
1566
+ ["bad_request" /* BAD_REQUEST */]: "The request was invalid. Please check your input.",
1567
+ ["unauthorized" /* UNAUTHORIZED */]: "You need to log in to access this resource.",
1568
+ ["forbidden" /* FORBIDDEN */]: "You don't have permission to access this resource.",
1569
+ ["not_found" /* NOT_FOUND */]: "The requested resource was not found.",
1570
+ ["method_not_allowed" /* METHOD_NOT_ALLOWED */]: "This operation is not allowed.",
1571
+ ["validation_error" /* VALIDATION_ERROR */]: "Please fix the errors in your form.",
1572
+ ["conflict" /* CONFLICT */]: "This operation conflicts with existing data.",
1573
+ ["rate_limited" /* RATE_LIMITED */]: "Too many requests. Please slow down.",
1574
+ ["internal_error" /* INTERNAL_ERROR */]: "An unexpected error occurred. Please try again.",
1575
+ ["service_unavailable" /* SERVICE_UNAVAILABLE */]: "The service is temporarily unavailable.",
1576
+ ["gateway_timeout" /* GATEWAY_TIMEOUT */]: "The request took too long. Please try again.",
1577
+ ["network_error" /* NETWORK_ERROR */]: "Network error. Please check your connection.",
1578
+ ["timeout" /* TIMEOUT */]: "The request timed out. Please try again.",
1579
+ ["unknown" /* UNKNOWN */]: "An unknown error occurred."
1580
+ };
1581
+
1582
+ // src/lib/rate-limit.ts
1583
+ var CLEANUP_INTERVAL_MS = 10 * 60 * 1e3;
1584
+ function createRateLimiter(options) {
1585
+ const { windowMs, maxRequests, keyPrefix = "" } = options;
1586
+ const store = /* @__PURE__ */ new Map();
1587
+ let lastCleanup = Date.now();
1588
+ function cleanup() {
1589
+ const now = Date.now();
1590
+ if (now - lastCleanup < CLEANUP_INTERVAL_MS) return;
1591
+ lastCleanup = now;
1592
+ for (const [key, entry] of store.entries()) {
1593
+ if (now > entry.resetAt) store.delete(key);
1594
+ }
1595
+ }
1596
+ return function check(key) {
1597
+ cleanup();
1598
+ const storeKey = keyPrefix ? `${keyPrefix}:${key}` : key;
1599
+ const now = Date.now();
1600
+ const entry = store.get(storeKey);
1601
+ if (!entry || now > entry.resetAt) {
1602
+ const resetAt = now + windowMs;
1603
+ store.set(storeKey, { count: 1, resetAt });
1604
+ return { success: true, remaining: maxRequests - 1, resetAt };
1605
+ }
1606
+ if (entry.count >= maxRequests) {
1607
+ const retryAfter = Math.ceil((entry.resetAt - now) / 1e3);
1608
+ return { success: false, remaining: 0, resetAt: entry.resetAt, retryAfter };
1609
+ }
1610
+ entry.count++;
1611
+ return { success: true, remaining: maxRequests - entry.count, resetAt: entry.resetAt };
1612
+ };
1613
+ }
1614
+ function getClientIP(request) {
1615
+ const forwarded = request.headers.get("x-forwarded-for");
1616
+ if (forwarded) return forwarded.split(",")[0].trim();
1617
+ const real = request.headers.get("x-real-ip");
1618
+ if (real) return real;
1619
+ return "unknown";
1620
+ }
1621
+
1622
+ // src/lib/cache-store.ts
1623
+ var DEFAULT_CONFIG = {
1624
+ maxSize: 1e3,
1625
+ defaultTTL: 60 * 1e3
1626
+ };
1627
+ var CacheStore = class {
1628
+ constructor(config = {}) {
1629
+ this.cache = /* @__PURE__ */ new Map();
1630
+ this.hits = 0;
1631
+ this.misses = 0;
1632
+ this.accessCounter = 0;
1633
+ this.config = { ...DEFAULT_CONFIG, ...config };
1634
+ }
1635
+ get(key) {
1636
+ const entry = this.cache.get(key);
1637
+ if (!entry) {
1638
+ this.misses++;
1639
+ return void 0;
1640
+ }
1641
+ if (Date.now() > entry.expiresAt) {
1642
+ this.cache.delete(key);
1643
+ this.misses++;
1644
+ return void 0;
1645
+ }
1646
+ entry.accessOrder = ++this.accessCounter;
1647
+ this.hits++;
1648
+ return entry.value;
1649
+ }
1650
+ set(key, value, ttl) {
1651
+ if (this.cache.size >= this.config.maxSize) this.evictLRU();
1652
+ this.cache.set(key, {
1653
+ value,
1654
+ expiresAt: Date.now() + (ttl ?? this.config.defaultTTL),
1655
+ accessOrder: ++this.accessCounter
1656
+ });
1657
+ }
1658
+ has(key) {
1659
+ const entry = this.cache.get(key);
1660
+ if (!entry) return false;
1661
+ if (Date.now() > entry.expiresAt) {
1662
+ this.cache.delete(key);
1663
+ return false;
1664
+ }
1665
+ return true;
1666
+ }
1667
+ delete(key) {
1668
+ return this.cache.delete(key);
1669
+ }
1670
+ /** Delete all keys matching a string prefix or RegExp pattern */
1671
+ deletePattern(pattern) {
1672
+ const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
1673
+ let deleted = 0;
1674
+ for (const key of this.cache.keys()) {
1675
+ if (regex.test(key)) {
1676
+ this.cache.delete(key);
1677
+ deleted++;
1678
+ }
1679
+ }
1680
+ return deleted;
1681
+ }
1682
+ clear() {
1683
+ this.cache.clear();
1684
+ this.hits = 0;
1685
+ this.misses = 0;
1686
+ this.accessCounter = 0;
1687
+ }
1688
+ /** Remove expired entries and return count removed */
1689
+ cleanup() {
1690
+ const now = Date.now();
1691
+ let removed = 0;
1692
+ for (const [key, entry] of this.cache.entries()) {
1693
+ if (now > entry.expiresAt) {
1694
+ this.cache.delete(key);
1695
+ removed++;
1696
+ }
1697
+ }
1698
+ return removed;
1699
+ }
1700
+ getStats() {
1701
+ const total = this.hits + this.misses;
1702
+ return {
1703
+ size: this.cache.size,
1704
+ maxSize: this.config.maxSize,
1705
+ hits: this.hits,
1706
+ misses: this.misses,
1707
+ hitRate: total > 0 ? this.hits / total : 0
1708
+ };
1709
+ }
1710
+ evictLRU() {
1711
+ let oldestKey = null;
1712
+ let oldestOrder = Infinity;
1713
+ for (const [key, entry] of this.cache.entries()) {
1714
+ if (entry.accessOrder < oldestOrder) {
1715
+ oldestOrder = entry.accessOrder;
1716
+ oldestKey = key;
1717
+ }
1718
+ }
1719
+ if (oldestKey) this.cache.delete(oldestKey);
1720
+ }
1721
+ };
1722
+
1723
+ // src/lib/cache-manager.ts
1724
+ var DEFAULT_CONFIG2 = {
1725
+ entity: { maxSize: 500, defaultTTL: 5 * 60 * 1e3 },
1726
+ query: { maxSize: 200, defaultTTL: 60 * 1e3 }
1727
+ };
1728
+ var CacheManager = class {
1729
+ constructor(enabled = true, config = {}) {
1730
+ this.entity = new CacheStore({ ...DEFAULT_CONFIG2.entity, ...config.entity });
1731
+ this.query = new CacheStore({ ...DEFAULT_CONFIG2.query, ...config.query });
1732
+ this.enabled = enabled;
1733
+ }
1734
+ /**
1735
+ * Cache-aside: return the cached value if present, otherwise call fetchFn,
1736
+ * store the result, and return it.
1737
+ */
1738
+ async getOrSet(key, ttlMs, fetchFn) {
1739
+ if (this.enabled) {
1740
+ const cached = this.query.get(key);
1741
+ if (cached !== void 0) return cached;
1742
+ }
1743
+ const value = await fetchFn();
1744
+ if (this.enabled) this.query.set(key, value, ttlMs);
1745
+ return value;
1746
+ }
1747
+ /** Invalidate a specific key in the query cache */
1748
+ invalidateKey(key) {
1749
+ this.query.delete(key);
1750
+ }
1751
+ /** Invalidate all query cache keys matching a string prefix or RegExp */
1752
+ invalidatePattern(pattern) {
1753
+ this.query.deletePattern(pattern);
1754
+ }
1755
+ /** Invalidate all entity and query cache entries for the given prefix */
1756
+ invalidateAll(prefix) {
1757
+ this.entity.deletePattern(prefix);
1758
+ this.query.deletePattern(prefix);
1759
+ }
1760
+ setEnabled(enabled) {
1761
+ this.enabled = enabled;
1762
+ }
1763
+ isEnabled() {
1764
+ return this.enabled;
1765
+ }
1766
+ /** Remove expired entries from both stores */
1767
+ maintenance() {
1768
+ return {
1769
+ entityRemoved: this.entity.cleanup(),
1770
+ queryRemoved: this.query.cleanup()
1771
+ };
1772
+ }
1773
+ clear() {
1774
+ this.entity.clear();
1775
+ this.query.clear();
1776
+ }
1777
+ getStats() {
1778
+ return { entity: this.entity.getStats(), query: this.query.getStats() };
1779
+ }
1780
+ };
1781
+ var _cacheManager = null;
1782
+ function getCacheManager(config) {
1783
+ if (!_cacheManager) _cacheManager = new CacheManager(true, config);
1784
+ return _cacheManager;
1785
+ }
1786
+ function resetCacheManager() {
1787
+ _cacheManager?.clear();
1788
+ _cacheManager = null;
1789
+ }
1790
+
1791
+ // src/constants/options.ts
1792
+ var COMPANY_SIZE_OPTIONS = [
1793
+ { value: "startup", label: "Startup (1-10)" },
1794
+ { value: "small", label: "Small (11-50)" },
1795
+ { value: "smb", label: "SMB (51-200)" },
1796
+ { value: "mid_market", label: "Mid-Market (201-1000)" },
1797
+ { value: "enterprise", label: "Enterprise (1000+)" }
1798
+ ];
1799
+ var LIFECYCLE_STAGE_OPTIONS = [
1800
+ { value: "subscriber", label: "Subscriber" },
1801
+ { value: "lead", label: "Lead" },
1802
+ { value: "mql", label: "MQL" },
1803
+ { value: "sql", label: "SQL" },
1804
+ { value: "opportunity", label: "Opportunity" },
1805
+ { value: "customer", label: "Customer" },
1806
+ { value: "evangelist", label: "Evangelist" }
1807
+ ];
1808
+ var REVENUE_RANGE_OPTIONS = [
1809
+ { value: "pre_revenue", label: "Pre-revenue" },
1810
+ { value: "0_1m", label: "$0-$1M" },
1811
+ { value: "1m_10m", label: "$1M-$10M" },
1812
+ { value: "10m_50m", label: "$10M-$50M" },
1813
+ { value: "50m_plus", label: "$50M+" }
1814
+ ];
1815
+ var ACTIVITY_TYPE_OPTIONS = [
1816
+ { value: "call", label: "Call" },
1817
+ { value: "email", label: "Email" },
1818
+ { value: "meeting", label: "Meeting" },
1819
+ { value: "demo", label: "Demo" },
1820
+ { value: "note", label: "Note" },
1821
+ { value: "task", label: "Task" }
1822
+ ];
1823
+ var ACTIVITY_OUTCOME_OPTIONS = [
1824
+ { value: "scheduled_demo", label: "Scheduled Demo" },
1825
+ { value: "scheduled_meeting", label: "Scheduled Meeting" },
1826
+ { value: "callback_later", label: "Callback Later" },
1827
+ { value: "left_voicemail", label: "Left Voicemail" },
1828
+ { value: "no_answer", label: "No Answer" },
1829
+ { value: "not_interested", label: "Not Interested" },
1830
+ { value: "successful", label: "Successful" },
1831
+ { value: "unsuccessful", label: "Unsuccessful" }
1832
+ ];
1833
+ var LOSS_REASON_OPTIONS = [
1834
+ { value: "price", label: "Price / Budget" },
1835
+ { value: "timing", label: "Bad Timing" },
1836
+ { value: "competitor", label: "Chose Competitor" },
1837
+ { value: "no_need", label: "No Need" },
1838
+ { value: "no_response", label: "No Response" },
1839
+ { value: "other", label: "Other" }
1840
+ ];
1841
+ var DEAL_STAGE_OPTIONS = [
1842
+ { value: "qualification", label: "Qualification" },
1843
+ { value: "discovery", label: "Discovery" },
1844
+ { value: "demo", label: "Demo" },
1845
+ { value: "proposal", label: "Proposal" },
1846
+ { value: "negotiation", label: "Negotiation" },
1847
+ { value: "closed_won", label: "Closed Won" },
1848
+ { value: "closed_lost", label: "Closed Lost" }
1849
+ ];
1850
+ function useServerList(endpoint, options = {}) {
1851
+ const {
1852
+ pageSize: initialPageSize = 25,
1853
+ initialPage = 1,
1854
+ initialSearch = "",
1855
+ initialSortField = "",
1856
+ initialSortDir = "asc",
1857
+ params: extraParams = {},
1858
+ disabled = false,
1859
+ fetcher = fetch
1860
+ } = options;
1861
+ const [page, setPage] = react.useState(initialPage);
1862
+ const [pageSize, setPageSize] = react.useState(initialPageSize);
1863
+ const [search, setSearchState] = react.useState(initialSearch);
1864
+ const [sortField, setSortField] = react.useState(initialSortField);
1865
+ const [sortDir, setSortDir] = react.useState(initialSortDir);
1866
+ const [data, setData] = react.useState([]);
1867
+ const [total, setTotal] = react.useState(0);
1868
+ const [loading, setLoading] = react.useState(!disabled);
1869
+ const [error, setError] = react.useState(null);
1870
+ const refreshCountRef = react.useRef(0);
1871
+ const fetchData = react.useCallback(async () => {
1872
+ if (disabled) return;
1873
+ setLoading(true);
1874
+ setError(null);
1875
+ const searchParams = new URLSearchParams();
1876
+ searchParams.set("page", String(page));
1877
+ searchParams.set("pageSize", String(pageSize));
1878
+ if (sortField) {
1879
+ searchParams.set("sortField", sortField);
1880
+ searchParams.set("sortDirection", sortDir);
1881
+ }
1882
+ if (search) searchParams.set("search", search);
1883
+ for (const [k, v] of Object.entries(extraParams)) {
1884
+ searchParams.set(k, String(v));
1885
+ }
1886
+ const sep = endpoint.includes("?") ? "&" : "?";
1887
+ const url = `${endpoint}${sep}${searchParams.toString()}`;
1888
+ try {
1889
+ const response = await fetcher(url);
1890
+ if (!response.ok) {
1891
+ throw new Error(`Request failed: ${response.status} ${response.statusText}`);
1892
+ }
1893
+ const json = await response.json();
1894
+ if (Array.isArray(json)) {
1895
+ setData(json);
1896
+ setTotal(json.length);
1897
+ } else if (json.results !== void 0) {
1898
+ setData(json.results);
1899
+ setTotal(json.count ?? json.results.length);
1900
+ } else if (json.data !== void 0) {
1901
+ setData(json.data);
1902
+ setTotal(json.total ?? json.data.length);
1903
+ } else {
1904
+ setData([]);
1905
+ setTotal(0);
1906
+ }
1907
+ } catch (err) {
1908
+ setError(err instanceof Error ? err.message : "Failed to load data");
1909
+ setData([]);
1910
+ } finally {
1911
+ setLoading(false);
1912
+ }
1913
+ }, [endpoint, page, pageSize, search, sortField, sortDir, disabled, fetcher, refreshCountRef.current]);
1914
+ react.useEffect(() => {
1915
+ fetchData();
1916
+ }, [fetchData]);
1917
+ const setSearch = react.useCallback((value) => {
1918
+ setPage(1);
1919
+ setSearchState(value);
1920
+ }, []);
1921
+ const setSort = react.useCallback(
1922
+ (field, dir) => {
1923
+ if (field === sortField && !dir) {
1924
+ setSortDir((prev) => prev === "asc" ? "desc" : "asc");
1925
+ } else {
1926
+ setSortField(field);
1927
+ setSortDir(dir ?? "asc");
1928
+ }
1929
+ setPage(1);
1930
+ },
1931
+ [sortField]
1932
+ );
1933
+ const refresh = react.useCallback(() => {
1934
+ refreshCountRef.current += 1;
1935
+ fetchData();
1936
+ }, [fetchData]);
1937
+ return {
1938
+ data,
1939
+ total,
1940
+ loading,
1941
+ error,
1942
+ page,
1943
+ pageSize,
1944
+ search,
1945
+ sortField,
1946
+ sortDir,
1947
+ setPage,
1948
+ setPageSize,
1949
+ setSearch,
1950
+ setSort,
1951
+ refresh
1952
+ };
1953
+ }
1954
+ function useServerDetail(endpoint, id, options = {}) {
1955
+ const { fetcher = fetch, disabled = false } = options;
1956
+ const [data, setData] = react.useState(null);
1957
+ const [loading, setLoading] = react.useState(!disabled && id !== null && id !== void 0);
1958
+ const [error, setError] = react.useState(null);
1959
+ const fetchData = react.useCallback(async () => {
1960
+ if (disabled || id === null) return;
1961
+ const url = id !== void 0 ? `${endpoint}${endpoint.endsWith("/") ? "" : "/"}${id}/` : endpoint;
1962
+ setLoading(true);
1963
+ setError(null);
1964
+ try {
1965
+ const response = await fetcher(url);
1966
+ if (!response.ok) {
1967
+ throw new Error(`Request failed: ${response.status} ${response.statusText}`);
1968
+ }
1969
+ setData(await response.json());
1970
+ } catch (err) {
1971
+ setError(err instanceof Error ? err.message : "Failed to load data");
1972
+ } finally {
1973
+ setLoading(false);
1974
+ }
1975
+ }, [endpoint, id, disabled, fetcher]);
1976
+ react.useEffect(() => {
1977
+ fetchData();
1978
+ }, [fetchData]);
1979
+ return { data, loading, error, refresh: fetchData };
1980
+ }
1981
+
1982
+ // src/lib/env.ts
1983
+ function getRequiredEnv(key) {
1984
+ const value = process.env[key];
1985
+ if (!value) {
1986
+ throw new Error(`Missing required environment variable: ${key}`);
1987
+ }
1988
+ return value;
1989
+ }
1990
+ function getOptionalEnv(key, defaultValue) {
1991
+ return process.env[key] ?? defaultValue;
1992
+ }
1993
+ function validateEnvVars(required) {
1994
+ const missing = required.filter((key) => !process.env[key]);
1995
+ if (missing.length > 0) {
1996
+ throw new Error(`Missing required environment variables: ${missing.join(", ")}`);
1997
+ }
1998
+ }
1999
+
2000
+ // src/index.ts
2001
+ function createStartSimpliApi(config = {}) {
2002
+ const client = createApiClient(config);
2003
+ return {
2004
+ client,
2005
+ contacts: new ContactsApi(client),
2006
+ organizations: new OrganizationsApi(client),
2007
+ entities: new EntitiesApi(client),
2008
+ workflows: new WorkflowsApi(client),
2009
+ messages: new MessagesApi(client),
2010
+ funnels: new FunnelsApi(client)
2011
+ };
2012
+ }
2013
+
2014
+ exports.ACTIVITY_OUTCOME_OPTIONS = ACTIVITY_OUTCOME_OPTIONS;
2015
+ exports.ACTIVITY_TYPE_OPTIONS = ACTIVITY_TYPE_OPTIONS;
2016
+ exports.ApiClient = ApiClient;
2017
+ exports.ApiException = ApiException;
2018
+ exports.AppError = AppError;
2019
+ exports.AppErrorCode = AppErrorCode;
2020
+ exports.AuthenticationError = AuthenticationError;
2021
+ exports.AuthorizationError = AuthorizationError;
2022
+ exports.COMPANY_SIZE_OPTIONS = COMPANY_SIZE_OPTIONS;
2023
+ exports.CacheManager = CacheManager;
2024
+ exports.CacheStore = CacheStore;
2025
+ exports.ConflictError = ConflictError;
2026
+ exports.ContactsApi = ContactsApi;
2027
+ exports.DEAL_STAGE_OPTIONS = DEAL_STAGE_OPTIONS;
2028
+ exports.DatabaseError = DatabaseError;
2029
+ exports.ENDPOINTS = ENDPOINTS;
2030
+ exports.EntitiesApi = EntitiesApi;
2031
+ exports.EntityQueryBuilder = EntityQueryBuilder;
2032
+ exports.ErrorCode = ErrorCode;
2033
+ exports.ErrorCodes = ErrorCodes;
2034
+ exports.ErrorMessages = ErrorMessages;
2035
+ exports.ExternalServiceError = ExternalServiceError;
2036
+ exports.FetchWrapper = FetchWrapper;
2037
+ exports.FieldErrorSchema = FieldErrorSchema;
2038
+ exports.FunnelsApi = FunnelsApi;
2039
+ exports.LIFECYCLE_STAGE_OPTIONS = LIFECYCLE_STAGE_OPTIONS;
2040
+ exports.LOSS_REASON_OPTIONS = LOSS_REASON_OPTIONS;
2041
+ exports.MAX_CHAT_MESSAGE_LENGTH = MAX_CHAT_MESSAGE_LENGTH;
2042
+ exports.MAX_PROMPT_LENGTH = MAX_PROMPT_LENGTH;
2043
+ exports.MessagesApi = MessagesApi;
2044
+ exports.NotFoundError = NotFoundError;
2045
+ exports.OrganizationsApi = OrganizationsApi;
2046
+ exports.REVENUE_RANGE_OPTIONS = REVENUE_RANGE_OPTIONS;
2047
+ exports.RateLimitError = RateLimitError;
2048
+ exports.StandardErrorResponseSchema = StandardErrorResponseSchema;
2049
+ exports.ValidationError = ValidationError;
2050
+ exports.WorkflowsApi = WorkflowsApi;
2051
+ exports.applyCorsHeaders = applyCorsHeaders;
2052
+ exports.buildFilterParams = buildFilterParams;
2053
+ exports.buildOrderingParam = buildOrderingParam;
2054
+ exports.buildQueryString = buildQueryString;
2055
+ exports.buildUrl = buildUrl;
2056
+ exports.createApiClient = createApiClient;
2057
+ exports.createCorsMiddleware = createCorsMiddleware;
2058
+ exports.createRateLimiter = createRateLimiter;
2059
+ exports.createStartSimpliApi = createStartSimpliApi;
2060
+ exports.getCacheManager = getCacheManager;
2061
+ exports.getClientIP = getClientIP;
2062
+ exports.getCorsHeaders = getCorsHeaders;
2063
+ exports.getErrorCodeFromStatus = getErrorCodeFromStatus;
2064
+ exports.getOptionalEnv = getOptionalEnv;
2065
+ exports.getRequiredEnv = getRequiredEnv;
2066
+ exports.handleFetchError = handleFetchError;
2067
+ exports.isApiException = isApiException;
2068
+ exports.isAuthError = isAuthError;
2069
+ exports.isDRFPaginatedResponse = isDRFPaginatedResponse;
2070
+ exports.isFunnelRunConflict = isFunnelRunConflict;
2071
+ exports.isFunnelValidationError = isFunnelValidationError;
2072
+ exports.isNotFoundError = isNotFoundError;
2073
+ exports.isPrismaError = isPrismaError;
2074
+ exports.isValidationError = isValidationError;
2075
+ exports.mergeQueryParams = mergeQueryParams;
2076
+ exports.normalizeId = normalizeId;
2077
+ exports.normalizePaginated = normalizePaginated;
2078
+ exports.parseErrorResponse = parseErrorResponse;
2079
+ exports.resetCacheManager = resetCacheManager;
2080
+ exports.resolveApiUrl = resolveApiUrl;
2081
+ exports.sanitizeChatMessage = sanitizeChatMessage;
2082
+ exports.sanitizeHtml = sanitizeHtml;
2083
+ exports.sanitizeSearchQuery = sanitizeSearchQuery;
2084
+ exports.sanitizeUserInput = sanitizeUserInput;
2085
+ exports.toAppError = toAppError;
2086
+ exports.useServerDetail = useServerDetail;
2087
+ exports.useServerList = useServerList;
2088
+ exports.validateApiResponse = validateApiResponse;
2089
+ exports.validateEnvVars = validateEnvVars;
2090
+ exports.validateIdentifier = validateIdentifier;
2091
+ //# sourceMappingURL=index.js.map
2092
+ //# sourceMappingURL=index.js.map