GithubHelp home page GithubHelp logo

mono-ts's Introduction

Mono TS

Introduction

There is an accompanying article "My quest for the perfect TS monorepo" that you might want to read for context.

This is a personal quest for the perfect Typescript monorepo setup.

It is the best I could come up with given the tooling that is available, so expect this repository to change over time as the ecosystem around Typescript and Javascript evolves.

My current projects are based on Node.js, Next.js, and Firebase, so that is what I am focussing on. If you use different platforms, I believe this is still a great reference, as it should be easy discard anything you have no use for. The approach itself is largely independent of the chosen technology stack.

Also, I am still working on some Firestore abstractions (server and client-side) that will hopefully make it in here in the coming months.

Contributions and suggestions are welcome within the scope of this example, but I doubt there ever will be a one-size-fits-all solution, so this code should be viewed as opinionated.

I ended up basing a lot of things on the Turborepo starter, and I recommend reading their monorepo handbook.

Features

  • Turborepo to orchestrate the build process and dependencies
  • Showing a traditional "built package" with multiple entry points as well as the "internal package" strategy referencing Typescript code directly
  • Multiple isolated Firebase deployments, using isolate-package
  • Firebase emulators with live code updates using firebase-tools-with-isolate
  • A web app based on Next.js with ShadCN and Tailwind CSS
  • Using ESM throughout, including the Next.js app
  • Shared configurations for ESLint and Typescript
  • Path aliases
  • Working IDE go-to-definition and go-to-type-definition using .d.ts.map files
  • Vitest

Install

In the main branch of this repo, packages are managed with PNPM, but if you prefer to use a different package manager, there is a branch using NPM, a branch using classic Yarn (v1), and a branch using modern Yarn (v4)

I recommended using pnpm over npm or yarn. Apart from being fast and efficient, PNPM has better support for monorepos, and the lockfile isolation code is solid and works in parallel for multiple packages, unlike NPM

You can install PNPM with corepack which is part of modern Node.js versions:

  • corepack enable (if you have not used it before)
  • corepack prepare pnpm@latest --activate

Then run pnpm install from the repository root.

Usage

To get started quickly run npx turbo dev from the root.

This will:

  • Build the web app and start its dev server
  • Build the api and fns backend services and start their emulators.

The web app should become available on http://localhost:3000 and the emulators UI on http://localhost:4000.

Alternatively, you can start the emulators and dev server separately. It makes the console output more readable and preserves coloring:

  • In apps/web run pnpm dev
  • In services/fns run pnpm dev
  • In services/api run pnpm dev

Additional information can be found in the README files of the various packages.

Workspace

Namespace

Typically in a monorepo, you will never publish the packages to NPM, and because of that, the namespace you use to prefix your package names does not matter. You might as well pick a generic one that you can use in every private codebase.

At first I used @mono, and later I switched to @repo when I discovered that in the Turborepo examples. I like both, because they are equally short and clear, but I went with @repo because I expect it is more likely to become a standard.

Packages

  • common Code that can shared across both front-end and back-end environments.
  • backend Code that is shared between server environments like cloud functions.

Apps

  • web A Next.js based web application configured to use Tailwind CSS and ShadCN components.

Services

  • fns Various Firebase functions that execute on document writes, pubsub events etc. This package shows how to use [isolate-package] explicitly as part of the predeploy phase.
  • api A 2nd gen Firebase function (based on Cloud Run) serving as an API endpoint, using Express. This package shows how to use firebase-tools-with-isolate to have the isolation integrated as part of the firebase deploy command. In addition, it illustrates how to use secrets.

Deployment

I consider deployment a bit out-of-scope for this demo.

For deployment to Firebase, you will have to set up and configure an actual project, but it is not required to run this demo since by default it runs on local emulators. Additional info about the use of isolate-package (used by fns) and firestore-tools-with-isolate (used by api) can be found in the instructions for each package.

The "built packages" strategy

In a traditional monorepo setup, each package exposes its code as if it was a published NPM package. For Typescript this means the code has to be transpiled and the manifest entry points reference to the build output files. You can use Typescript tsc compiler for this, but it is likely you will want to use a bundler for the reasons explained below.

The services in this codebase use TSUP as a bundler. It is a modern, simple to use Rollup-inspired bundler for Typescript.

The advantages of using a bundler are discussed below.

Convert path aliases

