@feedclip/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/COMMERCIAL-LICENSE.md +32 -0
  2. package/COMPLIANCE.md +110 -0
  3. package/LICENSE +21 -0
  4. package/README.md +676 -0
  5. package/dist/FeedClip-BmVeLeSY.cjs +6 -0
  6. package/dist/FeedClip-Czdkvwzl.js +1176 -0
  7. package/dist/angular.cjs +1 -0
  8. package/dist/angular.js +42 -0
  9. package/dist/feedclip.cjs +2 -0
  10. package/dist/feedclip.css +3 -0
  11. package/dist/feedclip.js +133 -0
  12. package/dist/types/ai.d.ts +2 -0
  13. package/dist/types/angular.d.ts +15 -0
  14. package/dist/types/atom.d.ts +9 -0
  15. package/dist/types/components/Alert.d.ts +8 -0
  16. package/dist/types/components/Controls.d.ts +10 -0
  17. package/dist/types/components/FeedClip.d.ts +11 -0
  18. package/dist/types/components/FeedbackDetails.d.ts +14 -0
  19. package/dist/types/components/FeedbackResult.d.ts +7 -0
  20. package/dist/types/components/HandleUpload.d.ts +21 -0
  21. package/dist/types/components/PauseRecording.d.ts +8 -0
  22. package/dist/types/components/Reset.d.ts +11 -0
  23. package/dist/types/components/StartRecording.d.ts +15 -0
  24. package/dist/types/components/StopRecording.d.ts +7 -0
  25. package/dist/types/components/TrimControls.d.ts +10 -0
  26. package/dist/types/components/Video.d.ts +8 -0
  27. package/dist/types/configuration-context.d.ts +2 -0
  28. package/dist/types/configuration.d.ts +22 -0
  29. package/dist/types/entitlements.d.ts +6 -0
  30. package/dist/types/feedback.d.ts +55 -0
  31. package/dist/types/i18n.d.ts +33 -0
  32. package/dist/types/index.d.ts +17 -0
  33. package/dist/types/indexed-db-store.d.ts +11 -0
  34. package/dist/types/license.d.ts +30 -0
  35. package/dist/types/transport.d.ts +7 -0
  36. package/dist/types/uploaders.d.ts +14 -0
  37. package/dist/types/utils.d.ts +6 -0
  38. package/dist/types/vue.d.ts +18 -0
  39. package/dist/vue.cjs +1 -0
  40. package/dist/vue.js +23 -0
  41. package/package.json +118 -0
  42. package/scripts/generate-license-keypair.mjs +25 -0
  43. package/scripts/issue-license.mjs +69 -0
