@cosmoops/connect-sdk 0.2.0 → 0.6.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 (86) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +284 -7
  3. package/dist/cjs/cli/doctor.js +209 -0
  4. package/dist/cjs/cli/init.js +20 -8
  5. package/dist/cjs/client/components/access-gate.js +162 -0
  6. package/dist/cjs/client/components/account-sessions.js +21 -19
  7. package/dist/cjs/client/components/app-shell.js +157 -0
  8. package/dist/cjs/client/components/apps-grid.js +2 -1
  9. package/dist/cjs/client/components/integrations-modal.js +95 -0
  10. package/dist/cjs/client/components/motion.js +27 -0
  11. package/dist/cjs/client/components/nav.js +97 -0
  12. package/dist/cjs/client/components/plans.js +39 -37
  13. package/dist/cjs/client/components/readiness.js +3 -1
  14. package/dist/cjs/client/components/side-nav.js +58 -0
  15. package/dist/cjs/client/components/subscription.js +2 -1
  16. package/dist/cjs/client/components/surfaces.js +54 -0
  17. package/dist/cjs/client/components/usage-meter.js +3 -2
  18. package/dist/cjs/client/components/user-menu.js +30 -3
  19. package/dist/cjs/client/index.js +29 -1
  20. package/dist/cjs/client/provider.js +54 -2
  21. package/dist/cjs/client/use-active-path.js +77 -0
  22. package/dist/cjs/errors.js +1 -1
  23. package/dist/cjs/next/index.js +96 -15
  24. package/dist/cjs/server/client.js +10 -2
  25. package/dist/cjs/server/handler.js +89 -6
  26. package/dist/cjs/server/index.js +8 -1
  27. package/dist/cjs/server/resources/analytics.js +66 -0
  28. package/dist/cjs/server/resources/identity.js +1 -1
  29. package/dist/cjs/server/resources/integrations.js +66 -0
  30. package/dist/cjs/server/resources/sessions.js +1 -1
  31. package/dist/cjs/server/webhooks.js +127 -0
  32. package/dist/cjs/this-entry-is-server-only.js +31 -0
  33. package/dist/esm/cli/doctor.js +206 -0
  34. package/dist/esm/cli/init.js +20 -8
  35. package/dist/esm/client/components/access-gate.js +158 -0
  36. package/dist/esm/client/components/account-sessions.js +21 -19
  37. package/dist/esm/client/components/app-shell.js +154 -0
  38. package/dist/esm/client/components/apps-grid.js +2 -1
  39. package/dist/esm/client/components/integrations-modal.js +92 -0
  40. package/dist/esm/client/components/motion.js +21 -0
  41. package/dist/esm/client/components/nav.js +89 -0
  42. package/dist/esm/client/components/plans.js +39 -37
  43. package/dist/esm/client/components/readiness.js +3 -1
  44. package/dist/esm/client/components/side-nav.js +53 -0
  45. package/dist/esm/client/components/subscription.js +2 -1
  46. package/dist/esm/client/components/surfaces.js +51 -0
  47. package/dist/esm/client/components/usage-meter.js +3 -2
  48. package/dist/esm/client/components/user-menu.js +31 -4
  49. package/dist/esm/client/index.js +15 -1
  50. package/dist/esm/client/provider.js +53 -2
  51. package/dist/esm/client/use-active-path.js +74 -0
  52. package/dist/esm/errors.js +1 -1
  53. package/dist/esm/next/index.js +95 -15
  54. package/dist/esm/server/client.js +10 -2
  55. package/dist/esm/server/handler.js +89 -6
  56. package/dist/esm/server/index.js +5 -0
  57. package/dist/esm/server/resources/analytics.js +62 -0
  58. package/dist/esm/server/resources/identity.js +1 -1
  59. package/dist/esm/server/resources/integrations.js +62 -0
  60. package/dist/esm/server/resources/sessions.js +1 -1
  61. package/dist/esm/server/webhooks.js +123 -0
  62. package/dist/esm/this-entry-is-server-only.js +30 -0
  63. package/dist/theme.css +28 -0
  64. package/dist/types/cli/doctor.d.ts +23 -0
  65. package/dist/types/cli/init.d.ts +2 -3
  66. package/dist/types/client/components/access-gate.d.ts +79 -0
  67. package/dist/types/client/components/app-shell.d.ts +115 -0
  68. package/dist/types/client/components/integrations-modal.d.ts +21 -0
  69. package/dist/types/client/components/motion.d.ts +22 -0
  70. package/dist/types/client/components/nav.d.ts +110 -0
  71. package/dist/types/client/components/side-nav.d.ts +31 -0
  72. package/dist/types/client/components/surfaces.d.ts +51 -0
  73. package/dist/types/client/index.d.ts +12 -1
  74. package/dist/types/client/provider.d.ts +38 -3
  75. package/dist/types/client/use-active-path.d.ts +8 -0
  76. package/dist/types/errors.d.ts +1 -1
  77. package/dist/types/next/index.d.ts +40 -0
  78. package/dist/types/server/client.d.ts +8 -2
  79. package/dist/types/server/index.d.ts +17 -2
  80. package/dist/types/server/resources/analytics.d.ts +31 -0
  81. package/dist/types/server/resources/identity.d.ts +12 -2
  82. package/dist/types/server/resources/integrations.d.ts +40 -0
  83. package/dist/types/server/webhooks.d.ts +67 -0
  84. package/dist/types/this-entry-is-server-only.d.ts +1 -0
  85. package/dist/types/types.d.ts +182 -1
  86. package/package.json +22 -4
