@mushi-mushi/cli 0.27.1 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,475 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/detect.ts
4
+ import { readFileSync, existsSync } from "fs";
5
+ import { join } from "path";
6
+ var FRAMEWORK_IDS = [
7
+ "next",
8
+ "react",
9
+ "cra",
10
+ "remix",
11
+ "astro",
12
+ "solid",
13
+ "vue",
14
+ "nuxt",
15
+ "svelte",
16
+ "sveltekit",
17
+ "angular",
18
+ "expo",
19
+ "react-native",
20
+ "capacitor",
21
+ "express",
22
+ "fastify",
23
+ "hono",
24
+ "vanilla"
25
+ ];
26
+ function isFrameworkId(value) {
27
+ return typeof value === "string" && FRAMEWORK_IDS.includes(value);
28
+ }
29
+ var FRAMEWORKS = {
30
+ next: {
31
+ id: "next",
32
+ label: "Next.js",
33
+ packageName: "@mushi-mushi/react",
34
+ needsWebPackage: false,
35
+ snippet: () => `// app/providers.tsx (or pages/_app.tsx for /pages router)
36
+ 'use client'
37
+ import { MushiProvider } from '@mushi-mushi/react'
38
+
39
+ export function Providers({ children }: { children: React.ReactNode }) {
40
+ return (
41
+ <MushiProvider config={{
42
+ projectId: process.env.NEXT_PUBLIC_MUSHI_PROJECT_ID!,
43
+ apiKey: process.env.NEXT_PUBLIC_MUSHI_API_KEY!,
44
+ }}>
45
+ {children}
46
+ </MushiProvider>
47
+ )
48
+ }`
49
+ },
50
+ react: {
51
+ id: "react",
52
+ label: "React",
53
+ packageName: "@mushi-mushi/react",
54
+ needsWebPackage: false,
55
+ snippet: () => `// src/main.tsx
56
+ import { MushiProvider } from '@mushi-mushi/react'
57
+
58
+ createRoot(document.getElementById('root')!).render(
59
+ <MushiProvider config={{
60
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
61
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
62
+ }}>
63
+ <App />
64
+ </MushiProvider>
65
+ )`
66
+ },
67
+ cra: {
68
+ id: "cra",
69
+ label: "Create React App",
70
+ packageName: "@mushi-mushi/react",
71
+ needsWebPackage: false,
72
+ // CRA inlines only REACT_APP_*-prefixed vars into process.env at build time.
73
+ snippet: () => `// src/index.tsx
74
+ import { MushiProvider } from '@mushi-mushi/react'
75
+
76
+ root.render(
77
+ <MushiProvider config={{
78
+ projectId: process.env.REACT_APP_MUSHI_PROJECT_ID,
79
+ apiKey: process.env.REACT_APP_MUSHI_API_KEY,
80
+ }}>
81
+ <App />
82
+ </MushiProvider>
83
+ )`
84
+ },
85
+ remix: {
86
+ id: "remix",
87
+ label: "Remix",
88
+ packageName: "@mushi-mushi/react",
89
+ needsWebPackage: false,
90
+ // Remix doesn't inline client env. Expose public values at runtime via the
91
+ // root loader + window.ENV (works on both the classic compiler and Vite).
92
+ snippet: () => `// app/root.tsx
93
+ import { MushiProvider } from '@mushi-mushi/react'
94
+ import { useLoaderData } from '@remix-run/react'
95
+
96
+ export async function loader() {
97
+ return { ENV: {
98
+ MUSHI_PROJECT_ID: process.env.MUSHI_PROJECT_ID,
99
+ MUSHI_API_KEY: process.env.MUSHI_API_KEY,
100
+ } }
101
+ }
102
+
103
+ export default function App() {
104
+ const { ENV } = useLoaderData<typeof loader>()
105
+ return (
106
+ <html>
107
+ <body>
108
+ <MushiProvider config={{ projectId: ENV.MUSHI_PROJECT_ID, apiKey: ENV.MUSHI_API_KEY }}>
109
+ <Outlet />
110
+ </MushiProvider>
111
+ <Scripts />
112
+ </body>
113
+ </html>
114
+ )
115
+ }`
116
+ },
117
+ astro: {
118
+ id: "astro",
119
+ label: "Astro",
120
+ packageName: "@mushi-mushi/web",
121
+ needsWebPackage: false,
122
+ // Astro exposes only PUBLIC_*-prefixed vars to client code (Vite-based).
123
+ snippet: () => `---
124
+ // src/layouts/Layout.astro (add this <script> once, e.g. in your base layout)
125
+ ---
126
+ <script>
127
+ import { Mushi } from '@mushi-mushi/web'
128
+ Mushi.init({
129
+ projectId: import.meta.env.PUBLIC_MUSHI_PROJECT_ID,
130
+ apiKey: import.meta.env.PUBLIC_MUSHI_API_KEY,
131
+ })
132
+ </script>`
133
+ },
134
+ solid: {
135
+ id: "solid",
136
+ label: "Solid",
137
+ packageName: "@mushi-mushi/web",
138
+ needsWebPackage: false,
139
+ // Solid / SolidStart are Vite-based → VITE_*-prefixed client env.
140
+ snippet: () => `// src/index.tsx (or src/app.tsx for SolidStart)
141
+ import { onMount } from 'solid-js'
142
+ import { Mushi } from '@mushi-mushi/web'
143
+
144
+ onMount(() => {
145
+ Mushi.init({
146
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
147
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
148
+ })
149
+ })`
150
+ },
151
+ vue: {
152
+ id: "vue",
153
+ label: "Vue 3",
154
+ packageName: "@mushi-mushi/vue",
155
+ needsWebPackage: false,
156
+ snippet: () => `// src/main.ts
157
+ import { MushiPlugin } from '@mushi-mushi/vue'
158
+
159
+ app.use(MushiPlugin, {
160
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
161
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
162
+ })`
163
+ },
164
+ nuxt: {
165
+ id: "nuxt",
166
+ label: "Nuxt",
167
+ packageName: "@mushi-mushi/vue",
168
+ needsWebPackage: false,
169
+ snippet: () => `// plugins/mushi.client.ts
170
+ import { MushiPlugin } from '@mushi-mushi/vue'
171
+
172
+ export default defineNuxtPlugin((nuxtApp) => {
173
+ nuxtApp.vueApp.use(MushiPlugin, {
174
+ projectId: import.meta.env.NUXT_PUBLIC_MUSHI_PROJECT_ID,
175
+ apiKey: import.meta.env.NUXT_PUBLIC_MUSHI_API_KEY,
176
+ })
177
+ })`
178
+ },
179
+ svelte: {
180
+ id: "svelte",
181
+ label: "Svelte",
182
+ packageName: "@mushi-mushi/svelte",
183
+ needsWebPackage: false,
184
+ snippet: () => `// src/main.ts
185
+ import { initMushi } from '@mushi-mushi/svelte'
186
+
187
+ initMushi({
188
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
189
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
190
+ })`
191
+ },
192
+ sveltekit: {
193
+ id: "sveltekit",
194
+ label: "SvelteKit",
195
+ packageName: "@mushi-mushi/svelte",
196
+ needsWebPackage: false,
197
+ snippet: () => `// src/routes/+layout.svelte
198
+ <script>
199
+ import { onMount } from 'svelte'
200
+
201
+ onMount(async () => {
202
+ const { initMushi } = await import('@mushi-mushi/svelte')
203
+ initMushi({
204
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
205
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
206
+ })
207
+ })
208
+ </script>`
209
+ },
210
+ angular: {
211
+ id: "angular",
212
+ label: "Angular",
213
+ packageName: "@mushi-mushi/angular",
214
+ needsWebPackage: false,
215
+ snippet: () => `// src/main.ts
216
+ import { provideMushi } from '@mushi-mushi/angular'
217
+
218
+ bootstrapApplication(AppComponent, {
219
+ providers: [
220
+ provideMushi({
221
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
222
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
223
+ }),
224
+ ],
225
+ })`
226
+ },
227
+ expo: {
228
+ id: "expo",
229
+ label: "Expo",
230
+ packageName: "@mushi-mushi/react-native",
231
+ needsWebPackage: false,
232
+ snippet: () => `// App.tsx
233
+ import { MushiProvider } from '@mushi-mushi/react-native'
234
+
235
+ export default function App() {
236
+ return (
237
+ <MushiProvider
238
+ projectId={process.env.EXPO_PUBLIC_MUSHI_PROJECT_ID!}
239
+ apiKey={process.env.EXPO_PUBLIC_MUSHI_API_KEY!}
240
+ >
241
+ <YourApp />
242
+ </MushiProvider>
243
+ )
244
+ }`
245
+ },
246
+ "react-native": {
247
+ id: "react-native",
248
+ label: "React Native",
249
+ packageName: "@mushi-mushi/react-native",
250
+ needsWebPackage: false,
251
+ snippet: () => `// App.tsx
252
+ import { MushiProvider } from '@mushi-mushi/react-native'
253
+
254
+ export default function App() {
255
+ return (
256
+ <MushiProvider
257
+ projectId={process.env.MUSHI_PROJECT_ID!}
258
+ apiKey={process.env.MUSHI_API_KEY!}
259
+ >
260
+ <YourApp />
261
+ </MushiProvider>
262
+ )
263
+ }`
264
+ },
265
+ capacitor: {
266
+ id: "capacitor",
267
+ label: "Capacitor (Ionic)",
268
+ packageName: "@mushi-mushi/capacitor",
269
+ needsWebPackage: false,
270
+ /* The Capacitor plugin's public API is `Mushi.configure(...)`, not
271
+ * `Mushi.init(...)` — see packages/capacitor/src/definitions.ts. We
272
+ * shipped the wrong call here for two releases and users got a runtime
273
+ * `TypeError: Mushi.init is not a function`. The accompanying admin
274
+ * console snippet (apps/admin/src/lib/sdkSnippets.ts) emits the same
275
+ * `Mushi.configure(...)` shape; both are pinned by tests. */
276
+ snippet: () => `// src/main.ts \u2014 after install, run \`npx cap sync\`
277
+ import { Mushi } from '@mushi-mushi/capacitor'
278
+
279
+ await Mushi.configure({
280
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
281
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
282
+ })`
283
+ },
284
+ express: {
285
+ id: "express",
286
+ label: "Express",
287
+ packageName: "@mushi-mushi/node",
288
+ needsWebPackage: false,
289
+ snippet: () => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
290
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
291
+ import { mushiExpressErrorHandler } from '@mushi-mushi/node/express'
292
+ import type { Express } from 'express'
293
+
294
+ export const mushi = new MushiNodeClient({
295
+ projectId: process.env.MUSHI_PROJECT_ID!,
296
+ apiKey: process.env.MUSHI_API_KEY!,
297
+ environment: process.env.NODE_ENV ?? 'production',
298
+ })
299
+ attachUnhandledHook({ client: mushi })
300
+
301
+ export function attachMushi(app: Express) {
302
+ app.use(mushiExpressErrorHandler({ client: mushi }))
303
+ }`
304
+ },
305
+ fastify: {
306
+ id: "fastify",
307
+ label: "Fastify",
308
+ packageName: "@mushi-mushi/node",
309
+ needsWebPackage: false,
310
+ snippet: () => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
311
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
312
+ import { mushiFastifyPlugin } from '@mushi-mushi/node/fastify'
313
+ import Fastify from 'fastify'
314
+
315
+ export const mushi = new MushiNodeClient({
316
+ projectId: process.env.MUSHI_PROJECT_ID!,
317
+ apiKey: process.env.MUSHI_API_KEY!,
318
+ environment: process.env.NODE_ENV ?? 'production',
319
+ })
320
+ attachUnhandledHook({ client: mushi })
321
+
322
+ const app = Fastify()
323
+ mushiFastifyPlugin(app, { client: mushi })`
324
+ },
325
+ hono: {
326
+ id: "hono",
327
+ label: "Hono",
328
+ packageName: "@mushi-mushi/node",
329
+ needsWebPackage: false,
330
+ snippet: () => `// src/instrument.ts \u2014 load with: node --import ./dist/instrument.js
331
+ import { MushiNodeClient, attachUnhandledHook } from '@mushi-mushi/node'
332
+ import { mushiHonoErrorHandler } from '@mushi-mushi/node/hono'
333
+ import { Hono } from 'hono'
334
+
335
+ export const mushi = new MushiNodeClient({
336
+ projectId: process.env.MUSHI_PROJECT_ID!,
337
+ apiKey: process.env.MUSHI_API_KEY!,
338
+ environment: process.env.NODE_ENV ?? 'production',
339
+ })
340
+ attachUnhandledHook({ client: mushi })
341
+
342
+ const app = new Hono()
343
+ app.onError(
344
+ mushiHonoErrorHandler({ client: mushi }, (err, c) =>
345
+ c.text('Internal Server Error', 500),
346
+ ),
347
+ )`
348
+ },
349
+ vanilla: {
350
+ id: "vanilla",
351
+ label: "Vanilla JS / unknown",
352
+ packageName: "@mushi-mushi/web",
353
+ needsWebPackage: false,
354
+ snippet: () => `// Anywhere in your client bundle
355
+ import { Mushi } from '@mushi-mushi/web'
356
+
357
+ Mushi.init({
358
+ projectId: import.meta.env.VITE_MUSHI_PROJECT_ID,
359
+ apiKey: import.meta.env.VITE_MUSHI_API_KEY,
360
+ })`
361
+ }
362
+ };
363
+ function readPackageJson(cwd) {
364
+ const path = join(cwd, "package.json");
365
+ if (!existsSync(path)) return null;
366
+ try {
367
+ return JSON.parse(readFileSync(path, "utf-8"));
368
+ } catch {
369
+ return null;
370
+ }
371
+ }
372
+ function detectFramework(cwd, pkg) {
373
+ const deps = collectDeps(pkg);
374
+ if (deps.has("next")) return FRAMEWORKS.next;
375
+ if (deps.has("nuxt")) return FRAMEWORKS.nuxt;
376
+ if (deps.has("@sveltejs/kit")) return FRAMEWORKS.sveltekit;
377
+ if (deps.has("@angular/core")) return FRAMEWORKS.angular;
378
+ if (deps.has("expo")) return FRAMEWORKS.expo;
379
+ if (deps.has("react-native")) return FRAMEWORKS["react-native"];
380
+ if (deps.has("@remix-run/react") || deps.has("@remix-run/node") || deps.has("@remix-run/serve")) {
381
+ return FRAMEWORKS.remix;
382
+ }
383
+ if (deps.has("astro")) return FRAMEWORKS.astro;
384
+ if (deps.has("@solidjs/start") || deps.has("solid-js")) return FRAMEWORKS.solid;
385
+ if (deps.has("@capacitor/core") && deps.has("react")) return FRAMEWORKS.react;
386
+ if (deps.has("@capacitor/core")) return FRAMEWORKS.capacitor;
387
+ if (deps.has("svelte")) return FRAMEWORKS.svelte;
388
+ if (deps.has("vue")) return FRAMEWORKS.vue;
389
+ if (deps.has("react-scripts")) return FRAMEWORKS.cra;
390
+ if (deps.has("react")) return FRAMEWORKS.react;
391
+ if (deps.has("express")) return FRAMEWORKS.express;
392
+ if (deps.has("fastify")) return FRAMEWORKS.fastify;
393
+ if (deps.has("hono") || deps.has("@hono/hono")) return FRAMEWORKS.hono;
394
+ if (existsSync(join(cwd, "next.config.js")) || existsSync(join(cwd, "next.config.ts"))) {
395
+ return FRAMEWORKS.next;
396
+ }
397
+ if (existsSync(join(cwd, "nuxt.config.ts")) || existsSync(join(cwd, "nuxt.config.js"))) {
398
+ return FRAMEWORKS.nuxt;
399
+ }
400
+ if (existsSync(join(cwd, "svelte.config.js"))) return FRAMEWORKS.svelte;
401
+ if (existsSync(join(cwd, "angular.json"))) return FRAMEWORKS.angular;
402
+ if (existsSync(join(cwd, "remix.config.js")) || existsSync(join(cwd, "remix.config.ts"))) {
403
+ return FRAMEWORKS.remix;
404
+ }
405
+ if (existsSync(join(cwd, "astro.config.mjs")) || existsSync(join(cwd, "astro.config.ts")) || existsSync(join(cwd, "astro.config.js"))) {
406
+ return FRAMEWORKS.astro;
407
+ }
408
+ return FRAMEWORKS.vanilla;
409
+ }
410
+ function detectPackageManager(cwd) {
411
+ if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock"))) return "bun";
412
+ if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
413
+ if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
414
+ if (existsSync(join(cwd, "package-lock.json"))) return "npm";
415
+ const userAgent = process.env.npm_config_user_agent ?? "";
416
+ if (userAgent.startsWith("bun")) return "bun";
417
+ if (userAgent.startsWith("pnpm")) return "pnpm";
418
+ if (userAgent.startsWith("yarn")) return "yarn";
419
+ return "npm";
420
+ }
421
+ function installCommand(pm, packages) {
422
+ const verb = pm === "npm" ? "install" : "add";
423
+ return `${pm} ${verb} ${packages.join(" ")}`;
424
+ }
425
+ var SERVER_FRAMEWORK_IDS = /* @__PURE__ */ new Set(["express", "fastify", "hono"]);
426
+ function envVarsToWrite(apiKey, projectId, framework, endpoint) {
427
+ const CLOUD_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
428
+ const endpointLine = endpoint && endpoint !== CLOUD_ENDPOINT ? `MUSHI_API_ENDPOINT=${endpoint}` : null;
429
+ if (SERVER_FRAMEWORK_IDS.has(framework.id)) {
430
+ return [
431
+ `MUSHI_PROJECT_ID=${projectId}`,
432
+ `MUSHI_API_KEY=${apiKey}`,
433
+ endpointLine
434
+ ].filter(Boolean).join("\n");
435
+ }
436
+ if (framework.id === "react-native" || framework.id === "remix") {
437
+ return [
438
+ `MUSHI_PROJECT_ID=${projectId}`,
439
+ `MUSHI_API_KEY=${apiKey}`,
440
+ endpointLine
441
+ ].filter(Boolean).join("\n");
442
+ }
443
+ if (framework.id === "expo") {
444
+ return [
445
+ `EXPO_PUBLIC_MUSHI_PROJECT_ID=${projectId}`,
446
+ `EXPO_PUBLIC_MUSHI_API_KEY=${apiKey}`,
447
+ endpointLine ? `EXPO_PUBLIC_${endpointLine}` : null
448
+ ].filter(Boolean).join("\n");
449
+ }
450
+ const prefix = framework.id === "next" ? "NEXT_PUBLIC_" : framework.id === "nuxt" ? "NUXT_PUBLIC_" : framework.id === "cra" ? "REACT_APP_" : framework.id === "astro" ? "PUBLIC_" : "VITE_";
451
+ return [
452
+ `${prefix}MUSHI_PROJECT_ID=${projectId}`,
453
+ `${prefix}MUSHI_API_KEY=${apiKey}`,
454
+ endpointLine ? `${prefix}${endpointLine}` : null
455
+ ].filter(Boolean).join("\n");
456
+ }
457
+ function collectDeps(pkg) {
458
+ if (!pkg) return /* @__PURE__ */ new Set();
459
+ return /* @__PURE__ */ new Set([
460
+ ...Object.keys(pkg.dependencies ?? {}),
461
+ ...Object.keys(pkg.devDependencies ?? {}),
462
+ ...Object.keys(pkg.peerDependencies ?? {})
463
+ ]);
464
+ }
465
+
466
+ export {
467
+ FRAMEWORK_IDS,
468
+ isFrameworkId,
469
+ FRAMEWORKS,
470
+ readPackageJson,
471
+ detectFramework,
472
+ detectPackageManager,
473
+ installCommand,
474
+ envVarsToWrite
475
+ };