package/README.md ADDED
@@ -0,0 +1,676 @@
1
+ # FeedClip AI
2
+
3
+ Customer Feedback Infrastructure for SaaS.
4
+
5
+ FeedClip is an embeddable feedback SDK for React, Vue, and Angular that captures
6
+ customer video, voice, screenshots, page context, and product metadata. Your
7
+ backend can turn that submission into a transcript, structured AI analysis, and
8
+ an engineering issue.
9
+
10
+ ```text
11
+ Capture SDK -> Ingestion API -> Transcription -> AI analysis -> Issue tracker
12
+ ```
13
+
14
+ ## Current MVP
15
+
16
+ The repository currently includes:
17
+
18
+ - camera and microphone recording with browser `MediaRecorder`;
19
+ - pause, resume, stop, preview, reset, and optional trimming;
20
+ - customer feedback type and written description;
21
+ - optional screenshot attachment;
22
+ - automatic URL, browser, locale, viewport, timezone, and referrer capture;
23
+ - custom SaaS context such as user, account, plan, release, and feature flags;
24
+ - an AI-ready `FeedbackSubmission` contract;
25
+ - a multipart HTTP transport for feedback ingestion;
26
+ - an IndexedDB transport for local development and offline capture;
27
+ - rendering of returned AI analysis and generated issue details;
28
+ - legacy file-only upload support;
29
+ - Supabase and S3 uploader helpers;
30
+ - localization for 10 languages;
31
+ - React implementation with Vue 3 and Angular 19 lifecycle adapters;
32
+ - ESM, CommonJS, CSS, and TypeScript declaration builds;
33
+ - 106 automated tests.
34
+
35
+ The hosted ingestion service, production transcription worker, persistent
36
+ dashboard, deduplication, and native issue-tracker connectors are the next
37
+ platform layer. The SDK contracts required by that layer are already included.
38
+
39
+ ## Installation
40
+
41
+ React:
42
+
43
+ ```bash
44
+ npm install @feedclip/sdk react react-dom
45
+ ```
46
+
47
+ Vue 3:
48
+
49
+ ```bash
50
+ npm install @feedclip/sdk vue react react-dom
51
+ ```
52
+
53
+ Angular 19:
54
+
55
+ ```bash
56
+ npm install @feedclip/sdk @angular/core react react-dom
57
+ ```
58
+
59
+ The Vue and Angular entrypoints are lifecycle adapters over the same tested
60
+ React capture engine. They require React 19 and React DOM 19 as peer
61
+ dependencies. Jotai is an internal dependency and is installed automatically.
62
+
63
+ These are framework adapters, not independent native Vue and Angular
64
+ implementations. This keeps capture behavior consistent, but means Vue and
65
+ Angular applications include the React runtime.
66
+
67
+ ## React
68
+
69
+ Use `onSubmit` for the complete customer-feedback flow:
70
+
71
+ ```tsx
72
+ import FeedClip, {
73
+ createFeedbackEndpointTransport,
74
+ } from "@feedclip/sdk";
75
+ import "@feedclip/sdk/style.css";
76
+
77
+ const submitFeedback = createFeedbackEndpointTransport({
78
+ endpoint: "/api/feedback",
79
+ headers: {
80
+ Authorization: `Bearer ${sessionToken}`,
81
+ },
82
+ });
83
+
84
+ export function CustomerFeedback() {
85
+ return (
86
+ <FeedClip
87
+ config={{
88
+ locale: "en-US",
89
+ maxDurationMilliSeconds: 60_000,
90
+ maxFileSize: 100_000_000,
91
+ defaultVideoFileExtension: "webm",
92
+ defaultVideoFileNameStyle: "ISO 8601",
93
+ onSubmit: submitFeedback,
94
+ getContext: () => ({
95
+ userId: currentUser.id,
96
+ accountId: currentAccount.id,
97
+ plan: currentAccount.plan,
98
+ appVersion: APP_VERSION,
99
+ featureFlags: activeFeatureFlags,
100
+ }),
101
+ }}
102
+ />
103
+ );
104
+ }
105
+ ```
106
+
107
+ ## Vue
108
+
109
+ ```vue
110
+ <script setup lang="ts">
111
+ import FeedClipVue from "@feedclip/sdk/vue";
112
+ import { createFeedbackEndpointTransport } from "@feedclip/sdk";
113
+ import "@feedclip/sdk/style.css";
114
+
115
+ const config = {
116
+ locale: "en-US" as const,
117
+ maxDurationMilliSeconds: 60_000,
118
+ maxFileSize: 100_000_000,
119
+ defaultVideoFileExtension: "webm" as const,
120
+ defaultVideoFileNameStyle: "ISO 8601" as const,
121
+ onSubmit: createFeedbackEndpointTransport({
122
+ endpoint: "/api/feedback",
123
+ }),
124
+ };
125
+ </script>
126
+
127
+ <template>
128
+ <FeedClipVue :config="config" />
129
+ </template>
130
+ ```
131
+
132
+ The adapter reacts to deep `config` changes and unmounts its internal capture
133
+ root together with the Vue component.
134
+
135
+ ## Angular
136
+
137
+ ```ts
138
+ import { Component } from "@angular/core";
139
+ import { FeedClipAngularComponent } from "@feedclip/sdk/angular";
140
+ import { createFeedbackEndpointTransport } from "@feedclip/sdk";
141
+ import "@feedclip/sdk/style.css";
142
+
143
+ @Component({
144
+ selector: "app-feedback",
145
+ standalone: true,
146
+ imports: [FeedClipAngularComponent],
147
+ template: `<feedclip-widget [config]="config" />`,
148
+ })
149
+ export class FeedbackComponent {
150
+ readonly config = {
151
+ locale: "en-US" as const,
152
+ maxDurationMilliSeconds: 60_000,
153
+ maxFileSize: 100_000_000,
154
+ defaultVideoFileExtension: "webm" as const,
155
+ defaultVideoFileNameStyle: "ISO 8601" as const,
156
+ onSubmit: createFeedbackEndpointTransport({
157
+ endpoint: "/api/feedback",
158
+ }),
159
+ };
160
+ }
161
+ ```
162
+
163
+ `FeedClipAngularComponent` is standalone, responds to `config` input changes,
164
+ and releases the capture root in `ngOnDestroy`.
165
+
166
+ Use either `onSubmit` or the legacy `onUpload` handler. When both are provided,
167
+ `onSubmit` takes precedence.
168
+
169
+ For local development without a backend, store real submissions in IndexedDB:
170
+
171
+ ```ts
172
+ import { createIndexedDbFeedbackStore } from "@feedclip/sdk";
173
+
174
+ const onSubmit = createIndexedDbFeedbackStore({
175
+ databaseName: "my-product-feedback",
176
+ });
177
+
178
+ await onSubmit.delete(feedbackId);
179
+ await onSubmit.clear();
180
+ ```
181
+
182
+ This stores the metadata, video, and screenshot in the browser and returns
183
+ `{ status: "received" }`. It does not invent an AI result.
184
+
185
+ ## Feedback Flow
186
+
187
+ ```text
188
+ Start recording
189
+ |
190
+ v
191
+ Video + voice capture <-> Pause / resume
192
+ |
193
+ v
194
+ Preview + description + feedback type + screenshot
195
+ |
196
+ v
197
+ FeedbackSubmission
198
+ |
199
+ v
200
+ Backend processing
201
+ |
202
+ +-> transcript
203
+ +-> AI summary and severity
204
+ +-> reproduction steps
205
+ +-> GitHub / Linear / Jira issue
206
+ |
207
+ v
208
+ FeedbackReceipt rendered in the widget
209
+ ```
210
+
211
+ ## Submission Contract
212
+
213
+ `onSubmit` receives the following object:
214
+
215
+ ```ts
216
+ interface FeedbackSubmission {
217
+ id: string;
218
+ createdAt: string;
219
+ kind: "bug" | "idea" | "question" | "other";
220
+ description: string;
221
+ video: File;
222
+ screenshot?: File;
223
+ context: {
224
+ url: string;
225
+ title: string;
226
+ userAgent: string;
227
+ language: string;
228
+ viewport: {
229
+ width: number;
230
+ height: number;
231
+ devicePixelRatio: number;
232
+ };
233
+ timezone: string;
234
+ referrer?: string;
235
+ };
236
+ customContext?: Record<string, unknown>;
237
+ }
238
+ ```
239
+
240
+ `getContext` may be synchronous or asynchronous. Do not place passwords,
241
+ access tokens, payment data, or other secrets in the returned object.
242
+
243
+ FeedClip removes URL credentials, fragments, query strings, and referrers from
244
+ browser context by default. Query strings can be enabled only when required:
245
+
246
+ ```ts
247
+ browserContext: {
248
+ includeQueryString: true,
249
+ includeReferrer: false,
250
+ }
251
+ ```
252
+
253
+ Review query parameters before enabling this option because they commonly
254
+ contain email addresses, reset tokens, OAuth codes, and other sensitive data.
255
+
256
+ Link the widget to the integrating product's privacy notice:
257
+
258
+ ```ts
259
+ privacyNotice: {
260
+ url: "/privacy",
261
+ label: "Privacy notice",
262
+ }
263
+ ```
264
+
265
+ The integrating product remains responsible for selecting and documenting its
266
+ lawful basis, presenting any required notice before capture, and obtaining
267
+ consent where consent is the selected basis. Browser camera or microphone
268
+ permission is not a substitute for privacy consent.
269
+
270
+ ## Backend Transport
271
+
272
+ `createFeedbackEndpointTransport` sends `multipart/form-data`:
273
+
274
+ | Field | Content |
275
+ |---|---|
276
+ | `payload` | JSON metadata without binary files |
277
+ | `video` | Recorded video and voice |
278
+ | `screenshot` | Optional customer screenshot |
279
+
280
+ ```ts
281
+ import { createFeedbackEndpointTransport } from "@feedclip/sdk";
282
+
283
+ const onSubmit = createFeedbackEndpointTransport({
284
+ endpoint: "https://feedback.example.com/v1/submissions",
285
+ credentials: "include",
286
+ headers: {
287
+ "X-Project-Key": projectKey,
288
+ },
289
+ });
290
+ ```
291
+
292
+ The endpoint must return a JSON `FeedbackReceipt`:
293
+
294
+ ```ts
295
+ interface FeedbackReceipt {
296
+ feedbackId: string;
297
+ status: "received" | "processing" | "completed";
298
+ analysis?: {
299
+ title: string;
300
+ summary: string;
301
+ category: "bug" | "idea" | "question" | "other";
302
+ priority: "low" | "medium" | "high" | "critical";
303
+ sentiment: "negative" | "neutral" | "positive";
304
+ reproductionSteps: string[];
305
+ expectedBehavior?: string;
306
+ actualBehavior?: string;
307
+ labels: string[];
308
+ transcript?: string;
309
+ };
310
+ issue?: {
311
+ provider: "github" | "linear" | "jira" | "custom";
312
+ id: string;
313
+ title: string;
314
+ url?: string;
315
+ };
316
+ }
317
+ ```
318
+
319
+ When `analysis` or `issue` is present, FeedClip renders it below the capture
320
+ controls.
321
+
322
+ ## AI Processing
323
+
324
+ A production backend should:
325
+
326
+ 1. authenticate the project and validate the submission;
327
+ 2. store video and screenshot in private object storage;
328
+ 3. enqueue asynchronous processing;
329
+ 4. transcribe the audio track;
330
+ 5. generate schema-validated analysis;
331
+ 6. deduplicate similar feedback;
332
+ 7. create or update an issue;
333
+ 8. persist the result and notify the originating SaaS.
334
+
335
+ FeedClip exports `buildFeedbackAnalysisPrompt` for the analysis step.
336
+
337
+ Example with AI SDK 6:
338
+
339
+ ```ts
340
+ import { generateText, Output } from "ai";
341
+ import { z } from "zod";
342
+ import { buildFeedbackAnalysisPrompt } from "@feedclip/sdk";
343
+
344
+ const analysisSchema = z.object({
345
+ title: z.string(),
346
+ summary: z.string(),
347
+ category: z.enum(["bug", "idea", "question", "other"]),
348
+ priority: z.enum(["low", "medium", "high", "critical"]),
349
+ sentiment: z.enum(["negative", "neutral", "positive"]),
350
+ reproductionSteps: z.array(z.string()),
351
+ expectedBehavior: z.string().optional(),
352
+ actualBehavior: z.string().optional(),
353
+ labels: z.array(z.string()),
354
+ transcript: z.string().optional(),
355
+ });
356
+
357
+ const { output: analysis } = await generateText({
358
+ model: "openai/gpt-5.4",
359
+ output: Output.object({ schema: analysisSchema }),
360
+ prompt: buildFeedbackAnalysisPrompt(payload, transcript),
361
+ });
362
+ ```
363
+
364
+ Keep provider credentials and AI processing on the server. Never expose model
365
+ or issue-tracker API keys in the capture SDK.
366
+
367
+ ### Included API project
368
+
369
+ This repository includes a standalone Node.js API in [`apps/api`](./apps/api).
370
+ It implements the SDK multipart contract, project-key authentication, private
371
+ development storage, OpenAI transcription, schema-validated AI analysis, and
372
+ submission status polling.
373
+
374
+ ```bash
375
+ cd apps/api
376
+ cp .env.example .env
377
+ npm install
378
+ npm run dev
379
+ ```
380
+
381
+ See [`apps/api/README.md`](./apps/api/README.md) for configuration and
382
+ production deployment notes.
383
+
384
+ See [`COMPLIANCE.md`](./COMPLIANCE.md) for the data inventory, controller and
385
+ processor responsibilities, deletion and retention controls, and deployment
386
+ checklist.
387
+
388
+ ## Legacy File Upload
389
+
390
+ Existing integrations can continue to receive only the recorded file:
391
+
392
+ ```tsx
393
+ <FeedClip
394
+ config={{
395
+ locale: "en-US",
396
+ maxDurationMilliSeconds: 60_000,
397
+ maxFileSize: 100_000_000,
398
+ defaultVideoFileExtension: "webm",
399
+ defaultVideoFileNameStyle: "UnixTimestamp",
400
+ onUpload: async (file) => {
401
+ const formData = new FormData();
402
+ formData.append("video", file);
403
+ await fetch("/api/upload", {
404
+ method: "POST",
405
+ body: formData,
406
+ });
407
+ },
408
+ }}
409
+ />
410
+ ```
411
+
412
+ ## Configuration
413
+
414
+ | Property | Type | Required | Description |
415
+ |---|---|---:|---|
416
+ | `locale` | Supported locale | Yes | Widget language |
417
+ | `maxDurationMilliSeconds` | `number` | Yes | Recording time limit |
418
+ | `maxFileSize` | `number` | Yes | Maximum submitted video size in bytes |
419
+ | `defaultVideoFileExtension` | `"webm" \| "mp4" \| "avi" \| "mov" \| "mkv"` | Yes | Preferred file extension |
420
+ | `defaultVideoFileNameStyle` | `"UnixTimestamp" \| "ISO 8601" \| "Custom"` | Yes | Generated filename strategy |
421
+ | `onSubmit` | `(submission, onProgress?) => Promise<FeedbackReceipt \| void>` | One handler | Complete feedback pipeline |
422
+ | `onUpload` | `(file, onProgress?) => Promise<void>` | One handler | Legacy file-only upload |
423
+ | `getContext` | `() => object \| Promise<object>` | No | Application-specific metadata |
424
+ | `browserContext` | `{ includeQueryString?, includeReferrer? }` | No | Opt in to additional browser context |
425
+ | `privacyNotice` | `{ url, label }` | No | Link to the integrating product's privacy notice |
426
+ | `license` | `FeedClipLicenseConfig` | No | Signed license token and verification parameters |
427
+ | `onLicenseError` | `(reason: string) => void` | No | Receives license verification failures |
428
+
429
+ Runtime validation currently expects consumers to provide one submission
430
+ handler. Omitting both handlers causes submission to fail with an error alert.
431
+
432
+ ## Free and Paid Products
433
+
434
+ The current `@feedclip/sdk` package is MIT-licensed. Its source code,
435
+ including commercial use, is free under the terms of [LICENSE](./LICENSE).
436
+
437
+ | Capability | Free | Paid |
438
+ |---|:---:|:---:|
439
+ | Video and voice capture | Yes | Yes |
440
+ | Description, feedback type, screenshot | Yes | Yes |
441
+ | Browser and custom product context | Yes | Yes |
442
+ | Self-hosted `onSubmit` and HTTP transport | Yes | Yes |
443
+ | Local IndexedDB storage | Yes | Yes |
444
+ | Pause and preview | Yes | Yes |
445
+ | Trimming, thumbnails, upload progress | No | Yes |
446
+ | Supabase/S3 uploader helpers | No | Yes |
447
+ | Screen recording, console and network capture | Roadmap | Roadmap |
448
+ | Privacy redaction and resumable uploads | Roadmap | Roadmap |
449
+ | Custom branding and UI themes | Roadmap | Roadmap |
450
+ | Managed storage and hosted transcription | Roadmap | Roadmap |
451
+ | Native issue generation | Roadmap | Roadmap |
452
+ | Dashboard, search, deduplication, webhooks | Roadmap | Roadmap |
453
+ | SSO, RBAC, audit logs, data residency, SLA | Roadmap | Roadmap |
454
+
455
+ The repository includes a self-hosted transcription and structured-analysis
456
+ reference API. It is not a hosted service included with the Paid license.
457
+
458
+ The Paid version uses a compact ECDSA P-256 signed license token. The private key stays
459
+ on the FeedClip licensing server; the SDK receives only the token and public
460
+ verification key.
461
+
462
+ ```ts
463
+ const { token } = await fetch("/api/feedclip/license", {
464
+ credentials: "include",
465
+ }).then((response) => response.json());
466
+
467
+ <FeedClip
468
+ config={{
469
+ // ...
470
+ license: {
471
+ token,
472
+ publicKey: FEEDCLIP_PUBLIC_KEY,
473
+ issuer: "https://feedclip.dev",
474
+ audience: "@feedclip/sdk",
475
+ projectId: "project_123",
476
+ },
477
+ onLicenseError: (reason) => {
478
+ console.error("FeedClip license rejected:", reason);
479
+ },
480
+ }}
481
+ />;
482
+ ```
483
+
484
+ The SDK verifies:
485
+
486
+ - token format and `ES256` algorithm;
487
+ - ECDSA signature;
488
+ - issuer and audience;
489
+ - project binding;
490
+ - issue and expiry timestamps;
491
+ - plan and optional feature overrides.
492
+
493
+ Invalid, expired, or mismatched tokens fall back to the Free plan.
494
+
495
+ ### Issuing licenses
496
+
497
+ Generate an ECDSA key pair:
498
+
499
+ ```bash
500
+ npm run license:keys
501
+ ```
502
+
503
+ Store the generated private JWK in a server-side secret manager. The public JWK
504
+ may be embedded in the client application.
505
+
506
+ Issue a project-bound license:
507
+
508
+ ```bash
509
+ export FEEDCLIP_PRIVATE_KEY_JWK='{"kty":"EC",...}'
510
+
511
+ npm run license:issue -- \
512
+ --project project_123 \
513
+ --plan paid \
514
+ --issuer https://feedclip.dev \
515
+ --audience @feedclip/sdk \
516
+ --days 365
517
+ ```
518
+
519
+ Optional feature overrides are signed into the token for development and
520
+ future product rollout:
521
+
522
+ ```bash
523
+ npm run license:issue -- \
524
+ --project project_123 \
525
+ --plan paid \
526
+ --features '{"screenRecording":true}'
527
+ ```
528
+
529
+ An override does not provide an implementation that is not present in the
530
+ installed SDK.
531
+
532
+ License verification protects the official SDK feature path from accidental or
533
+ unauthorized activation. Because the Free SDK source is MIT-licensed, it is not
534
+ DRM. Paid backend APIs, quotas, storage, AI processing, and connectors must
535
+ always enforce the same plan server-side.
536
+
537
+ ## Upload Helpers
538
+
539
+ Supabase and S3 helpers perform real browser uploads.
540
+
541
+ ### Supabase Storage
542
+
543
+ ```ts
544
+ import { createSupabaseUploader } from "@feedclip/sdk";
545
+
546
+ const license = await verifyFeedClipLicense({
547
+ token,
548
+ publicKey: FEEDCLIP_PUBLIC_KEY,
549
+ issuer: "https://feedclip.dev",
550
+ audience: "@feedclip/sdk",
551
+ projectId: "project_123",
552
+ });
553
+
554
+ const onUpload = createSupabaseUploader({
555
+ url: "https://project.supabase.co",
556
+ apiKey: supabaseAnonKey,
557
+ bucket: "feedback",
558
+ folder: "recordings",
559
+ license,
560
+ });
561
+ ```
562
+
563
+ ### S3 Pre-signed URL
564
+
565
+ ```ts
566
+ import { createS3Uploader } from "@feedclip/sdk";
567
+
568
+ const onUpload = createS3Uploader({
569
+ presignedUrl,
570
+ license,
571
+ });
572
+ ```
573
+
574
+ Do not embed privileged Supabase service keys or AWS credentials in browser
575
+ code. Use restricted public credentials or server-generated pre-signed URLs.
576
+
577
+ ## Localization
578
+
579
+ Supported locale tags:
580
+
581
+ | Tag | Language |
582
+ |---|---|
583
+ | `en-US` | English |
584
+ | `ru-RU` | Russian |
585
+ | `es-ES` | Spanish |
586
+ | `fr-FR` | French |
587
+ | `de-DE` | German |
588
+ | `it-IT` | Italian |
589
+ | `pt-PT` | Portuguese |
590
+ | `zh-CN` | Simplified Chinese |
591
+ | `ja-JP` | Japanese |
592
+ | `ko-KR` | Korean |
593
+
594
+ The original recording controls are translated for every listed locale.
595
+ The new feedback description fields currently use English fallback outside
596
+ `en-US` and `ru-RU`.
597
+
598
+ ## Public Exports
599
+
600
+ ```ts
601
+ import FeedClip, {
602
+ buildFeedbackAnalysisPrompt,
603
+ collectBrowserContext,
604
+ createFeedbackEndpointTransport,
605
+ createFeedbackId,
606
+ createIndexedDbFeedbackStore,
607
+ getPlanEntitlements,
608
+ isFeatureAllowed,
609
+ createS3Uploader,
610
+ createSupabaseUploader,
611
+ verifyFeedClipLicense,
612
+ } from "@feedclip/sdk";
613
+
614
+ import type {
615
+ BrowserContext,
616
+ Configuration,
617
+ FeedbackAnalysis,
618
+ FeedbackKind,
619
+ FeedbackPriority,
620
+ FeedbackReceipt,
621
+ FeedbackSubmission,
622
+ FeedClipEntitlements,
623
+ FeedClipFeature,
624
+ FeedClipLicenseClaims,
625
+ FeedClipLicenseConfig,
626
+ FeedClipLicenseGrant,
627
+ FeedClipPlan,
628
+ GeneratedIssue,
629
+ } from "@feedclip/sdk";
630
+
631
+ import FeedClipVue from "@feedclip/sdk/vue";
632
+ import { FeedClipAngularComponent } from "@feedclip/sdk/angular";
633
+ ```
634
+
635
+ ## Development
636
+
637
+ ```bash
638
+ yarn install
639
+ yarn dev
640
+ yarn lint
641
+ yarn test
642
+ yarn build
643
+ ```
644
+
645
+ The production build outputs:
646
+
647
+ ```text
648
+ dist/feedclip.js
649
+ dist/feedclip.cjs
650
+ dist/vue.js
651
+ dist/vue.cjs
652
+ dist/angular.js
653
+ dist/angular.cjs
654
+ dist/feedclip.css
655
+ dist/types/
656
+ ```
657
+
658
+ ## Roadmap
659
+
660
+ - hosted multi-tenant ingestion API;
661
+ - secure direct uploads and resumable large-file support;
662
+ - production transcription pipeline;
663
+ - native GitHub, Linear, and Jira connectors;
664
+ - semantic deduplication and feedback clustering;
665
+ - dashboard, search, status tracking, and release linkage;
666
+ - console and network error capture with privacy controls;
667
+ - configurable retention, redaction, consent, and data residency;
668
+ - webhooks and processing-status polling.
669
+
670
+ ## Licensing
671
+
672
+ The current `@feedclip/sdk` repository and npm package are licensed under
673
+ MIT, including commercial use.
674
+
675
+ The Paid FeedClip distribution and hosted services use commercial terms. See
676
+ [COMMERCIAL-LICENSE.md](./COMMERCIAL-LICENSE.md).