@@ -0,0 +1,40 @@
1
+ import { type TransportOptions } from "../http.js";
2
+ import type { DisconnectIntegrationResponse, ExecuteIntegrationActionResponse, InitiateIntegrationConnectionResponse, IntegrationsListResponse } from "../../types.js";
3
+ export interface ExecuteIntegrationActionInput {
4
+ toolkitSlug: string;
5
+ actionSlug: string;
6
+ /** Passed through to Composio verbatim - its shape is defined by the toolkit's own action schema, which Connect does not model. */
7
+ params?: Record<string, unknown>;
8
+ }
9
+ /**
10
+ * Composio-hosted third-party connections (Google Calendar, Slack,
11
+ * Twitter/X, ...) an organization has connected. Connect proxies every call
12
+ * here - your service never sees or holds the underlying OAuth token, which
13
+ * stays with Composio.
14
+ */
15
+ export declare class IntegrationsResource {
16
+ private readonly transport;
17
+ constructor(transport: TransportOptions);
18
+ /** Enabled toolkits and this organization's connection status for each. */
19
+ list(organizationId: string): Promise<IntegrationsListResponse["toolkits"]>;
20
+ /**
21
+ * Starts a Composio-hosted connection for one toolkit. The returned
22
+ * `redirectUrl` is where the browser completes the provider's OAuth
23
+ * screen, then Composio bounces it back to `returnUrl`.
24
+ *
25
+ * **The connection is not active when this returns.** Treat the toolkit
26
+ * as `pending` until a later `list()` call reports `active` - only
27
+ * Connect's own webhook from Composio confirms that, never the redirect
28
+ * itself. Reconnecting a disconnected/failed toolkit calls this same
29
+ * method - there is no separate reconnect.
30
+ *
31
+ * Meant to be called on behalf of a signed-in org admin (this is what the
32
+ * bridge's fixed `POST /integrations/connect` route does), not as a bare
33
+ * background action with no admin present to complete the OAuth screen.
34
+ */
35
+ initiateConnect(organizationId: string, toolkitSlug: string, returnUrl: string): Promise<InitiateIntegrationConnectionResponse>;
36
+ /** Idempotent - disconnecting a toolkit that was never connected, or is already disconnected, is a success. */
37
+ disconnect(organizationId: string, toolkitSlug: string): Promise<DisconnectIntegrationResponse>;
38
+ /** Calls a Composio action against this organization's connected account for the named toolkit. */
39
+ execute(organizationId: string, input: ExecuteIntegrationActionInput): Promise<ExecuteIntegrationActionResponse>;
40
+ }
@@ -0,0 +1,67 @@
1
+ import type { ConnectWebhookEnvelope, ConnectWebhookEventMap, ConnectWebhookEventType } from "../types.js";
2
+ /**
3
+ * Verifies a `Connect-Signature` header against the raw request body.
4
+ *
5
+ * Exported on its own for anyone wiring this into a framework
6
+ * `createConnectWebhookHandler` does not cover. The **raw** body matters:
7
+ * verify before parsing, and never re-serialise - `JSON.stringify(await
8
+ * req.json())` produces a different string whenever key order or number
9
+ * formatting differs, and the signature will not match.
10
+ *
11
+ * Returns a boolean and never explains which check failed. Reporting "bad
12
+ * timestamp" separately from "bad signature" tells whoever is probing which
13
+ * half of a forgery to keep working on.
14
+ */
15
+ export declare function verifyConnectWebhook(rawBody: string, signatureHeader: string | null | undefined, secret: string, now?: Date): boolean;
16
+ /** One handler per event type. Every one is optional; unhandled types are acknowledged and ignored. */
17
+ export type ConnectWebhookHandlers = {
18
+ [K in ConnectWebhookEventType]?: (data: ConnectWebhookEventMap[K], envelope: ConnectWebhookEnvelope<K>) => void | Promise<void>;
19
+ };
20
+ export interface ConnectWebhookHandlerOptions {
21
+ /** The endpoint's signing secret, from Console. Keep it in an environment variable. */
22
+ secret: string;
23
+ on: ConnectWebhookHandlers;
24
+ /**
25
+ * Called when a handler throws. Return nothing to have the delivery
26
+ * retried (Connect responds to a 5xx by retrying for about 33 hours);
27
+ * the default logs and rethrows, which produces exactly that.
28
+ */
29
+ onError?: (error: unknown, envelope: ConnectWebhookEnvelope) => void | Promise<void>;
30
+ }
31
+ /**
32
+ * A ready-made `POST` route for Connect's webhooks.
33
+ *
34
+ * ```ts
35
+ * export const POST = createConnectWebhookHandler({
36
+ * secret: process.env.CONNECT_WEBHOOK_SECRET!,
37
+ * on: {
38
+ * "organization.deletion_scheduled": ({ organizationId, purgeAfter }) =>
39
+ * freeze(organizationId, purgeAfter),
40
+ * "organization.deletion_cancelled": ({ organizationId }) => unfreeze(organizationId),
41
+ * "organization.deleted": ({ organizationId }) => purge(organizationId),
42
+ * },
43
+ * })
44
+ * ```
45
+ *
46
+ * Three behaviours worth knowing, because each of them is a decision rather
47
+ * than an accident:
48
+ *
49
+ * **An unverified request gets a 401 and nothing else happens.** No parsing,
50
+ * no logging of the body, no handler. The endpoint is a public URL, so
51
+ * anything reachable before the signature check is reachable by anyone.
52
+ *
53
+ * **An unhandled event type is a 200.** Connect adds event types over time,
54
+ * and answering 4xx to one you have not written code for would dead-letter
55
+ * it immediately and, after enough of them, disable your endpoint. Silence
56
+ * is the correct answer to "we do not care about this one".
57
+ *
58
+ * **A throwing handler produces a 500, on purpose.** That is what makes
59
+ * Connect retry. Swallowing the error would acknowledge an event you failed
60
+ * to process, and the retry ladder is the only thing standing between a
61
+ * transient failure and a permanently missed deletion.
62
+ *
63
+ * Delivery is at-least-once and unordered. Dedupe on `envelope.id`, and
64
+ * reconcile against the readiness endpoint rather than trusting arrival
65
+ * order - the pull channel is authoritative, this one is fast.
66
+ */
67
+ export declare function createConnectWebhookHandler(options: ConnectWebhookHandlerOptions): (request: Request) => Promise<Response>;
@@ -0,0 +1 @@
1
+ export {};
@@ -16,6 +16,15 @@ export interface ConnectUser {
16
16
  email: string | null;
17
17
  emailVerified: boolean;
18
18
  displayName: string | null;
19
+ /**
20
+ * The member's profile picture, or `null` when they have not set one.
21
+ *
22
+ * Deliberately nullable rather than a generated placeholder: only you know
23
+ * what your fallback should look like. `<ConnectUserMenu>` renders initials
24
+ * via `<Avatar.Fallback>`, which also covers the URL loading slowly or
25
+ * failing outright - so pair the two rather than branching on `null`.
26
+ */
27
+ photoUrl: string | null;
19
28
  organizationId: string;
20
29
  organizationName: string;
21
30
  }