If you use path aliases like ~/* or @/* to conveniently reference top-level folders from deeply nested import statements, these paths are not converted by the standard Typescript tsc compiler.

If your only target is a platform like Next.js, that uses a bundler under the hood, this is not an issue because these aliases are handled for you. But if you target other platforms like Firebase, you might have to convert them. A bundler like TSUP can do this transformation.

Write ESM without import file extensions

A bundler will allow you to output ESM-compatible code without having to adhere to the ESM import rules. ESM requires all relative imports to be explicit, appending a .js file extension for importing TS files and appending /index.js when importing from the root of a directory.

The reason you need to use .js and not .ts is because these imports, like path aliases are not converted by the Typescript compiler, and so at runtime the transpiled JS file is what is getting imported.

Because a bundler, by nature, will bundle code into one or more isolated files, those files do not use relative imports and only contain imports from node_modules, which do not require a file extension. For this reason, a bundled js file that uses import and export keywords is an ES module.

An advantage of writing your code as ESM is that you can import both ES modules and CommonJS without conversion. An application that uses CJS can not import ESM directly, because CJS imports are synchronous and ESM imports are asynchronous.

Not having to use ESM import extensions can be especially valuable if you are trying to convert a large codebase to ESM, because I have yet to find a solution that can convert existing imports. There is this ESLint plugin that you could use it in combination with the --fix flag to inject the extensions, but at the time of writing it does not understand path aliases.

Tree shaking

Some bundlers like TSUP are capable of eliminating dead code by tree-shaking the build output, so that less code remains to be deployed. Eliminating dead code is most important for client-side code that is shipped to the user, but for the backend it can also reduce cold-start times for serverless functions, although in most situations, it is probably not going to be noticeable.

The "internal packages" strategy

The internal packages strategy, as it was coined by Jared Palmer of Turborepo, removes the build step from the internal packages by linking directly to the Typescript source files in the package manifest.

There are some advantages to this approach:

  • Code and type changes can be picked up directly, removing the need for a watch task in development mode.
  • Removing the build step reduces overall complexity where you might otherwise use a bundler with configuration.
  • IDE go-to-definition, in which cmd-clicking on a reference takes you to the source location instead of the typed exports, works without the need for Typescript project references or generating d.ts.map files.

But, as always, there are also some disadvantages you should be aware of:

  • You can not publish the shared packages to NPM, as you do not expose them as Javascript.
  • If you use path aliases like ~/, you will need to make sure every package has its own unique aliases. You might not need aliases, because shared packages typically do not have a deeply nested folder structure anyway.
  • Since all source code gets compiled by the consuming application, build times can start to suffer when the codebase grows. See caveats for more info.
  • The shared package is effectively just a source folder, and as a whole it needs to be transpiled and bundled into the consuming package. This means that its dependencies must also be available in the consuming package. Next.js can do this for you with the transpilePackage setting, but this is the reason services/api includes remeda, as it is used by packages/common.

For testing and comparison, mono-ts uses the internal packages approach for @repo/common and a traditional built approach for @repo/backend. Both are compatible with isolate-package for deploying to Firebase.

Live code changes from internal packages

Traditionally in a monorepo, each package is treated similarly to a released NPM package, meaning that the code and types are resolved from the built "dist" output for each module. Adding new types and changing code in shared packages therefore requires you to rebuild these, which can be cumbersome during development.

Turborepo does not (yet) include a watch task, so Turbowatch was created to solve this issue. I haven't tried it but it looks like a neat solution. However, you might want to use the internal packages strategy instead.

Firebase

Demo Project

Throughout this repository, we use a Firebase demo project called demo-mono-ts A demo project allows you to run emulators for the different components like database without creating a Firebase projects with resources. To make this work you pass the --project flag when starting the emulator, and you need to use a name that starts with demo-.

When passing configuration to initializeApp you can use any non-empty string for the API keys as you can see in apps/web/.env.development.

Deploying

Deploying code to Firebase that uses shared packages from a monorepo comes with its own set of challenges, because the Firebase deploy pipeline requires you to upload a self-contained package that can be treated similarly to an NPM package, by installing its dependencies and executing the main entry.

This repo includes a solution based on isolate-package I wrote an article explaining what it does and why it is needed.

This demo can be run using only the emulators, but if you would like to see the deployment to Firebase working you can simply execute npx firebase deploy --project your-project-name from any of the service packages. For services/fns this will trigger a deploy using isolate-package and the standard firebase-tools, and for services/api this will invoke a deploy using the firestore-tools-with-isolate fork where both are integrated.

You might notice @google-cloud/functions-framework as a dependency in the service package even though it is not being used in code imports. It is currently required for Firebase to be able to deploy a PNPM workspace. Without it you will get an error asking you to install the dependency. I don't quite understand how the two are related, but it works.

Running Emulators

For Firebase Functions each service (api and fns) start separate emulators on port 5001 and 5002. The backend service (using the firebase-admin api) connects to emulators by setting various environment variables.

I have stored these in .env files in the respective service packages. Normally you would want to store them in a file that is not part of the repository like .env.local but by placing them in .env I prevent having to give instructions for setting them up just for running the demo.

Secrets

The api service uses a secret for DEMO_API_KEY. To make secrets work with the emulator you currently have to add the secret to .secret.local and also a .env or .env.local file. See this issue for more info. I have placed it in .env which is part of the repo, so you don't have to set anything up, but .env.local is the proper location probably because that file is not checked into git.

mono-ts's People

Contributors

0x80 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

mono-ts's Issues

Adopt TS 5.5 features

  • See if we can replace shared tsconfig with simple file with {configDir}
  • Enable isolatedDeclarations
  • See if we can get rid if type guards like isDefined

Lockfile and scripts after isolate

Love the monorepo setup, been testing it out during the week and have some questions. Not sure if this is the best place for it. If not, please suggest where I should ask :)

  1. Been testing out the mono-ts example and noticed that the pnpm-lock.yaml for services/fns contains next dependencies, even when the package.json contains no such dependencies. Tried pnpm dedupe inside the isolate file and it shrinks by quite a bit.

  2. Is there anyway to run scripts after the isolate phase when using firebase-tools-isolate? Have use-case to copy some assets that I don't want isolate to "mess" with. It works with fns example, by specifying it after the isolate step in firebase.json but I saw that you wrote that example is not a recommend way of doing it.

Getting ERR_PNPM_OUTDATED_LOCKFILE while attempting to deploy this example

Not sure if related to #11 but I did try the newest commit. But since this error seems to be different from before and I also tried the commit titled "Fix remeda import", and got the same error, I assume it's related to something else so I opted to create another issue.

I believe I should be using the same lock file that is already included and I'm using the specified version of pnpm set by corepack (8.12.1), so I'm not exactly sure why I'm getting a pnpm related error (though the newest pnpm version is 8.15.5).

I am also using a brand new project (no functions deployed) so I don't have a previously working deployment using this sample repo.

Based on the attached log, I could just find some information about some people having trouble with transitioning between pnpm 7 and 8 pnpm/pnpm#6312 but I don't think that might be the case here since I'm just using all pnpm 8 here. So I'm not exactly sure if there are any other issues to consider.

api > npx firebase deploy --debug
[2024-04-01T15:20:29.167Z] Object ".functions" in "firebase.json" has unknown property: {"additionalProperty":"isolate"}
[2024-04-01T15:20:29.168Z] Field ".functions" in "firebase.json" is possibly invalid: should be array
[2024-04-01T15:20:29.168Z] Field ".functions" in "firebase.json" is possibly invalid: should match some schema in anyOf
[2024-04-01T15:20:29.172Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[2024-04-01T15:20:29.173Z] > authorizing via signed-in user ([email protected])
[2024-04-01T15:20:29.173Z] [iam] checking project some-project-id for permissions ["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]
[2024-04-01T15:20:29.175Z] >>> [apiv2][query] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions [none]
[2024-04-01T15:20:29.176Z] >>> [apiv2][(partial)header] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:29.176Z] >>> [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions {"permissions":["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]}
[2024-04-01T15:20:29.333Z] <<< [apiv2][status] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions 200
[2024-04-01T15:20:29.334Z] <<< [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions {"permissions":["cloudfunctions.functions.create","cloudfunctions.functions.delete","cloudfunctions.functions.get","cloudfunctions.functions.list","cloudfunctions.functions.update","cloudfunctions.operations.get","firebase.projects.get"]}
[2024-04-01T15:20:29.334Z] >>> [apiv2][query] POST https://iam.googleapis.com/v1/projects/some-project-id/serviceAccounts/[email protected]:testIamPermissions [none]
[2024-04-01T15:20:29.334Z] >>> [apiv2][body] POST https://iam.googleapis.com/v1/projects/some-project-id/serviceAccounts/[email protected]:testIamPermissions {"permissions":["iam.serviceAccounts.actAs"]}
[2024-04-01T15:20:29.454Z] <<< [apiv2][status] POST https://iam.googleapis.com/v1/projects/some-project-id/serviceAccounts/[email protected]:testIamPermissions 200
[2024-04-01T15:20:29.454Z] <<< [apiv2][body] POST https://iam.googleapis.com/v1/projects/some-project-id/serviceAccounts/[email protected]:testIamPermissions {"permissions":["iam.serviceAccounts.actAs"]}

=== Deploying to 'some-project-id'...

i  deploying functions
Running command: turbo build
• Packages in scope: @repo/api
• Running build in 1 packages
• Remote caching disabled    
@repo/backend:build: cache hit (outputs already on disk), replaying logs 458f0911af1fc863
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] build C:\Users\mega\github\mono-ts\packages\backend 
@repo/backend:build: > run-p bundle type:gen
@repo/backend:build: 
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] bundle C:\Users\mega\github\mono-ts\packages\backend
@repo/backend:build: > tsup-node
@repo/backend:build: 
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] type:gen C:\Users\mega\github\mono-ts\packages\backend
@repo/backend:build: > tsc --emitDeclarationOnly
@repo/backend:build: 
@repo/backend:build: CLI Building entry: {"utils/index":"src/utils/index.ts","firebase":"src/firebase.ts"}
@repo/backend:build: CLI Using tsconfig: tsconfig.json
@repo/backend:build: CLI tsup v8.0.2
@repo/backend:build: CLI Using tsup config: C:\Users\mega\github\mono-ts\packages\backend\tsup.config.ts
@repo/backend:build: CLI Target: es2022
@repo/backend:build: ESM Build start
@repo/backend:build: ESM dist\utils\index.js     923.00 B
@repo/backend:build: ESM dist\firebase.js        822.00 B
@repo/backend:build: ESM dist\firebase.js.map    1.46 KB
@repo/backend:build: ESM dist\utils\index.js.map 1.84 KB
@repo/backend:build: ESM ⚡️ Build success in 26ms
@repo/api:build: cache hit (outputs already on disk), replaying logs d05108c11031fbdf
@repo/api:build: 
@repo/api:build: > @repo/[email protected] build C:\Users\mega\github\mono-ts\services\api
@repo/api:build: > tsup-node
@repo/api:build: 
@repo/api:build: CLI Building entry: src/index.ts
@repo/api:build: CLI Using tsconfig: tsconfig.json
@repo/api:build: CLI tsup v8.0.2
@repo/api:build: CLI Using tsup config: C:\Users\mega\github\mono-ts\services\api\tsup.config.ts
@repo/api:build: CLI Target: node18
@repo/api:build: CLI Cleaning output folder
@repo/api:build: ESM Build start
@repo/api:build: ESM dist\index.js     3.73 KB
@repo/api:build: ESM dist\index.js.map 8.42 KB
@repo/api:build: ESM ⚡️ Build success in 69ms

 Tasks:    2 successful, 2 total
Cached:    2 cached, 2 total
  Time:    296ms >>> FULL TURBO

+  functions: Finished running predeploy script. 
[2024-04-01T15:20:30.294Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id [none]
[2024-04-01T15:20:30.519Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id 200
[2024-04-01T15:20:30.519Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id {"projectId":"some-project-id","projectNumber":"587075144678","displayName":"izumo-dev","name":"projects/some-project-id","resources":{"hostingSite":"some-project-id"},"state":"ACTIVE","etag":"1_2d472ddb-a3d3-4aaa-b931-2d364c78d796"}
i  functions: preparing codebase api for deployment
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
[2024-04-01T15:20:30.521Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudfunctions.googleapis.com [none]
[2024-04-01T15:20:30.522Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudfunctions.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:30.523Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/runtimeconfig.googleapis.com [none]
[2024-04-01T15:20:30.523Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/runtimeconfig.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:30.524Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudbuild.googleapis.com [none]
[2024-04-01T15:20:30.524Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudbuild.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:30.525Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/artifactregistry.googleapis.com [none]
[2024-04-01T15:20:30.525Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/artifactregistry.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:30.776Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/artifactregistry.googleapis.com 200
[2024-04-01T15:20:30.776Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/artifactregistry.googleapis.com [omitted]
+  artifactregistry: required API artifactregistry.googleapis.com is enabled
[2024-04-01T15:20:30.784Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/runtimeconfig.googleapis.com 200
[2024-04-01T15:20:30.784Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/runtimeconfig.googleapis.com [omitted]
[2024-04-01T15:20:30.788Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudbuild.googleapis.com 200
[2024-04-01T15:20:30.788Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudbuild.googleapis.com [omitted]
+  functions: required API cloudbuild.googleapis.com is enabled
[2024-04-01T15:20:30.793Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudfunctions.googleapis.com 200
[2024-04-01T15:20:30.793Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/cloudfunctions.googleapis.com [omitted]
+  functions: required API cloudfunctions.googleapis.com is enabled
[2024-04-01T15:20:30.794Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id/adminSdkConfig [none]
[2024-04-01T15:20:31.088Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id/adminSdkConfig 200
[2024-04-01T15:20:31.088Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id/adminSdkConfig {"projectId":"some-project-id","storageBucket":"some-project-id.appspot.com"}
[2024-04-01T15:20:31.089Z] >>> [apiv2][query] GET https://runtimeconfig.googleapis.com/v1beta1/projects/some-project-id/configs [none]
[2024-04-01T15:20:31.224Z] <<< [apiv2][status] GET https://runtimeconfig.googleapis.com/v1beta1/projects/some-project-id/configs 200
[2024-04-01T15:20:31.225Z] <<< [apiv2][body] GET https://runtimeconfig.googleapis.com/v1beta1/projects/some-project-id/configs {}
[2024-04-01T15:20:31.226Z] Validating nodejs source
[2024-04-01T15:20:32.611Z] > [functions] package.json contents: {
  "name": "@repo/api",
  "version": "0.0.0",
  "type": "module",
  "main": "./dist/index.js",
  "module": "./dist/index.js",
  "files": [
    "dist",
    ".env.*"
  ],
  "scripts": {
    "type:check": "tsc --noEmit",
    "build": "tsup-node",
    "build:watch": "tsup-node --watch",
    "emulate": "firebase emulators:start --project demo-mono-ts --only functions",
    "dev": "run-p build:watch emulate",
    "lint": "eslint . --max-warnings 0",
    "deploy": "firebase deploy --project demo-mono-ts --only functions"
  },
  "license": "MIT",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.3.0",
    "@repo/backend": "workspace:*",
    "@repo/common": "workspace:*",
    "body-parser": "^1.20.2",
    "compression": "^1.7.4",
    "cors": "^2.8.5",
    "express": "^4.19.2",
    "firebase-admin": "^12.0.0",
    "firebase-functions": "^4.8.2",
    "firestore-server-utils": "1.0.0-4",
    "nocache": "^4.0.0",
    "remeda": "^1.56.0",
    "zod": "^3.22.4"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@types/body-parser": "^1.19.5",
    "@types/compression": "^1.7.5",
    "@types/cors": "^2.8.17",
    "@types/express": "^4.17.21",
    "@types/node": "^20.12.2",
    "firebase-tools-with-isolate": "13.6.4",
    "npm-run-all": "^4.1.5",
    "tsup": "^8.0.2",
    "typescript": "^5.4.3",
    "vitest": "^1.4.0"
  }
}
[2024-04-01T15:20:32.615Z] Building nodejs source
i  functions: Loading and analyzing source code for codebase api to determine what to deploy
[2024-04-01T15:20:32.616Z] Could not find functions.yaml. Must use http discovery
[2024-04-01T15:20:32.624Z] Found firebase-functions binary at 'C:\Users\mega\github\mono-ts\services\api\node_modules\.bin\firebase-functions'
Serving at port 8216

[2024-04-01T15:20:33.748Z] Got response from /__/functions.yaml {"endpoints":{"api":{"availableMemoryMb":null,"timeoutSeconds":null,"minInstances":null,"maxInstances":null,"ingressSettings":null,"concurrency":null,"serviceAccountEmail":null,"vpc":null,"platform":"gcfv2","region":["europe-west3"],"secretEnvironmentVariables":[{"key":"DEMO_API_KEY"}],"labels":{},"httpsTrigger":{},"entryPoint":"api"}},"specVersion":"v1alpha1","requiredAPIs":[],"params":[{"type":"secret","name":"DEMO_API_KEY"}]}
i  functions: Loaded environment variables from .env. 
[2024-04-01T15:20:33.769Z] >>> [apiv2][query] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY [none]
[2024-04-01T15:20:33.942Z] <<< [apiv2][status] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY 200
[2024-04-01T15:20:33.942Z] <<< [apiv2][body] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY {"name":"projects/587075144678/secrets/DEMO_API_KEY","replication":{"automatic":{}},"createTime":"2024-04-01T05:29:16.175515Z","labels":{"firebase-managed":"true"},"etag":"\"161502453f909b\""}
[2024-04-01T15:20:33.943Z] >>> [apiv2][query] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest [none]
i  functions: preparing . directory for uploading...
i  functions: Start isolating the source folder...
debug Using isolate-package version 1.13.2
debug Found tsconfig at: ./tsconfig.json
debug Workspace root resolved to C:\Users\mega\github\mono-ts
debug Isolate target package (root)/\services\api
debug Isolate output directory (root)/\services\api\isolate
[2024-04-01T15:20:34.782Z] <<< [apiv2][status] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest 200
[2024-04-01T15:20:34.782Z] <<< [apiv2][body] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest {"name":"projects/587075144678/secrets/DEMO_API_KEY/versions/1","createTime":"2024-04-01T05:29:16.523081Z","state":"ENABLED","replicationStatus":{"automatic":{}},"etag":"\"1615024544de49\""}
debug Cleaned the existing isolate output directory
debug Detected package manager pnpm 8.12.1
debug Detected pnpm packages globs: [ 'apps/*', 'packages/*', 'services/*' ]
debug Registering package ./apps\web
debug Registering package ./packages\typescript-config
debug Registering package ./packages\eslint-config
debug Registering package ./packages\common
debug Registering package ./packages\backend
debug Registering package ./services\fns
debug Registering package ./services\api
debug Using PNPM pack instead of NPM pack
debug Packed (temp)/repo-backend-0.0.0.tgz
debug Packed (temp)/repo-common-0.0.0.tgz
debug Unpacking (temp)/repo-backend-0.0.0.tgz
debug Unpacking (temp)/repo-common-0.0.0.tgz
debug Moved package files to (isolate)/\packages\common
debug Moved package files to (isolate)/\packages\backend
debug Packed (temp)/repo-api-0.0.0.tgz
info Generating PNPM lockfile...
debug Relevant importer ids: [ 'services/api', 'packages\\backend', 'packages\\common' ]
debug Setting target package importer on root
debug Pruning the lockfile
debug Created lockfile at C:\Users\mega\github\mono-ts\services\api\isolate\pnpm-lock.yaml
debug Deleting temp directory (root)/\services\api\isolate\__tmp
info Isolate completed at C:\Users\mega\github\mono-ts\services\api\isolate
i  functions: Finished isolation at C:\Users\mega\github\mono-ts\services\api\isolate
i  functions: packaged C:\Users\mega\github\mono-ts\services\api\isolate (47.26 KB) for uploading 
[2024-04-01T15:20:40.781Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v1/projects/some-project-id/locations/-/functions [none]
[2024-04-01T15:20:41.357Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v1/projects/some-project-id/locations/-/functions 200
[2024-04-01T15:20:41.357Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v1/projects/some-project-id/locations/-/functions {}
[2024-04-01T15:20:41.358Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/-/functions filter=environment%3D%22GEN_2%22
[2024-04-01T15:20:41.870Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/-/functions 200
[2024-04-01T15:20:41.870Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/-/functions {}
i  functions: ensuring required API run.googleapis.com is enabled...
i  functions: ensuring required API eventarc.googleapis.com is enabled...
i  functions: ensuring required API pubsub.googleapis.com is enabled...
i  functions: ensuring required API storage.googleapis.com is enabled...
[2024-04-01T15:20:41.873Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/run.googleapis.com [none]
[2024-04-01T15:20:41.873Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/run.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:41.874Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/eventarc.googleapis.com [none]
[2024-04-01T15:20:41.874Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/eventarc.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:41.875Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/pubsub.googleapis.com [none]
[2024-04-01T15:20:41.875Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/pubsub.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:41.876Z] >>> [apiv2][query] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/storage.googleapis.com [none]
[2024-04-01T15:20:41.876Z] >>> [apiv2][(partial)header] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/storage.googleapis.com x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:42.115Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/eventarc.googleapis.com 200
[2024-04-01T15:20:42.115Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/eventarc.googleapis.com [omitted]
+  functions: required API eventarc.googleapis.com is enabled
[2024-04-01T15:20:42.117Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/pubsub.googleapis.com 200
[2024-04-01T15:20:42.117Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/pubsub.googleapis.com [omitted]
+  functions: required API pubsub.googleapis.com is enabled
[2024-04-01T15:20:42.129Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/run.googleapis.com 200
[2024-04-01T15:20:42.129Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/run.googleapis.com [omitted]
+  functions: required API run.googleapis.com is enabled
[2024-04-01T15:20:42.141Z] <<< [apiv2][status] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/storage.googleapis.com 200
[2024-04-01T15:20:42.141Z] <<< [apiv2][body] GET https://serviceusage.googleapis.com/v1/projects/some-project-id/services/storage.googleapis.com [omitted]
+  functions: required API storage.googleapis.com is enabled
i  functions: generating the service identity for pubsub.googleapis.com...
i  functions: generating the service identity for eventarc.googleapis.com...
[2024-04-01T15:20:42.142Z] >>> [apiv2][query] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/pubsub.googleapis.com:generateServiceIdentity [none]
[2024-04-01T15:20:42.143Z] >>> [apiv2][query] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/eventarc.googleapis.com:generateServiceIdentity [none]
[2024-04-01T15:20:42.443Z] <<< [apiv2][status] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/pubsub.googleapis.com:generateServiceIdentity 200
[2024-04-01T15:20:42.443Z] <<< [apiv2][body] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/pubsub.googleapis.com:generateServiceIdentity {"name":"operations/finished.DONE_OPERATION","done":true,"response":{"@type":"type.googleapis.com/google.api.serviceusage.v1beta1.ServiceIdentity","email":"[email protected]","uniqueId":"108631385510699709457"}}
[2024-04-01T15:20:42.580Z] <<< [apiv2][status] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/eventarc.googleapis.com:generateServiceIdentity 200
[2024-04-01T15:20:42.580Z] <<< [apiv2][body] POST https://serviceusage.googleapis.com/v1beta1/projects/587075144678/services/eventarc.googleapis.com:generateServiceIdentity {"name":"operations/finished.DONE_OPERATION","done":true,"response":{"@type":"type.googleapis.com/google.api.serviceusage.v1beta1.ServiceIdentity","email":"[email protected]","uniqueId":"110202057313630454318"}}
[2024-04-01T15:20:42.581Z] >>> [apiv2][query] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest [none]
[2024-04-01T15:20:42.821Z] <<< [apiv2][status] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest 200
[2024-04-01T15:20:42.821Z] <<< [apiv2][body] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY/versions/latest {"name":"projects/587075144678/secrets/DEMO_API_KEY/versions/1","createTime":"2024-04-01T05:29:16.523081Z","state":"ENABLED","replicationStatus":{"automatic":{}},"etag":"\"1615024544de49\""}
[2024-04-01T15:20:42.822Z] Resolved secret version of DEMO_API_KEY to 1.
[2024-04-01T15:20:42.822Z] >>> [apiv2][query] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id [none]
[2024-04-01T15:20:43.023Z] <<< [apiv2][status] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id 200
[2024-04-01T15:20:43.024Z] <<< [apiv2][body] GET https://firebase.googleapis.com/v1beta1/projects/some-project-id {"projectId":"some-project-id","projectNumber":"587075144678","displayName":"izumo-dev","name":"projects/some-project-id","resources":{"hostingSite":"some-project-id"},"state":"ACTIVE","etag":"1_2d472ddb-a3d3-4aaa-b931-2d364c78d796"}
i  functions: ensuring [email protected] access to secret DEMO_API_KEY.
[2024-04-01T15:20:43.025Z] >>> [apiv2][query] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY:getIamPolicy [none]
[2024-04-01T15:20:43.323Z] <<< [apiv2][status] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY:getIamPolicy 200
[2024-04-01T15:20:43.324Z] <<< [apiv2][body] GET https://secretmanager.googleapis.com/v1/projects/some-project-id/secrets/DEMO_API_KEY:getIamPolicy {"version":1,"etag":"BwYVAk98m9A=","bindings":[{"role":"roles/secretmanager.secretAccessor","members":["serviceAccount:[email protected]"]}]}
+  functions: ensured [email protected] access to DEMO_API_KEY.
[2024-04-01T15:20:43.325Z] [functions] found 1 new HTTP functions, testing setIamPolicy permission...
[2024-04-01T15:20:43.325Z] >>> [apiv2][query] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions [none]
[2024-04-01T15:20:43.325Z] >>> [apiv2][(partial)header] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions x-goog-quota-user=projects/some-project-id
[2024-04-01T15:20:43.325Z] >>> [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions {"permissions":["cloudfunctions.functions.setIamPolicy"]}
[2024-04-01T15:20:43.461Z] <<< [apiv2][status] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions 200
[2024-04-01T15:20:43.462Z] <<< [apiv2][body] POST https://cloudresourcemanager.googleapis.com/v1/projects/some-project-id:testIamPermissions {"permissions":["cloudfunctions.functions.setIamPolicy"]}
[2024-04-01T15:20:43.462Z] [functions] found setIamPolicy permission, proceeding with deploy
[2024-04-01T15:20:43.463Z] >>> [apiv2][query] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions:generateUploadUrl [none]
[2024-04-01T15:20:44.317Z] <<< [apiv2][status] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions:generateUploadUrl 200
[2024-04-01T15:20:44.317Z] <<< [apiv2][body] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions:generateUploadUrl {"uploadUrl":"https://storage.googleapis.com/gcf-v2-uploads-587075144678-europe-west3/8cae9160-4d89-4c10-ad8b-3d06603720e4.zip?GoogleAccessId=service-587075144678@gcf-admin-robot.iam.gserviceaccount.com&Expires=1711986645&Signature=R1P5FKZmt%2FHKUosQ7VVfaY8rDV7biWJieMEfRCAZWgooQSeZNIDMfWLOUKqX3x8IbZTqyeTkV8OeE8H1ssIdcim1Xm5lPBw2Ie%2BT6LhZcDFvR3d7Kr70%2BNpSLWleFDEhejYWWFYToFQWNqGV3Pr%2FXi3PUE%2FTl5JmNqrtu6luEiknwqvai1%2BHPeZTbVPgQEY9CkNzZeHfNRoXvra1xEhsxlRDPsbAgBfThiJgR%2BJ%2Flz9wvjpKmtTz4%2B1nB5jHxQhGLeA7zsaoUpCMLMwr928SHsUIhuoPTKvagvKdc0gLJRIxxnSsWqv7GdMIJYhXfJaIvV1E%2FHEKbzPP%2Fqj1s4Phdg%3D%3D","storageSource":{"bucket":"gcf-v2-uploads-587075144678-europe-west3","object":"8cae9160-4d89-4c10-ad8b-3d06603720e4.zip"}}
[2024-04-01T15:20:44.318Z] >>> [apiv2][query] PUT https://storage.googleapis.com/gcf-v2-uploads-587075144678-europe-west3/8cae9160-4d89-4c10-ad8b-3d06603720e4.zip GoogleAccessId=service-587075144678%40gcf-admin-robot.iam.gserviceaccount.com&Expires=1711986645&Signature=R1P5FKZmt%2FHKUosQ7VVfaY8rDV7biWJieMEfRCAZWgooQSeZNIDMfWLOUKqX3x8IbZTqyeTkV8OeE8H1ssIdcim1Xm5lPBw2Ie%2BT6LhZcDFvR3d7Kr70%2BNpSLWleFDEhejYWWFYToFQWNqGV3Pr%2FXi3PUE%2FTl5JmNqrtu6luEiknwqvai1%2BHPeZTbVPgQEY9CkNzZeHfNRoXvra1xEhsxlRDPsbAgBfThiJgR%2BJ%2Flz9wvjpKmtTz4%2B1nB5jHxQhGLeA7zsaoUpCMLMwr928SHsUIhuoPTKvagvKdc0gLJRIxxnSsWqv7GdMIJYhXfJaIvV1E%2FHEKbzPP%2Fqj1s4Phdg%3D%3D
[2024-04-01T15:20:44.318Z] >>> [apiv2][body] PUT https://storage.googleapis.com/gcf-v2-uploads-587075144678-europe-west3/8cae9160-4d89-4c10-ad8b-3d06603720e4.zip [stream]
[2024-04-01T15:20:45.300Z] <<< [apiv2][status] PUT https://storage.googleapis.com/gcf-v2-uploads-587075144678-europe-west3/8cae9160-4d89-4c10-ad8b-3d06603720e4.zip 200
[2024-04-01T15:20:45.301Z] <<< [apiv2][body] PUT https://storage.googleapis.com/gcf-v2-uploads-587075144678-europe-west3/8cae9160-4d89-4c10-ad8b-3d06603720e4.zip [omitted]
+  functions: . folder uploaded successfully
i  functions: creating Node.js 20 (2nd Gen) function api:api(europe-west3)...
[2024-04-01T15:20:45.304Z] >>> [apiv2][query] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions functionId=api
[2024-04-01T15:20:45.304Z] >>> [apiv2][body] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions {"name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-uploads-587075144678-europe-west3","object":"8cae9160-4d89-4c10-ad8b-3d06603720e4.zip"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"secretEnvironmentVariables":[{"key":"DEMO_API_KEY","secret":"DEMO_API_KEY","projectId":"some-project-id","version":"1"}],"ingressSettings":null,"timeoutSeconds":null,"serviceAccountEmail":null,"availableMemory":"256Mi","minInstanceCount":null,"maxInstanceCount":null,"maxInstanceRequestConcurrency":80,"availableCpu":"1","vpcConnector":null,"vpcConnectorEgressSettings":null},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"}}
[2024-04-01T15:20:46.515Z] <<< [apiv2][status] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions 200
[2024-04-01T15:20:46.516Z] <<< [apiv2][body] POST https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/functions {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2"},"done":false}
[2024-04-01T15:20:46.517Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:20:47.249Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:20:47.249Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","state":"NOT_STARTED"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:20:47.766Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:20:47.766Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:20:48.484Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:20:48.485Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","state":"NOT_STARTED"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:20:49.499Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:20:49.500Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:20:50.214Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:20:50.215Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","message":"Build in progress","state":"IN_PROGRESS","resource":"projects/587075144678/locations/europe-west3/builds/060fabe5-e91c-4bb5-a0d6-ac5e9807178d","resourceUri":"https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:20:52.217Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:20:52.218Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:20:52.928Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:20:52.929Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","message":"Build in progress","state":"IN_PROGRESS","resource":"projects/587075144678/locations/europe-west3/builds/060fabe5-e91c-4bb5-a0d6-ac5e9807178d","resourceUri":"https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:20:56.930Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:20:56.930Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:20:57.662Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:20:57.662Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","message":"Build in progress","state":"IN_PROGRESS","resource":"projects/587075144678/locations/europe-west3/builds/060fabe5-e91c-4bb5-a0d6-ac5e9807178d","resourceUri":"https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:21:05.676Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:21:05.677Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:21:06.399Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:21:06.399Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"BUILD","message":"Build in progress","state":"IN_PROGRESS","resource":"projects/587075144678/locations/europe-west3/builds/060fabe5-e91c-4bb5-a0d6-ac5e9807178d","resourceUri":"https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678"},{"name":"SERVICE","state":"NOT_STARTED"}],"operationType":"CREATE_FUNCTION"},"done":false}
[2024-04-01T15:21:16.402Z] [create-api-europe-west3-api] Retrying task index 0
[2024-04-01T15:21:16.403Z] >>> [apiv2][query] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b [none]
[2024-04-01T15:21:17.115Z] <<< [apiv2][status] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b 200
[2024-04-01T15:21:17.115Z] <<< [apiv2][body] GET https://cloudfunctions.googleapis.com/v2/projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b {"name":"projects/some-project-id/locations/europe-west3/operations/operation-1711984847718-6150a88b587b5-070a912b-04ac934b","metadata":{"@type":"type.googleapis.com/google.cloud.functions.v2.OperationMetadata","createTime":"2024-04-01T15:20:48.178994453Z","endTime":"2024-04-01T15:21:18.704568995Z","target":"projects/some-project-id/locations/europe-west3/functions/api","verb":"create","cancelRequested":false,"apiVersion":"v2","requestResource":{"@type":"type.googleapis.com/google.cloud.functions.v2.Function","name":"projects/some-project-id/locations/europe-west3/functions/api","buildConfig":{"runtime":"nodejs20","entryPoint":"api","source":{"storageSource":{"bucket":"gcf-v2-sources-587075144678-europe-west3","object":"api/function-source.zip","generation":"1711984847866154"}},"environmentVariables":{"GOOGLE_NODE_RUN_SCRIPTS":""}},"serviceConfig":{"service":"projects/some-project-id/locations/europe-west3/services/api","timeoutSeconds":60,"environmentVariables":{"FIRESTORE_EMULATOR_HOST":"localhost:8080","FIREBASE_CONFIG":"{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}","GCLOUD_PROJECT":"some-project-id","EVENTARC_CLOUD_EVENT_SOURCE":"projects/some-project-id/locations/europe-west3/services/api","FUNCTION_TARGET":"api"},"ingressSettings":"ALLOW_ALL","serviceAccountEmail":"[email protected]","availableMemory":"256Mi","secretEnvironmentVariables":[{"key":"DEMO_API_KEY","projectId":"some-project-id","secret":"DEMO_API_KEY","version":"1"}],"maxInstanceRequestConcurrency":80,"availableCpu":"1"},"labels":{"deployment-tool":"cli-firebase","firebase-functions-codebase":"api","firebase-functions-hash":"7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"},"environment":"GEN_2"},"stages":[{"name":"ARTIFACT_REGISTRY","message":"Deleting function artifacts in Artifact Registry","state":"COMPLETE"},{"name":"SERVICE","message":"Deleting Cloud Run service","state":"COMPLETE","resource":"projects/some-project-id/locations/europe-west3/services/api"}],"operationType":"CREATE_FUNCTION"},"done":true,"error":{"code":3,"message":"Build failed with status: FAILURE and message: installing pnpm dependencies: (error ID: 8622936f):\nScope: all 3 workspace projects\n ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with \"frozen-lockfile\" because pnpm-lock.yaml is not up to date with packages/common/package.json\n\nNote that in CI environments this setting is true by default. If you still need to run install in such cases, use \"pnpm install --no-frozen-lockfile\"\n\n   
 Failure reason:\n    specifiers in the lockfile ({}) don't match specs in package.json ({\"firebase\":\"^10.10.0\",\"remeda\":\"^1.56.0\"}). For more details see the logs at https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678."}}
[2024-04-01T15:21:17.117Z] Got source token undefined for region europe-west3
Build failed with status: FAILURE and message: installing pnpm dependencies: (error ID: 8622936f):
Scope: all 3 workspace projects
 ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with packages/common/package.json

Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"

    Failure reason:
    specifiers in the lockfile ({}) don't match specs in package.json ({"firebase":"^10.10.0","remeda":"^1.56.0"}). For more details see the logs at https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678.
[2024-04-01T15:21:17.119Z] Total Function Deployment time: 31816
[2024-04-01T15:21:17.119Z] 1 Functions Deployed
[2024-04-01T15:21:17.119Z] 1 Functions Errored
[2024-04-01T15:21:17.120Z] 0 Function Deployments Aborted
[2024-04-01T15:21:17.120Z] Average Function Deployment time: 31815

Functions deploy had errors with the following functions:
        api:api(europe-west3)
[2024-04-01T15:21:17.121Z] Not printing URL for HTTPS function. Typically this means it didn't match a filter or we failed deployment
i  functions: cleaning up build files...
[2024-04-01T15:21:17.122Z] >>> [apiv2][query] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/some-project-id/locations/europe-west3/repositories/gcf-artifacts/packages/api [none]
[2024-04-01T15:21:17.123Z] >>> [apiv2][query] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list [none]
[2024-04-01T15:21:17.669Z] <<< [apiv2][status] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list 404
[2024-04-01T15:21:17.669Z] <<< [apiv2][body] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list {"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}]}
[2024-04-01T15:21:17.670Z] Failed docker command with error  HTTP Error: 404, Not Found {"name":"FirebaseError","children":[],"context":{"body":{"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}],"error":{"message":"Not Found"}},"response":{"statusCode":404}},"exit":1,"message":"HTTP Error: 404, Not Found","status":404}
[2024-04-01T15:21:17.686Z] >>> [apiv2][query] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list [none]
[2024-04-01T15:21:17.862Z] <<< [apiv2][status] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/some-project-id/locations/europe-west3/repositories/gcf-artifacts/packages/api 404
[2024-04-01T15:21:17.862Z] <<< [apiv2][body] DELETE https://artifactregistry.googleapis.com/v1beta2/projects/some-project-id/locations/europe-west3/repositories/gcf-artifacts/packages/api {"error":{"code":404,"message":"Package \"projects/some-project-id/locations/europe-west3/repositories/gcf-artifacts/packages/api\" was not found.","status":"NOT_FOUND"}}
[2024-04-01T15:21:18.249Z] <<< [apiv2][status] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list 404
[2024-04-01T15:21:18.249Z] <<< [apiv2][body] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list {"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}]}
[2024-04-01T15:21:18.250Z] Failed docker command with error  HTTP Error: 404, Not Found {"name":"FirebaseError","children":[],"context":{"body":{"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}],"error":{"message":"Not Found"}},"response":{"statusCode":404}},"exit":1,"message":"HTTP Error: 404, Not Found","status":404}
[2024-04-01T15:21:18.357Z] >>> [apiv2][query] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list [none]
[2024-04-01T15:21:18.880Z] <<< [apiv2][status] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list 404
[2024-04-01T15:21:18.880Z] <<< [apiv2][body] GET https://eu.gcr.io/v2/some-project-id/gcf/europe-west3/tags/list {"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}]}
[2024-04-01T15:21:18.880Z] Failed docker command with error  HTTP Error: 404, Not Found {"name":"FirebaseError","children":[],"context":{"body":{"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}],"error":{"message":"Not Found"}},"response":{"statusCode":404}},"exit":1,"message":"HTTP Error: 404, Not Found","status":404}
!  functions: Unhandled error cleaning up build images. This could result in a small monthly bill if not corrected. You can attempt to delete these images by redeploying or you can delete them manually at https://console.cloud.google.com/gcr/images/some-project-id/eu/gcf    
[2024-04-01T15:21:18.881Z] Functions deploy failed.
[2024-04-01T15:21:18.881Z] {
  "endpoint": {
    "id": "api",
    "project": "some-project-id",
    "region": "europe-west3",
    "entryPoint": "api",
    "platform": "gcfv2",
    "runtime": "nodejs20",
    "httpsTrigger": {},
    "labels": {
      "deployment-tool": "cli-firebase"
    },
    "secretEnvironmentVariables": [
      {
        "key": "DEMO_API_KEY",
        "secret": "DEMO_API_KEY",
        "projectId": "some-project-id",
        "version": "1"
      }
    ],
    "ingressSettings": null,
    "availableMemoryMb": null,
    "serviceAccount": null,
    "timeoutSeconds": null,
    "maxInstances": null,
    "minInstances": null,
    "concurrency": 80,
    "vpc": null,
    "environmentVariables": {
      "FIRESTORE_EMULATOR_HOST": "localhost:8080",
      "FIREBASE_CONFIG": "{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}",
      "GCLOUD_PROJECT": "some-project-id",
      "EVENTARC_CLOUD_EVENT_SOURCE": "projects/some-project-id/locations/europe-west3/services/api"
    },
    "codebase": "api",
    "cpu": 1,
    "targetedByOnly": false,
    "hash": "7104f7b4c2ad4df1ee5ccfbb499057eaa90ff1e9"
  },
  "op": "create",
  "original": {
    "name": "FirebaseError",
    "children": [],
    "exit": 1,
    "message": "Build failed with status: FAILURE and message: installing pnpm dependencies: (error ID: 8622936f):\nScope: all 3 workspace projects\n ERR_PNPM_OUTDATED_LOCKFILE  Cannot install with \"frozen-lockfile\" because pnpm-lock.yaml is not up to date with packages/common/package.json\n\nNote that in CI environments this setting is true by default. If you still need to run install in such cases, use \"pnpm install --no-frozen-lockfile\"\n\n    Failure reason:\n    specifiers in the lockfile ({}) don't match specs in package.json ({\"firebase\":\"^10.10.0\",\"remeda\":\"^1.56.0\"}). For more details see the logs at https://console.cloud.google.com/cloud-build/builds;region=europe-west3/060fabe5-e91c-4bb5-a0d6-ac5e9807178d?project=587075144678.",
    "status": 3,
    "code": 3
  }
}
[2024-04-01T15:21:18.886Z] Error: Failed to create function api in region europe-west3
    at C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:303:27
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Fabricator.createV2Function (C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:284:30)
    at async Fabricator.createEndpoint (C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:136:13)
    at async handle (C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:88:17)

Error: There was an error deploying function

Specifically this is what I get:
image

Attempting to deploy using this example seems to not work?

Hello! Thank you for the work on isolate-package and this sample repository, as it has been great for developing a monorepo for Firebase, particularly when I was using the emulators. However, I've tried deploying just the API service for this example repository using npx firebase deploy --project some-project-name and it appears to not deploy on my end. So I tried using npx firebase deploy --debug to see if I could get some more info and it seems to just point me elsewhere as shown in the snippet below:

[2024-04-01T05:33:38.805Z] Failed docker command with error  HTTP Error: 404, Not Found {"name":"FirebaseError","children":[],"context":{"body":{"errors":[{"code":"NAME_UNKNOWN","message":"Repository \"eu.gcr.io\" not found"}],"error":{"message":"Not Found"}},"response":{"statusCode":404}},"exit":1,"message":"HTTP Error: 404, Not Found","status":404}
!  functions: Unhandled error cleaning up build images. This could result in a small monthly bill if not corrected. You can attempt to delete these images by redeploying or you can delete them manually at https://console.cloud.google.com/gcr/images/some-project-id/eu/gcf
[2024-04-01T05:33:38.806Z] Functions deploy failed.
[2024-04-01T05:33:38.806Z] {
  "endpoint": {
    "id": "api",
    "project": "some-project-id",
    "region": "europe-west3",
    "entryPoint": "api",
    "platform": "gcfv2",
    "runtime": "nodejs20",
    "httpsTrigger": {},
    "labels": {
      "deployment-tool": "cli-firebase"
    },
    "secretEnvironmentVariables": [
      {
        "key": "DEMO_API_KEY",
        "secret": "DEMO_API_KEY",
        "projectId": "some-project-id",
        "version": "1"
      }
    ],
    "ingressSettings": null,
    "availableMemoryMb": null,
    "serviceAccount": null,
    "timeoutSeconds": null,
    "maxInstances": null,
    "minInstances": null,
    "concurrency": 80,
    "vpc": null,
    "environmentVariables": {
      "FIRESTORE_EMULATOR_HOST": "localhost:8080",
      "FIREBASE_CONFIG": "{\"projectId\":\"some-project-id\",\"storageBucket\":\"some-project-id.appspot.com\"}",
      "GCLOUD_PROJECT": "some-project-id",
      "EVENTARC_CLOUD_EVENT_SOURCE": "projects/some-project-id/locations/europe-west3/services/api"
    },
    "codebase": "api",
    "cpu": 1,
    "targetedByOnly": false,
    "hash": "2df6a17a2879b46efc425a28a009b953deb5eb1e"
  },
  "op": "create",
  "original": {
    "name": "FirebaseError",
    "children": [],
    "exit": 1,
    "message": "Could not create or update Cloud Run service api, Container Healthcheck failed. Revision 'api-00001-roj' is not ready and cannot serve traffic. The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable. Logs for this revision might contain more information.\n\nLogs URL: https://console.cloud.google.com/logs/viewer?project=some-project-id&resource=cloud_run_revision/service_name/api/revision_name/api-00001-roj&advancedFilter=resource.type%3D%22cloud_run_revision%22%0Aresource.labels.service_name%3D%22api%22%0Aresource.labels.revision_name%3D%22api-00001-roj%22 \nFor more troubleshooting guidance, see https://cloud.google.com/run/docs/troubleshooting#container-failed-to-start",
    "status": 3,
    "code": 3
  }
}
[2024-04-01T05:33:38.807Z] Error: Failed to create function api in region europe-west3
    at C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:303:27
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Fabricator.createV2Function (C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:284:30)
    at async Fabricator.createEndpoint (C:\Users\mega\githubmono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:136:13)
    at async handle (C:\Users\mega\github\mono-ts\node_modules\.pnpm\[email protected]\node_modules\firebase-tools-with-isolate\lib\deploy\functions\release\fabricator.js:88:17)

Error: There was an error deploying functions

So it seems that it's possible to see some logs in the logs explorer for the sample project I made for this on Firebase/GCP:

image

I'm a bit puzzled as to why this error is occurring as I figured that these imports would be figured out by following along with this solution? I'm wondering if there is anything I'm missing or any insights you might have?

Fails on Windows without using WSL

Issue Description

During the deployment of the api service using Firebase tools, the process fails with an error related to pnpm dependencies and an outdated lockfile. The error message indicates that the pnpm-lock.yaml file is not up to date with packages/common/package.json, causing the deployment to fail.

Steps to Reproduce

  1. Checkout Main Branch:

    • Switch to the main branch of the mono-ts repository.
  2. Install Dependencies:

    • Run pnpm install in the root directory.
  3. Navigate to API Service:

    • Change directory to services/api.
  4. Configure Firebase:

    • Create a Firebase project.
    • Set the project name in .firebaserc.
  5. Upgrade GCP Project:

    • Upgrade the GCP project to the BLAZE plan.
  6. Enable Secret Manager API:

    • Enable the "Secret Manager API" in the GCP console.
  7. Deploy API Service:

    • Execute the deploy task from services/api without the --project demo-mono-ts parameter.
    • Enter a secret when prompted during deployment.

Deployment Log

> firebase deploy --only functions

=== Deploying to 'my-actual-project-id'...

i  deploying functions
Running command: turbo build
• Packages in scope: @repo/api
• Running build in 1 packages
• Remote caching disabled
@repo/backend:build: cache hit, replaying logs 188a15c5f887936f
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] build C:\Users\myself\WebstormProjects\mono-ts\packages\backend
@repo/backend:build: > run-p bundle type:gen
@repo/backend:build: 
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] bundle C:\Users\myself\WebstormProjects\mono-ts\packages\backend
@repo/backend:build: > tsup-node
@repo/backend:build: 
@repo/backend:build: 
@repo/backend:build: > @repo/[email protected] type:gen C:\Users\myself\WebstormProjects\mono-ts\packages\backend
@repo/backend:build: > tsc --emitDeclarationOnly
@repo/backend:build: 
@repo/backend:build: CLI Building entry: {"utils/index":"src/utils/index.ts","firebase":"src/firebase.ts"}
@repo/backend:build: CLI Using tsconfig: tsconfig.json
@repo/backend:build: CLI tsup v8.0.2
@repo/backend:build: CLI Using tsup config: C:\Users\myself\WebstormProjects\mono-ts\packages\backend\tsup.config.ts
@repo/backend:build: CLI Target: es2022
@repo/backend:build: ESM Build start
@repo/backend:build: ESM dist\firebase.js        822.00 B
@repo/backend:build: ESM dist\utils\index.js     923.00 B
@repo/backend:build: ESM dist\firebase.js.map    1.52 KB
@repo/backend:build: ESM dist\utils\index.js.map 1.92 KB
@repo/backend:build: ESM ⚡️ Build success in 51ms
@repo/api:build: cache hit, replaying logs 02c60e416d86d2e8
@repo/api:build: 
@repo/api:build: > @repo/[email protected] build C:\Users\myself\WebstormProjects\mono-ts\services\api
@repo/api:build: > tsup-node
@repo/api:build: 
@repo/api:build: CLI Building entry: src/index.ts
@repo/api:build: CLI Using tsconfig: tsconfig.json
@repo/api:build: CLI tsup v8.0.2
@repo/api:build: CLI Using tsup config: C:\Users\myself\WebstormProjects\mono-ts\services\api\tsup.config.ts
@repo/api:build: CLI Target: node18
@repo/api:build: CLI Cleaning output folder
@repo/api:build: ESM Build start
@repo/api:build: ESM dist\index.js     3.76 KB
@repo/api:build: ESM dist\index.js.map 8.94 KB
@repo/api:build: ESM ⚡️ Build success in 67ms

 Tasks:    2 successful, 2 total
Cached:    2 cached, 2 total
  Time:    1.135s >>> FULL TURBO

+  functions: Finished running predeploy script.
i  functions: preparing codebase api for deployment
i  functions: ensuring required API cloudfunctions.googleapis.com is enabled...
i  functions: ensuring required API cloudbuild.googleapis.com is enabled...
i  artifactregistry: ensuring required API artifactregistry.googleapis.com is enabled...
+  artifactregistry: required API artifactregistry.googleapis.com is enabled
+  functions: required API cloudfunctions.googleapis.com is enabled
+  functions: required API cloudbuild.googleapis.com is enabled
i  functions: Loading and analyzing source code for codebase api to determine what to deploy
Serving at port 8864

i  functions: Loaded environment variables from .env.
? This secret will be stored in Cloud Secret Manager (https://cloud.google.com/secret-manager/pricing) as DEMO_API_KEY. Enter a value for DEMO_API_KEY: [hidden]
i  functions: preparing . directory for uploading...
i  functions: Start isolating the source folder...
debug Using isolate-package version 1.14.0
debug Found tsconfig at: ./tsconfig.json
debug Workspace root resolved to C:\Users\myself\WebstormProjects\mono-ts
debug Isolate target package (root)/\services\api
debug Isolate output directory (root)/\services\api\isolate
debug Detected package manager pnpm 9.0.4+sha256.caa915eaae9d9aefccf50ee8aeda25a2f8684d8f9d5c6e367eaf176d97c1f89e
debug Use PNPM pack instead of NPM pack
debug Detected pnpm packages globs: [ 'apps/*', 'packages/*', 'services/*' ]
debug Registering package ./apps\web
debug Registering package ./packages\typescript-config
debug Registering package ./packages\eslint-config
debug Registering package ./packages\common
debug Registering package ./packages\backend
debug Registering package ./services\fns
debug Registering package ./services\api
debug Packed (temp)/repo-backend-0.0.0.tgz
debug Packed (temp)/repo-common-0.0.0.tgz
debug Unpacking (temp)/repo-backend-0.0.0.tgz
debug Unpacking (temp)/repo-common-0.0.0.tgz
debug Moved package files to (isolate)/\packages\common
debug Moved package files to (isolate)/\packages\backend
debug Packed (temp)/repo-api-0.0.0.tgz
info Generating PNPM lockfile...
debug Relevant importer ids: [ 'services/api', 'packages\\backend', 'packages\\common' ]
debug Setting target package importer on root
debug Pruning the lockfile
debug Created lockfile at C:\Users\myself\WebstormProjects\mono-ts\services\api\isolate\pnpm-lock.yaml
debug Deleting temp directory (root)/\services\api\isolate\__tmp
info Isolate completed at C:\Users\myself\WebstormProjects\mono-ts\services\api\isolate
i  functions: Finished isolation at C:\Users\myself\WebstormProjects\mono-ts\services\api\isolate
i  functions: packaged C:\Users\myself\WebstormProjects\mono-ts\services\api\isolate (53.43 KB) for uploading
i  functions: ensuring required API run.googleapis.com is enabled...
i  functions: ensuring required API eventarc.googleapis.com is enabled...
i  functions: ensuring required API pubsub.googleapis.com is enabled...
i  functions: ensuring required API storage.googleapis.com is enabled...
+  functions: required API pubsub.googleapis.com is enabled
!  functions: missing required API run.googleapis.com. Enabling now...
+  functions: required API storage.googleapis.com is enabled
!  functions: missing required API eventarc.googleapis.com. Enabling now...
+  functions: required API run.googleapis.com is enabled
+  functions: required API eventarc.googleapis.com is enabled
i  functions: generating the service identity for pubsub.googleapis.com...
i  functions: generating the service identity for eventarc.googleapis.com...
i  functions: ensuring [email protected] access to secret DEMO_API_KEY.
+  secretmanager: Granted roles/secretmanager.secretAccessor on projects/my-actual-project-id/secrets/DEMO_API_KEY to [email protected]
+  functions: ensured [email protected] access to DEMO_API_KEY.
+  functions: . folder uploaded successfully
i  functions: creating Node.js 20 (2nd Gen) function api:api(europe-west3)...

Build failed with status: FAILURE and message: installing pnpm dependencies: (error ID: 8622936f):
Scope: all 3 workspace projects
 ERR_PNPM_OUT

DATED_LOCKFILE  Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with packages/common/package.json

Note that in CI environments this setting is true by default. If you still need to run install in such cases, use "pnpm install --no-frozen-lockfile"

    Failure reason:
    specifiers in the lockfile ({}) don't match specs in package.json ({"firebase":"^10.12.0","remeda":"^1.61.0"}). For more details see the logs at https://console.cloud.google.com/cloud-build/builds;region=europe-west3/34b9adb4-b996-415e-9d85-9584c161ce9f?project=453676369314.

Functions deploy had errors with the following functions:
        api:api(europe-west3)
i  functions: cleaning up build files...
!  functions: Unhandled error cleaning up build images. This could result in a small monthly bill if not corrected. You can attempt to delete these images by redeploying or you can delete them manually at https://console.cloud.google.com/gcr/images/my-actual-project-id/eu/gcf

Error: There was an error deploying functions
 ELIFECYCLE  Command failed with exit code 2.

Support for firebase hosting?

Hi,
So far your repo contains addresses deployment of functions (services)
What about deploying apps/web application to firebase hosting? Can that be supported as well?
Thanks

Should isolate merge dependencies?

Hey! Kudos for this repo. It helped me a ton.

I'm using the noExternal option to include everything in my final bundle but there's a problem.

Scenario A: I keep @repo/common in my package.json dependencies

Everything works but it isolate the @repo/common for nothing since everything is already in the final bundle thanks to noExternal

Scenario B: I remove the @repo/common from package.json dependencies

That way the isolate only has the final bundle and its package.json BUT it doesn't work but the @repo/common dependencies are not merged with the bundle package.json

So, for now I'll keep the @repo/common dependency in my package.json but I shouldn't have to right?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.