@browserbasehq/sdk-functions 0.0.3 → 0.0.5
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/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -44,10 +44,10 @@ Build status could not be determined. Check the dashboard for updates.`));}else
|
|
|
44
44
|
Your function will be available for invocation once the build is processed.`));}catch(e){console.error(a.red(`
|
|
45
45
|
\u2717 Publish failed: ${e.message??"unknown error"}`)),process.exit(1);}}var ve=A(()=>{le();ue();fe();});var j=class{constructor(e=false){p(this,"nextConnection",null);p(this,"invokeConnection",null);p(this,"currentRequestId",null);p(this,"currentFunctionName",null);p(this,"currentSessionId",null);p(this,"sessionCleanupCallback",null);p(this,"verbose");p(this,"runtimeConnectedOnce",false);this.verbose=e;}setSessionCleanupCallback(e){this.sessionCleanupCallback=e;}holdNextConnection(e){this.nextConnection&&(this.nextConnection.response.writeHead(503,{"Content-Type":"application/json"}),this.nextConnection.response.end(JSON.stringify({error:"Another runtime connected"}))),this.nextConnection={response:e,timestamp:Date.now()},this.runtimeConnectedOnce=true,this.verbose&&console.log(a.cyan("\u{1F50C} Function runtime connected, ready for invocations"));}triggerInvocation(e,n,r,t){if(!this.nextConnection)return this.verbose&&console.log(a.yellow("\u26A0\uFE0F No runtime connected to handle invocation")),false;if(this.invokeConnection)return this.verbose&&console.log(a.yellow("\u26A0\uFE0F Another invocation is already in progress")),false;let i=randomUUID();this.currentRequestId=i,this.currentFunctionName=e,this.currentSessionId=r.session.id,this.invokeConnection={response:t,timestamp:Date.now()};let s={functionName:e,params:n,context:r};return this.nextConnection.response.writeHead(200,{"Content-Type":"application/json","Lambda-Runtime-Aws-Request-Id":i,"Lambda-Runtime-Deadline-Ms":String(Date.now()+3e5),"Lambda-Runtime-Invoked-Function-Arn":`arn:aws:lambda:us-east-1:000000000000:function:${e}`}),this.nextConnection.response.end(JSON.stringify(s)),this.nextConnection=null,console.log(a.blue(`\u{1F680} Invoking function '${e}' (request-id: ${i})`)),true}completeWithSuccess(e,n){return e!==this.currentRequestId?(this.verbose&&console.log(a.yellow(`\u26A0\uFE0F Request ID mismatch: expected ${this.currentRequestId}, got ${e}`)),false):this.invokeConnection?(this.invokeConnection.response.writeHead(200,{"Content-Type":"application/json"}),this.invokeConnection.response.end(JSON.stringify(n??{})),console.log(a.green(`\u2713 Function '${this.currentFunctionName}' completed successfully`)),this.sessionCleanupCallback&&this.currentSessionId&&this.sessionCleanupCallback(this.currentSessionId).catch(r=>{console.error(a.red("Failed to cleanup session:"),r);}),this.invokeConnection=null,this.currentRequestId=null,this.currentFunctionName=null,this.currentSessionId=null,true):(this.verbose&&console.log(a.yellow("\u26A0\uFE0F No active invocation to complete")),false)}completeWithError(e,n){return e!==this.currentRequestId?(this.verbose&&console.log(a.yellow(`\u26A0\uFE0F Request ID mismatch: expected ${this.currentRequestId}, got ${e}`)),false):this.invokeConnection?(this.invokeConnection.response.writeHead(500,{"Content-Type":"application/json"}),this.invokeConnection.response.end(JSON.stringify({error:{message:n.errorMessage,type:n.errorType,stackTrace:n.stackTrace}})),console.log(a.red(`\u2717 Function '${this.currentFunctionName}' failed: ${n.errorMessage}`)),this.sessionCleanupCallback&&this.currentSessionId&&this.sessionCleanupCallback(this.currentSessionId).catch(r=>{console.error(a.red("Failed to cleanup session:"),r);}),this.invokeConnection=null,this.currentRequestId=null,this.currentFunctionName=null,this.currentSessionId=null,true):(this.verbose&&console.log(a.yellow("\u26A0\uFE0F No active invocation to complete")),false)}isReady(){return this.nextConnection!==null&&this.invokeConnection===null}hasActiveInvocation(){return this.invokeConnection!==null}getCurrentRequestId(){return this.currentRequestId}isRuntimeConnected(){return this.runtimeConnectedOnce&&this.nextConnection!==null}};var F=class{constructor(){p(this,"browserbaseClient",null);p(this,"projectId");p(this,"apiKey");p(this,"initialized",false);let e=process.env.BROWSERBASE_PROJECT_ID,n=process.env.BROWSERBASE_API_KEY;if(!e||!n)throw console.error(a.red(`\u2717 Browserbase credentials not found.
|
|
46
46
|
`)+a.red(` Please set BROWSERBASE_PROJECT_ID and BROWSERBASE_API_KEY in your .env file.
|
|
47
|
-
`)+a.gray(" Copy .env.example to .env and fill in your credentials.")),new Error("Missing Browserbase credentials");this.projectId=e,this.apiKey=n;}async initialize(){this.initialized||(this.browserbaseClient=new xe({apiKey:this.apiKey}),this.initialized=true,console.log(a.green("\u2713 Browserbase client initialized")));}async createSession(e){if(!this.browserbaseClient)throw new Error("Browser manager not initialized");console.log(a.cyan("Creating browser session..."));let n=await this.browserbaseClient.sessions.create({projectId:this.projectId,...e}),r={id:n.id,connectUrl:n.connectUrl};return console.log(a.green(`\u2713 Browser session created: ${r.id}`)),r}async closeSession(e){if(!this.browserbaseClient)throw new Error("Browser manager not initialized");try{console.log(a.cyan(`Closing browser session: ${e}...`)),await this.browserbaseClient.sessions.update(e,{projectId:this.projectId,status:"REQUEST_RELEASE"}),console.log(a.green(`\u2713 Browser session closed: ${e}`));}catch(n){console.warn(a.yellow(`\u26A0\uFE0F Could not close session ${e}:`),n instanceof Error?n.message:String(n));}}getProjectId(){return this.projectId}isInitialized(){return this.initialized}};var T=class{constructor(e){p(this,"manifests",new Map);p(this,"manifestsPath");this.manifestsPath=e||join(process.cwd(),".browserbase","functions","manifests");}loadManifests(){if(!existsSync(this.manifestsPath)){console.log(a.yellow(`\u26A0\uFE0F No ${this.manifestsPath} directory found`)),console.log(a.gray(" Run your entrypoint file first to generate manifests"));return}try{let n=readdirSync(this.manifestsPath).filter(r=>r.endsWith(".json"));for(let r of n){let t=join(this.manifestsPath,r),i=readFileSync(t,"utf-8"),s=JSON.parse(i);this.manifests.set(s.name,s),console.log(a.gray(` Loaded manifest for function: ${s.name}`));}this.manifests.size>0?console.log(a.green(`\u2713 Loaded ${this.manifests.size} function manifest(s)`)):console.log(a.yellow("\u26A0\uFE0F No function manifests found in .browserbase directory"));}catch(e){console.error(a.red("Failed to load function manifests:"),e);}}getManifest(e){return this.manifests.get(e)}getSize(){return this.manifests.size}hasManifest(e){return this.manifests.has(e)}getManifestNames(){return Array.from(this.manifests.keys())}};var O={async parseJsonBody(o){return new Promise((e,n)=>{let r="";o.on("data",t=>{r+=t.toString();}),o.on("end",()=>{try{let t=r?JSON.parse(r):{};e(t);}catch(t){n(new Error("Invalid JSON body",{cause:t}));}}),o.on("error",n);})},async parseAndValidate(o,e){let n=await this.parseJsonBody(o);return e.parse(n)}};var y={sendJson(o,e,n){o.writeHead(e,{"Content-Type":"application/json"}),o.end(JSON.stringify(n));},sendSuccess(o,e,n=200){let r={status:"success",...e!==void 0&&{data:e}};this.sendJson(o,n,r);},sendError(o,e,n=500,r,t){let i={error:e};r&&(i.message=r),t&&(i.details=t),this.sendJson(o,n,i);},sendBadRequest(o,e,n){this.sendError(o,"Bad Request",400,e,n);},sendNotFound(o,e){this.sendError(o,"Not Found",404,e);},sendInternalError(o,e="An internal error occurred",n){this.sendError(o,"Internal Server Error",500,e,n);},sendServiceUnavailable(o,e){this.sendError(o,"Service Unavailable",503,e);},sendAccepted(o,e){let n=e||{status:"accepted"};this.sendJson(o,202,n);}};var ke=I.
|
|
47
|
+
`)+a.gray(" Copy .env.example to .env and fill in your credentials.")),new Error("Missing Browserbase credentials");this.projectId=e,this.apiKey=n;}async initialize(){this.initialized||(this.browserbaseClient=new xe({apiKey:this.apiKey}),this.initialized=true,console.log(a.green("\u2713 Browserbase client initialized")));}async createSession(e){if(!this.browserbaseClient)throw new Error("Browser manager not initialized");console.log(a.cyan("Creating browser session..."));let n=await this.browserbaseClient.sessions.create({projectId:this.projectId,...e}),r={id:n.id,connectUrl:n.connectUrl};return console.log(a.green(`\u2713 Browser session created: ${r.id}`)),r}async closeSession(e){if(!this.browserbaseClient)throw new Error("Browser manager not initialized");try{console.log(a.cyan(`Closing browser session: ${e}...`)),await this.browserbaseClient.sessions.update(e,{projectId:this.projectId,status:"REQUEST_RELEASE"}),console.log(a.green(`\u2713 Browser session closed: ${e}`));}catch(n){console.warn(a.yellow(`\u26A0\uFE0F Could not close session ${e}:`),n instanceof Error?n.message:String(n));}}getProjectId(){return this.projectId}isInitialized(){return this.initialized}};var T=class{constructor(e){p(this,"manifests",new Map);p(this,"manifestsPath");this.manifestsPath=e||join(process.cwd(),".browserbase","functions","manifests");}loadManifests(){if(!existsSync(this.manifestsPath)){console.log(a.yellow(`\u26A0\uFE0F No ${this.manifestsPath} directory found`)),console.log(a.gray(" Run your entrypoint file first to generate manifests"));return}try{let n=readdirSync(this.manifestsPath).filter(r=>r.endsWith(".json"));for(let r of n){let t=join(this.manifestsPath,r),i=readFileSync(t,"utf-8"),s=JSON.parse(i);this.manifests.set(s.name,s),console.log(a.gray(` Loaded manifest for function: ${s.name}`));}this.manifests.size>0?console.log(a.green(`\u2713 Loaded ${this.manifests.size} function manifest(s)`)):console.log(a.yellow("\u26A0\uFE0F No function manifests found in .browserbase directory"));}catch(e){console.error(a.red("Failed to load function manifests:"),e);}}getManifest(e){return this.manifests.get(e)}getSize(){return this.manifests.size}hasManifest(e){return this.manifests.has(e)}getManifestNames(){return Array.from(this.manifests.keys())}};var O={async parseJsonBody(o){return new Promise((e,n)=>{let r="";o.on("data",t=>{r+=t.toString();}),o.on("end",()=>{try{let t=r?JSON.parse(r):{};e(t);}catch(t){n(new Error("Invalid JSON body",{cause:t}));}}),o.on("error",n);})},async parseAndValidate(o,e){let n=await this.parseJsonBody(o);return e.parse(n)}};var y={sendJson(o,e,n){o.writeHead(e,{"Content-Type":"application/json"}),o.end(JSON.stringify(n));},sendSuccess(o,e,n=200){let r={status:"success",...e!==void 0&&{data:e}};this.sendJson(o,n,r);},sendError(o,e,n=500,r,t){let i={error:e};r&&(i.message=r),t&&(i.details=t),this.sendJson(o,n,i);},sendBadRequest(o,e,n){this.sendError(o,"Bad Request",400,e,n);},sendNotFound(o,e){this.sendError(o,"Not Found",404,e);},sendInternalError(o,e="An internal error occurred",n){this.sendError(o,"Internal Server Error",500,e,n);},sendServiceUnavailable(o,e){this.sendError(o,"Service Unavailable",503,e);},sendAccepted(o,e){let n=e||{status:"accepted"};this.sendJson(o,202,n);}};var ke=I.looseObject({id:I.string(),connectUrl:I.string()}),U=I.looseObject({session:ke});var Be=I.object({functionName:I.string().min(1),params:I.looseObject({}),context:U});I.object({requestId:I.string().min(1),event:Be});var X=I.object({errorMessage:I.string().min(1),errorType:I.string().min(1),stackTrace:I.array(I.string().min(1))});var q=class{constructor(e){p(this,"bridge");p(this,"browserManager");p(this,"manifestStore");this.bridge=e.bridge,this.browserManager=e.browserManager,this.manifestStore=e.manifestStore,this.bridge.setSessionCleanupCallback(async n=>{await this.cleanupSession(n);});}async handleInvocationNext(e,n){this.bridge.holdNextConnection(n);}async handleFunctionInvoke(e,n,r){try{let t=z$1.object({functionName:z$1.string().optional(),params:z$1.unknown().default({}),context:U.optional()}),i=await O.parseAndValidate(e,t),s=r||i.functionName;if(!s){y.sendBadRequest(n,"Function name is required");return}let d=this.manifestStore.getManifest(s);if(!d){console.error(a.red(`\u2717 Function "${s}" not found in registry`)),console.error(a.gray(" Make sure the function is defined in your entrypoint file")),y.sendNotFound(n,`Function "${s}" not found in registry. Make sure it is defined with defineFn() in your entrypoint file.`);return}let c;try{console.log(a.cyan(`Creating browser session for ${s}...`));let h=d?.config?.sessionConfig||{};c=await this.browserManager.createSession(h);}catch(h){console.error(a.red("Failed to create browser session:"),h),y.sendInternalError(n,"Failed to create browser session",h instanceof Error?h.message:String(h));return}let u=i.context||{invocation:{id:randomUUID(),region:"local"},session:c};if(u.session=c,!this.bridge.triggerInvocation(s,i.params,u,n)){await this.cleanupSession(c.id),y.sendServiceUnavailable(n,this.bridge.hasActiveInvocation()?"Another invocation is in progress":"No runtime connected");return}}catch(t){t instanceof z$1.ZodError?y.sendBadRequest(n,"Invalid request body",t):(console.error(a.red("Error handling invoke:"),t),y.sendInternalError(n));}}async handleInvocationResponse(e,n,r){try{let t=await O.parseJsonBody(e);if(!this.bridge.completeWithSuccess(r,t)){y.sendBadRequest(n,"No matching invocation or request ID mismatch");return}y.sendAccepted(n);}catch(t){console.error(a.red("Error handling response:"),t),y.sendInternalError(n);}}async handleInvocationError(e,n,r){try{let t=await O.parseAndValidate(e,X);if(!this.bridge.completeWithError(r,t)){y.sendBadRequest(n,"No matching invocation or request ID mismatch");return}y.sendAccepted(n);}catch(t){t instanceof z$1.ZodError?y.sendBadRequest(n,"Invalid error format",t):(console.error(a.red("Error handling error report:"),t),y.sendInternalError(n));}}async cleanupSession(e){try{await this.browserManager.closeSession(e);}catch(n){console.error(a.red(`Failed to cleanup session ${e}:`),n);}}};async function Ne(o,e,n){let{handlers:r}=n,t=new URL(o.url||"",`http://${o.headers.host}`),i=o.method||"GET",s=t.pathname;if(console.log(a.gray(`[${i}] ${s}`)),e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, POST, OPTIONS"),e.setHeader("Access-Control-Allow-Headers","Content-Type"),i==="OPTIONS"){e.writeHead(200),e.end();return}try{if(i==="GET"&&s==="/"){e.writeHead(200,{"Content-Type":"application/json"}),e.end(JSON.stringify({ok:!0}));return}if(i==="GET"&&s==="/2018-06-01/runtime/invocation/next"){await r.handleInvocationNext(o,e);return}let d=s.match(/^\/v1\/functions\/([^/]+)\/invoke$/);if(i==="POST"&&d&&d[1]){let m=d[1];await r.handleFunctionInvoke(o,e,m);return}let c=s.match(/^\/2018-06-01\/runtime\/invocation\/([^/]+)\/response$/);if(i==="POST"&&c&&c[1]){let m=c[1];await r.handleInvocationResponse(o,e,m);return}let u=s.match(/^\/2018-06-01\/runtime\/invocation\/([^/]+)\/error$/);if(i==="POST"&&u&&u[1]){let m=u[1];await r.handleInvocationError(o,e,m);return}e.writeHead(404,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"Not found"}));}catch(d){console.error(a.red("Server error:"),d),e.writeHead(500,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:"Internal server error"}));}}async function ne(o){let{port:e,host:n,handlers:i}=o,s=createServer(async(d,c)=>{await Ne(d,c,{handlers:i});});return new Promise((d,c)=>{s.listen(e,n,()=>{d(s);}),s.on("error",u=>{u.code==="EADDRINUSE"?c(new Error(`Port ${e} is already in use`)):u.code==="EACCES"?c(new Error(`Permission denied to bind to port ${e}`)):c(u);});})}var z=class{constructor(e){p(this,"process",null);p(this,"entrypoint");p(this,"runtimeApiUrl");p(this,"verbose");p(this,"isShuttingDown",false);this.entrypoint=e.entrypoint,this.runtimeApiUrl=e.runtimeApiUrl,this.verbose=e.verbose;}async start(){if(this.process)throw new Error("Process is already running");this.verbose&&(console.log(a.gray("Starting runtime process...")),console.log(a.gray(` Command: tsx watch --clear-screen=false ${this.entrypoint}`)),console.log(a.gray(` Working directory: ${process.cwd()}`)),console.log(a.gray(` Runtime API: ${this.runtimeApiUrl}`)));let n=createRequire(import.meta.url).resolve("tsx/cli"),r=["watch","--clear-screen=false",this.entrypoint];if(this.process=spawn(process.execPath,[n,...r],{cwd:process.cwd(),env:{...process.env,AWS_LAMBDA_RUNTIME_API:this.runtimeApiUrl,BB_FUNCTIONS_PHASE:"runtime",NODE_ENV:"local"},stdio:["ignore","pipe","pipe"]}),this.process.stdout?.on("data",t=>{t.toString().trim().split(`
|
|
48
48
|
`).forEach(s=>{s.trim()&&console.log(a.blue("[Runtime]"),s);});}),this.process.stderr?.on("data",t=>{t.toString().trim().split(`
|
|
49
49
|
`).forEach(s=>{s.trim()&&(s.includes("Watching for file changes")?console.log(a.green("\u2713 Runtime watching for file changes")):s.includes("Restarting")?console.log(a.yellow("\u21BB Runtime restarting due to file change...")):console.error(a.red("[Runtime Error]"),s));});}),this.process.on("exit",(t,i)=>{this.isShuttingDown||(t!==0?(console.error(a.red(`\u2717 Runtime process exited unexpectedly with code ${t}`)),i&&console.error(a.red(` Signal: ${i}`))):console.log(a.gray("Runtime process exited")),this.process=null);}),this.process.on("error",t=>{t.code==="ENOENT"?console.error(a.red("\u2717 Failed to start runtime: tsx not found"),a.yellow(`
|
|
50
50
|
Make sure tsx is installed: npm install -g tsx or pnpm add tsx`)):console.error(a.red("\u2717 Failed to start runtime process:"),t),this.process=null;}),await new Promise(t=>setTimeout(t,100)),!this.process||this.process.exitCode!==null)throw new Error("Failed to start runtime process");console.log(a.green("\u2713 Runtime process started"));}async stop(){if(this.process)return this.isShuttingDown=true,this.verbose&&console.log(a.gray("Stopping runtime process...")),new Promise(e=>{if(!this.process){e();return}let n=setTimeout(()=>{this.process&&(console.log(a.yellow("\u26A0\uFE0F Force killing runtime process")),this.process.kill("SIGKILL"));},5e3);this.process.on("exit",()=>{clearTimeout(n),this.process=null,console.log(a.green("\u2713 Runtime process stopped")),e();}),this.process.kill("SIGTERM");})}isRunning(){return this.process!==null&&this.process.exitCode===null}};async function oe(o){let{entrypoint:e,port:n,host:r,verbose:t}=o;process.env.NODE_ENV==="production"&&console.warn(a.yellow("\u26A0\uFE0F Warning: Running dev server in production mode. This is not recommended."));let i=`${r}:${n}`;t&&console.log(a.gray(`Runtime API URL: ${i}`));let s=new j(t),d=new F;await d.initialize();let c=new T;c.loadManifests();let u=new q({bridge:s,browserManager:d,manifestStore:c}),m=new z({entrypoint:e,runtimeApiUrl:i,verbose:t}),h=null;try{h=await ne({port:n,host:r,bridge:s,browserManager:d,handlers:u}),console.log(a.green(`\u2713 Development server listening on http://${r}:${n}`)),console.log(a.cyan("Starting runtime process...")),await m.start();let N=1e4,we=200,be=Date.now(),G=!1;for(;Date.now()-be<N;){if(s.isRuntimeConnected()){G=!0,console.log(a.green("\u2713 Runtime connected and ready")),c.loadManifests();break}await new Promise(W=>setTimeout(W,we));}G||(console.log(a.yellow("\u26A0\uFE0F Runtime is taking longer than expected to connect...")),c.loadManifests());let Y=async()=>(console.log(a.cyan(`
|
|
51
|
-
\u{1F4E6} Shutting down...`)),await m.stop(),new Promise(W=>{h?.close(()=>{console.log(a.green("\u2713 Server closed")),W();});}));process.on("SIGINT",async()=>{await Y(),process.exit(0);}),process.on("SIGTERM",async()=>{await Y(),process.exit(0);});}catch(N){throw console.error(a.red("Failed to start:"),N),m.isRunning()&&await m.stop(),h&&h.close(),N}}var Ue=fileURLToPath(import.meta.url),V=dirname(Ue);async function se(o){if(!Ke(o.projectName))throw new Error(`Invalid project name "${o.projectName}". Project names must start with a letter and contain only letters, numbers, hyphens, and underscores.`);let e=resolve(process.cwd(),o.projectName);if(existsSync(e))throw new Error(`Directory "${o.projectName}" already exists. Please choose a different name or delete the existing directory.`);console.log(a.cyan(`\u{1F680} Creating new Browserbase Functions project: ${a.bold(o.projectName)}`)),mkdirSync(e,{recursive:true});try{qe(),existsSync(join(e,".git"))?console.log(a.yellow("\u2713 Git repository already exists")):(console.log(a.gray("Initializing git repository...")),execSync("git init",{cwd:e,stdio:"pipe"}),console.log(a.green("\u2713 Git repository initialized"))),We(e),existsSync(join(e,"package.json"))?console.log(a.yellow("\u2713 package.json already exists")):(console.log(a.gray("Creating package.json...")),execSync("pnpm init",{cwd:e,stdio:"pipe"}),console.log(a.green("\u2713 package.json created")));let n=ze(o.packageManager);_e(e,n),console.log(a.gray("Installing dependencies...")),Je(e,n),console.log(a.green("\u2713 Dependencies installed")),Le(e),existsSync(join(e,"tsconfig.json"))?console.log(a.yellow("\u2713 TypeScript configuration already exists")):(console.log(a.gray("Initializing TypeScript configuration...")),execSync(`${n==="pnpm"?"pnpm":"npx"} tsc --init`,{cwd:e,stdio:"pipe"}),Ve(e),console.log(a.green("\u2713 TypeScript configuration created"))),He(e),console.log(""),console.log(a.green.bold("\u2728 Project initialized successfully!")),console.log(""),console.log(a.cyan("Next steps:")),console.log(a.gray("1. Navigate to your project:")),console.log(a.white(` cd ${o.projectName}`)),console.log(a.gray("2. Add your Browserbase API key and project ID to .env")),console.log(a.gray("3. Run your function locally:")),console.log(a.white(` ${n==="pnpm"?"pnpm":"npx"} bb dev index.ts`)),console.log(a.gray("4. When ready, publish your function:")),console.log(a.white(` ${n==="pnpm"?"pnpm":"npx"} bb publish index.ts`)),console.log(""),console.log(a.gray("Learn more at https://browserbase.com/docs"));}catch(n){console.error(a.red("\u274C Initialization failed:"),n instanceof Error?n.message:n),process.exit(1);}}function qe(){let o=[{command:"node --version",name:"Node.js"},{command:"pnpm --version",name:"pnpm"},{command:"git --version",name:"git"}];for(let{command:e,name:n}of o)try{execSync(e,{stdio:"pipe"});}catch{throw new Error(`${n} is not installed. Please install ${n} and try again.`)}}function ze(o){if(o)return o;let e=process.env.npm_config_user_agent;return e&&e.includes("pnpm"),"pnpm"}function _e(o,e){let n=join(o,"package.json"),r=JSON.parse(readFileSync(n,"utf-8")),t;try{e==="pnpm"?(t=execSync("pnpm --version",{stdio:"pipe"}).toString().trim(),r.packageManager=`pnpm@${t}`):(t=execSync("npm --version",{stdio:"pipe"}).toString().trim(),r.packageManager=`npm@${t}`);}catch{r.packageManager=e==="pnpm"?"pnpm@9.0.0":"npm@10.0.0";}r.type="module",writeFileSync(n,JSON.stringify(r,null,2)),console.log(a.green(`\u2713 Package manager set to ${r.packageManager}`));}function Je(o,e){let n=e==="pnpm"?"pnpm add":"npm install",r=e==="pnpm"?"pnpm add -D":"npm install --save-dev";console.log(a.gray(" Installing @browserbasehq/sdk-functions...")),execSync(`${n} @browserbasehq/sdk-functions`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing playwright-core...")),execSync(`${n} playwright-core`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing zod...")),execSync(`${n} zod`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing TypeScript and type definitions...")),execSync(`${r} typescript @types/node`,{cwd:o,stdio:"pipe"});}function Le(o){let e=join(o,".env");if(existsSync(e))console.log(a.yellow("\u2713 .env file already exists"));else {let n=join(V,"templates",".env.template");copyFileSync(n,e),console.log(a.green("\u2713 .env file created"));}}function We(o){let e=join(o,".gitignore");if(existsSync(e))console.log(a.yellow("\u2713 .gitignore file already exists"));else {let n=join(V,"templates",".gitignore.template");copyFileSync(n,e),console.log(a.green("\u2713 .gitignore file created"));}}function He(o){let e=join(o,"index.ts");if(existsSync(e))console.log(a.yellow("\u2713 index.ts already exists"));else {let n=join(V,"templates","starter-function.ts.template");copyFileSync(n,e),console.log(a.green("\u2713 Starter function created (index.ts)"));}}function Ve(o){let e=join(o,"tsconfig.json");try{let n=JSON.parse(readFileSync(e,"utf-8"));n.compilerOptions={...n.compilerOptions,target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",esModuleInterop:!0,forceConsistentCasingInFileNames:!0,strict:!0,skipLibCheck:!0,resolveJsonModule:!0},writeFileSync(e,JSON.stringify(n,null,2));}catch{console.log(a.yellow(" Using default TypeScript configuration"));}}function Ke(o){return /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(o)}var M=new Command;M.name("bb").description("Browserbase Functions CLI").version("0.0.
|
|
51
|
+
\u{1F4E6} Shutting down...`)),await m.stop(),new Promise(W=>{h?.close(()=>{console.log(a.green("\u2713 Server closed")),W();});}));process.on("SIGINT",async()=>{await Y(),process.exit(0);}),process.on("SIGTERM",async()=>{await Y(),process.exit(0);});}catch(N){throw console.error(a.red("Failed to start:"),N),m.isRunning()&&await m.stop(),h&&h.close(),N}}var Ue=fileURLToPath(import.meta.url),V=dirname(Ue);async function se(o){if(!Ke(o.projectName))throw new Error(`Invalid project name "${o.projectName}". Project names must start with a letter and contain only letters, numbers, hyphens, and underscores.`);let e=resolve(process.cwd(),o.projectName);if(existsSync(e))throw new Error(`Directory "${o.projectName}" already exists. Please choose a different name or delete the existing directory.`);console.log(a.cyan(`\u{1F680} Creating new Browserbase Functions project: ${a.bold(o.projectName)}`)),mkdirSync(e,{recursive:true});try{qe(),existsSync(join(e,".git"))?console.log(a.yellow("\u2713 Git repository already exists")):(console.log(a.gray("Initializing git repository...")),execSync("git init",{cwd:e,stdio:"pipe"}),console.log(a.green("\u2713 Git repository initialized"))),We(e),existsSync(join(e,"package.json"))?console.log(a.yellow("\u2713 package.json already exists")):(console.log(a.gray("Creating package.json...")),execSync("pnpm init",{cwd:e,stdio:"pipe"}),console.log(a.green("\u2713 package.json created")));let n=ze(o.packageManager);_e(e,n),console.log(a.gray("Installing dependencies...")),Je(e,n),console.log(a.green("\u2713 Dependencies installed")),Le(e),existsSync(join(e,"tsconfig.json"))?console.log(a.yellow("\u2713 TypeScript configuration already exists")):(console.log(a.gray("Initializing TypeScript configuration...")),execSync(`${n==="pnpm"?"pnpm":"npx"} tsc --init`,{cwd:e,stdio:"pipe"}),Ve(e),console.log(a.green("\u2713 TypeScript configuration created"))),He(e),console.log(""),console.log(a.green.bold("\u2728 Project initialized successfully!")),console.log(""),console.log(a.cyan("Next steps:")),console.log(a.gray("1. Navigate to your project:")),console.log(a.white(` cd ${o.projectName}`)),console.log(a.gray("2. Add your Browserbase API key and project ID to .env")),console.log(a.gray("3. Run your function locally:")),console.log(a.white(` ${n==="pnpm"?"pnpm":"npx"} bb dev index.ts`)),console.log(a.gray("4. When ready, publish your function:")),console.log(a.white(` ${n==="pnpm"?"pnpm":"npx"} bb publish index.ts`)),console.log(""),console.log(a.gray("Learn more at https://browserbase.com/docs"));}catch(n){console.error(a.red("\u274C Initialization failed:"),n instanceof Error?n.message:n),process.exit(1);}}function qe(){let o=[{command:"node --version",name:"Node.js"},{command:"pnpm --version",name:"pnpm"},{command:"git --version",name:"git"}];for(let{command:e,name:n}of o)try{execSync(e,{stdio:"pipe"});}catch{throw new Error(`${n} is not installed. Please install ${n} and try again.`)}}function ze(o){if(o)return o;let e=process.env.npm_config_user_agent;return e&&e.includes("pnpm"),"pnpm"}function _e(o,e){let n=join(o,"package.json"),r=JSON.parse(readFileSync(n,"utf-8")),t;try{e==="pnpm"?(t=execSync("pnpm --version",{stdio:"pipe"}).toString().trim(),r.packageManager=`pnpm@${t}`):(t=execSync("npm --version",{stdio:"pipe"}).toString().trim(),r.packageManager=`npm@${t}`);}catch{r.packageManager=e==="pnpm"?"pnpm@9.0.0":"npm@10.0.0";}r.type="module",writeFileSync(n,JSON.stringify(r,null,2)),console.log(a.green(`\u2713 Package manager set to ${r.packageManager}`));}function Je(o,e){let n=e==="pnpm"?"pnpm add":"npm install",r=e==="pnpm"?"pnpm add -D":"npm install --save-dev";console.log(a.gray(" Installing @browserbasehq/sdk-functions...")),execSync(`${n} @browserbasehq/sdk-functions`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing playwright-core...")),execSync(`${n} playwright-core`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing zod...")),execSync(`${n} zod`,{cwd:o,stdio:"pipe"}),console.log(a.gray(" Installing TypeScript and type definitions...")),execSync(`${r} typescript @types/node`,{cwd:o,stdio:"pipe"});}function Le(o){let e=join(o,".env");if(existsSync(e))console.log(a.yellow("\u2713 .env file already exists"));else {let n=join(V,"templates",".env.template");copyFileSync(n,e),console.log(a.green("\u2713 .env file created"));}}function We(o){let e=join(o,".gitignore");if(existsSync(e))console.log(a.yellow("\u2713 .gitignore file already exists"));else {let n=join(V,"templates",".gitignore.template");copyFileSync(n,e),console.log(a.green("\u2713 .gitignore file created"));}}function He(o){let e=join(o,"index.ts");if(existsSync(e))console.log(a.yellow("\u2713 index.ts already exists"));else {let n=join(V,"templates","starter-function.ts.template");copyFileSync(n,e),console.log(a.green("\u2713 Starter function created (index.ts)"));}}function Ve(o){let e=join(o,"tsconfig.json");try{let n=JSON.parse(readFileSync(e,"utf-8"));n.compilerOptions={...n.compilerOptions,target:"ES2022",module:"NodeNext",moduleResolution:"NodeNext",esModuleInterop:!0,forceConsistentCasingInFileNames:!0,strict:!0,skipLibCheck:!0,resolveJsonModule:!0},writeFileSync(e,JSON.stringify(n,null,2));}catch{console.log(a.yellow(" Using default TypeScript configuration"));}}function Ke(o){return /^[a-zA-Z][a-zA-Z0-9_-]*$/.test(o)}var M=new Command;M.name("bb").description("Browserbase Functions CLI").version("0.0.4");var K=["npm","pnpm"];M.command("init <project-name>").description("Initialize a new Browserbase Functions project").option("-p, --package-manager <manager>",`Package manager to use (${K.join(" or ")})`,"pnpm").action(async(o,e)=>{try{let n=e.packageManager.toLowerCase();K.includes(n)||(console.error(a.red(`Error: Invalid package manager "${e.packageManager}"`)),console.error(a.gray(`Valid options are: ${K.join(", ")}`)),process.exit(1)),await se({projectName:o,packageManager:n});}catch(n){console.error(a.red("Initialization failed:"),n),process.exit(1);}});M.command("dev").description("Start a local development server for testing Browserbase Functions").argument("<entrypoint>","Path to the TypeScript/JavaScript file that imports all your functions").option("-p, --port <number>","Port to listen on","14113").option("-h, --host <string>","Host to bind to","127.0.0.1").action(async(o,e)=>{try{let n=await import('fs'),r=await import('path'),t=r.resolve(o);n.existsSync(t)||(console.error(a.red(`Error: Entrypoint file not found: ${t}`)),process.exit(1));let i=r.extname(t);[".ts",".tsx",".js",".jsx",".mjs",".cjs"].includes(i)||(console.error(a.red("Error: Invalid file extension. Expected .ts, .tsx, .js, .jsx, .mjs, or .cjs")),process.exit(1));let s=parseInt(e.port,10);(isNaN(s)||s<1||s>65535)&&(console.error(a.red("Error: Invalid port number. Must be between 1 and 65535.")),process.exit(1)),console.log(a.cyan("Starting Browserbase Functions development server...")),console.log(a.gray(`Entrypoint: ${t}`)),await oe({entrypoint:t,port:s,host:e.host,verbose:e.verbose});}catch(n){console.error(a.red("Failed to start development server:"),n),process.exit(1);}});M.command("publish").description("Publish your Browserbase Function to the cloud").argument("<entrypoint>","Path to the TypeScript/JavaScript file that imports all your functions").option("-u, --api-url <url>","API endpoint URL").option("--dry-run","Show what would be published without uploading").action(async(o,e)=>{try{let{publishFunction:n}=await Promise.resolve().then(()=>(ve(),ye));await n({entrypoint:o,apiUrl:e.apiUrl,dryRun:e.dryRun});}catch(n){console.error(a.red("Publish failed:"),n),process.exit(1);}});M.parse();
|
|
52
52
|
//# sourceMappingURL=cli.js.map
|
|
53
53
|
//# sourceMappingURL=cli.js.map
|