@@ -95,7 +104,7 @@ export interface RolesResponse {
95
104
  permissionCatalog: ServicePermission[];
96
105
  roles: ServiceRoleDefinition[];
97
106
  }
98
- export type ReadinessBlockerCode = "subscription_missing" | "subscription_inactive" | "audience_mismatch" | "verification_required" | "verification_pending" | "verification_rejected" | "verification_expired" | "payment_method_missing" | "seat_limit_reached" | "organization_not_found" | "onboarding_approval_pending" | "onboarding_approval_rejected";
107
+ export type ReadinessBlockerCode = "subscription_missing" | "subscription_inactive" | "audience_mismatch" | "verification_required" | "verification_pending" | "verification_rejected" | "verification_expired" | "payment_method_missing" | "seat_limit_reached" | "organization_not_found" | "onboarding_approval_pending" | "onboarding_approval_rejected" | "organization_suspended" | "payment_retry_pending";
99
108
  export interface ReadinessBlocker {
100
109
  /**
101
110
  * Branch on this. Typed as a union for the codes that exist today, widened
@@ -108,6 +117,8 @@ export interface ReadinessBlocker {
108
117
  message: string;
109
118
  /** Where in Connect the customer resolves this. `null` when nothing they do helps (e.g. a review in progress). */
110
119
  resolveUrl: string | null;
120
+ /** When this blocker resolves itself automatically - currently only set on `payment_retry_pending`, the deadline dunning suspends the subscription. `undefined`/`null` for every other code. */
121
+ graceEndsAt?: string | null;
111
122
  }
112
123
  export interface ReadinessResponse {
113
124
  organizationId: string;
@@ -432,3 +443,173 @@ export interface RevokeOtherSessionsResponse {
432
443
  }
433
444
  /** Host-controlled - the SDK has no theme provider of its own. See `ConnectUserMenuProps.theme`. */
434
445
  export type ThemeMode = "light" | "dark" | "system";
446
+ /**
447
+ * `not_connected` never travels over the wire as a persisted state - it's
448
+ * what `ListOrganizationIntegrationsUseCase` reports for a toolkit this
449
+ * organization has no `IntegrationConnection` record for at all.
450
+ */
451
+ export type IntegrationConnectionStatus = "not_connected" | "pending" | "active" | "failed" | "disconnected" | "expired";
452
+ /**
453
+ * A Composio-hosted third-party toolkit (Google Calendar, Slack, Twitter/X,
454
+ * ...) this organization can see - only ever one a platform admin enabled in
455
+ * Connect's own Console, joined with this org's own connection status.
456
+ * Connections are org-shared: one covers every member, the way a Slack app
457
+ * install is shared rather than per-user.
458
+ */
459
+ export interface IntegrationToolkit {
460
+ slug: string;
461
+ name: string;
462
+ description: string;
463
+ category: string | null;
464
+ logoUrl: string | null;
465
+ status: IntegrationConnectionStatus;
466
+ }
467
+ export interface IntegrationsListResponse {
468
+ toolkits: IntegrationToolkit[];
469
+ }
470
+ /** The connection isn't active yet when this returns - see `IntegrationsResource.initiateConnect`'s doc comment. */
471
+ export interface InitiateIntegrationConnectionResponse {
472
+ /** Send the browser here to complete the provider's OAuth screen. */
473
+ redirectUrl: string;
474
+ connectionId: string;
475
+ }
476
+ export interface DisconnectIntegrationResponse {
477
+ success: true;
478
+ }
479
+ export interface ExecuteIntegrationActionResponse {
480
+ data: unknown;
481
+ successful: boolean;
482
+ }
483
+ /**
484
+ * The metrics Connect can report for your service.
485
+ *
486
+ * Hand-written here rather than imported from Connect's own registry, like
487
+ * every other wire type in this file, so the published package carries none of
488
+ * Connect's internals. `conformance.test.ts` type-checks these against the
489
+ * server DTOs, so drift fails the build in Connect's repo rather than in a
490
+ * partner's integration.
491
+ */
492
+ export type ConnectMetric = "usage.events" | "usage.active_users" | "api.requests" | "api.errors" | "billing.mrr_paise" | "billing.active_subscriptions" | "metering.addon_consumed";
493
+ export interface AnalyticsPoint {
494
+ /** `YYYY-MM-DD`, UTC. */
495
+ day: string;
496
+ /**
497
+ * **`null` is not zero.** It means the metric was not measurable that day -
498
+ * `usage.active_users` is a distinct count that only exists after Connect's
499
+ * nightly rollup, so today's is always `null`, as is any future day. Render
500
+ * it as a gap or a dash, never as a zero.
501
+ */
502
+ value: number | null;
503
+ }
504
+ export interface AnalyticsSeries {
505
+ metric: ConnectMetric;
506
+ points: AnalyticsPoint[];
507
+ /** Sum across measurable days only, or `null` if no day in the range was measurable. */
508
+ total: number | null;
509
+ /** True when at least one day was not measurable - caveat the total when this is set. */
510
+ partial: boolean;
511
+ }
512
+ export interface AnalyticsResponse {
513
+ from: string;
514
+ to: string;
515
+ series: AnalyticsSeries[];
516
+ }
517
+ export interface AnalyticsQuery {
518
+ metrics: ConnectMetric[];
519
+ /** Inclusive `YYYY-MM-DD`, UTC. The range must be shorter than 90 days. */
520
+ from: string;
521
+ to: string;
522
+ }
523
+ /** One event you push into Connect's analytics pipeline. */
524
+ export interface EmitEventInput {
525
+ /**
526
+ * Dot-namespaced and lowercase, e.g. `checkout.completed`. Prefixes Connect
527
+ * emits itself - `api.`, `billing.`, `addon.`, `subscription.`, `connect.` -
528
+ * are rejected, so your events can never inflate a metered number.
529
+ */
530
+ name: string;
531
+ /** Defaults to now. Clamped server-side to within 48 hours. */
532
+ occurredAt?: string | Date;
533
+ /** Attributes the event to the signed-in user and their organization. */
534
+ sessionToken?: string;
535
+ /** A whole number in the smallest unit of `unit` - paise, bytes, milliseconds. */
536
+ value?: number;
537
+ unit?: string;
538
+ props?: Record<string, unknown>;
539
+ }
540
+ export interface EmitEventsResponse {
541
+ /** False when the call failed outright - see `AnalyticsResource.emit`. */
542
+ delivered: boolean;
543
+ accepted: number;
544
+ attributed: number;
545
+ }
546
+ /**
547
+ * Every event Connect will POST to your webhook endpoint.
548
+ *
549
+ * Additive only - Connect adds event types, never renames one - so a
550
+ * `switch` that does not handle a future type is safe, and
551
+ * `createConnectWebhookHandler` simply ignores anything you have not
552
+ * registered a handler for.
553
+ */
554
+ export type ConnectWebhookEventType = "organization.deletion_scheduled" | "organization.deletion_cancelled" | "organization.deleted" | "subscription.cancelled";
555
+ /**
556
+ * A workspace's deletion has been confirmed and the grace window is running.
557
+ *
558
+ * Access is *already* denied - readiness reports
559
+ * `organization_pending_deletion` from this moment - so treat this as "stop
560
+ * writing", not "start planning". `purgeAfter` is what makes this event worth
561
+ * having: the customer's data still exists until then, so an export or a
562
+ * wind-down can run on the same clock rather than after everything is gone.
563
+ */
564
+ export interface OrganizationDeletionScheduledEvent {
565
+ organizationId: string;
566
+ /** ISO-8601. When Connect destroys the workspace. */
567
+ purgeAfter: string;
568
+ requestedBy: "owner" | "platform_admin";
569
+ graceDays: number;
570
+ }
571
+ /**
572
+ * The deletion was withdrawn and the workspace is live again.
573
+ *
574
+ * **Handle this one.** It is the event integrations forget, and its absence
575
+ * is the worst failure of the set: a service that froze a workspace on
576
+ * `organization.deletion_scheduled` and never unfreezes leaves a paying
577
+ * customer locked out of something that has no idea anything changed.
578
+ */
579
+ export interface OrganizationDeletionCancelledEvent {
580
+ organizationId: string;
581
+ }
582
+ /** The grace window closed and Connect purged the workspace. Purge your own copy. */
583
+ export interface OrganizationDeletedEvent {
584
+ organizationId: string;
585
+ /** ISO-8601. */
586
+ purgedAt: string;
587
+ }
588
+ /** A subscription ended. Fires on its own, not only as part of a deletion. */
589
+ export interface SubscriptionCancelledEvent {
590
+ organizationId: string;
591
+ subscriptionId: string;
592
+ serviceId: string;
593
+ }
594
+ /** Maps each event type to the shape of its `data`. */
595
+ export interface ConnectWebhookEventMap {
596
+ "organization.deletion_scheduled": OrganizationDeletionScheduledEvent;
597
+ "organization.deletion_cancelled": OrganizationDeletionCancelledEvent;
598
+ "organization.deleted": OrganizationDeletedEvent;
599
+ "subscription.cancelled": SubscriptionCancelledEvent;
600
+ }
601
+ /** The envelope, as it arrives on the wire. */
602
+ export interface ConnectWebhookEnvelope<T extends ConnectWebhookEventType = ConnectWebhookEventType> {
603
+ /**
604
+ * Unique per delivery. **Dedupe on this.** Delivery is at-least-once and
605
+ * unordered: a partner that assumes exactly-once, or assumes order, will
606
+ * eventually be wrong.
607
+ */
608
+ id: string;
609
+ type: T;
610
+ /** ISO-8601. */
611
+ createdAt: string;
612
+ /** Bumped only for a breaking payload change - never for a new event type. */
613
+ apiVersion: string;
614
+ data: ConnectWebhookEventMap[T];
615
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmoops/connect-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.6.0",
4
4
  "description": "Official server-side SDK for the CosmoOps Connect platform API - Login with Connect, entitlements, billing and metering.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "commonjs",
@@ -15,11 +15,19 @@
15
15
  },
16
16
  "./server": {
17
17
  "types": "./dist/types/server/index.d.ts",
18
+ "browser": {
19
+ "import": "./dist/esm/this-entry-is-server-only.js",
20
+ "require": "./dist/cjs/this-entry-is-server-only.js"
21
+ },
18
22
  "import": "./dist/esm/server/index.js",
19
23
  "require": "./dist/cjs/server/index.js"
20
24
  },
21
25
  "./next": {
22
26
  "types": "./dist/types/next/index.d.ts",
27
+ "browser": {
28
+ "import": "./dist/esm/this-entry-is-server-only.js",
29
+ "require": "./dist/cjs/this-entry-is-server-only.js"
30
+ },
23
31
  "import": "./dist/esm/next/index.js",
24
32
  "require": "./dist/cjs/next/index.js"
25
33
  },
@@ -39,7 +47,8 @@
39
47
  "node": ">=18"
40
48
  },
41
49
  "files": [
42
- "dist"
50
+ "dist",
51
+ "CHANGELOG.md"
43
52
  ],
44
53
  "keywords": [
45
54
  "cosmoops",
@@ -58,6 +67,8 @@
58
67
  "verify:pack": "bun run scripts/verify-pack.ts",
59
68
  "prepublishOnly": "bun run build && bun run verify:pack",
60
69
  "test": "bun test",
70
+ "docs": "typedoc",
71
+ "docs:md": "typedoc --options typedoc.markdown.json",
61
72
  "storybook": "storybook dev -p 6106",
62
73
  "build:storybook": "storybook build -o storybook-static"
63
74
  },
@@ -72,18 +83,22 @@
72
83
  "@types/react": "^19",
73
84
  "@types/react-dom": "^19",
74
85
  "lucide-react": "^0.545.0",
86
+ "motion": "^13.1.1",
75
87
  "react": "19.2.8",
76
88
  "react-dom": "19.2.8",
77
89
  "storybook": "^10.5.10",
78
90
  "tailwindcss": "^4.3.3",
91
+ "typedoc": "^0.28.20",
92
+ "typedoc-plugin-markdown": "^4.12.0",
79
93
  "typescript": "^5",
80
94
  "vite": "^8.2.2"
81
95
  },
82
96
  "peerDependencies": {
83
97
  "@heroui/react": ">=3.2.0",
84
98
  "lucide-react": ">=0.400.0",
85
- "react": ">=18",
86
- "react-dom": ">=18"
99
+ "motion": ">=12",
100
+ "react": ">=19",
101
+ "react-dom": ">=19"
87
102
  },
88
103
  "peerDependenciesMeta": {
89
104
  "@heroui/react": {
@@ -92,6 +107,9 @@
92
107
  "lucide-react": {
93
108
  "optional": true
94
109
  },
110
+ "motion": {
111
+ "optional": true
112
+ },
95
113
  "react": {
96
114
  "optional": true
97
115
  },