6.3.0 • Published 6 months ago

@miaou/back v6.3.0

Weekly downloads
-
License
MIT
Repository
-
Last release
6 months ago

@miaou/back back utilities for Firebase

This library use : firebase

Install

yarn add --exact @miaou/back

Documentation

Mail

Generate Email using mjml and handlebars

Requirements

  • yarn add --dev --exact copyfiles
  • mjml plugin for intelliJ

How to

Files structure

Files must be in src folder and must be named with the following pattern {template_name}.{mjml|i18n.yml}

    ├── src
    │   ├── user
    │   │   ├── signin.mjml
    │   │   └── signin.i18n.yml

Create your signin.i18n.yml

en:
  subject: Welcome {{email}}!
  subtitle: GETTING STARTED
  title: Let's get you up and running smoothly
fr:
  subject: Bienvenue  {{email}}!
  subtitle: DÉMARRAGE
  title: Laissez-nous vous mettre en route en douceur

Create your signin.mjml

<mjml>
  <mj-head>
    <mj-attributes>
      <mj-all font-family="'Cabin', 'Helvetica', 'Arial', sans-serif"></mj-all>
      <mj-text color="#515151"></mj-text>
    </mj-attributes>
    <mj-font href="https://fonts.googleapis.com/css?family=Cabin:normal,italic,bold&display=swap" name="Cabin"></mj-font>
  </mj-head>
  <mj-body background-color="#f8f8f8">
    <mj-section background-color="#292D4D" padding-bottom="48px" padding-left="48px" padding-right="48px" padding-top="24px" padding="48px">
      <mj-column padding="0">
        <mj-text color="rgba(255,255,255,0.5)" font-size="14px" line-height="1.6" padding="0px">
          {{$t "subtitle"}}
        </mj-text>
        <mj-text color="#ffffff" font-size="38px" line-height="1.375" padding="0px">
          <strong>{{$t "title"}}</strong>
        </mj-text>
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
const { html, subject } = await generateMail({
    srcPath: path.join(__dirname, '..'),
    locale,
    templateFileName: template,
    variables,
})

Add script into package.json

Add yarn copyfiles -u 1 src/**/*.mjml src/**/*.i18n.yml lib/ before to build to push your mjml files to your build folder

// package.json
{
  "scripts": {
    "build": "yarn copyfiles -u 1 src/**/*.mjml src/**/*.i18n.yml lib/ && tsc",
    ...
  },
  ...
}

Firestore

Backup for firestore

Requirements

You must set the right for the default app engine service account.

gcloud auth login
gcloud config set project PROJECT_ID
gcloud projects add-iam-policy-binding PROJECT_ID \
    --member serviceAccount:PROJECT_ID@appspot.gserviceaccount.com \
    --role roles/datastore.importExportAdmin
gsutil iam ch serviceAccount:PROJECT_ID@appspot.gserviceaccount.com:admin \
    gs://PROJECT_ID.appspot.com

Usage for backup

You could configure your backup as you want. You can set folderName and expiration time with your preferences

// index.ts
import {getStorage} from 'firebase-admin/storage'
import {backup} from '@miaou/back/lib/firestore'
import {Day} from "@miaou/types";

const app = initializeApp()
const storage = getStorage(app)

export const myBackup = backup(
    pubsub.schedule('every 24 hours').timeZone('Europe/Paris'),
    storage.bucket(),
    {folderName: 'backup', expirationIn: 2 as Day, dryRun: process.env.ENVIRONMENT !== 'production'})

Usage for restore

This example is for restore backup when folder name is backup. If you have another folder name you can replace it with yours

gcloud firestore import gs://PROJECT_ID.appspot.com/backup/YYYY-MM-DD

Fireway

You must name your file with the following pattern v{version_number}-{file_name}.migration.ts.

  • v001-orders-validated.migration.ts
  • v002-deleted-commands.migration.ts
  • v003-users.migration.ts
// v001-orders.migration.ts
import {BigBatch} from '@qualdesk/firestore-big-batch'

const database = getFirestore()

export const migrate = async () => {
    const batch = new BigBatch({firestore: database})
    const db = database.collection('order')

    Object.values(inventory).forEach((inventoryProduct) => {
        const ref = db.doc(inventoryProduct.id)
        batch.set(ref, {
            id: inventoryProduct.id,
            productId: inventoryProduct.productId,
            quantity: inventoryProduct.quantity,
        })
    })

    await batch.commit()
}
import {region} from 'firebase-functions'
import {getFirestore} from 'firebase-admin/firestore'
// Do not forget to call your function export * as system from './infra/spi/migration' in your index.ts
export const migrate = migrateFirestore(
    region('europe-west1'),
    getFirestore(), { migrationFolderPath: __dirname })

Best practices

Do not import functions or types from other package/folder (expect firebase packages). Your migration code should be isolated.

Functions

Middleware

const sentryInstance = Sentry.init({
    dsn: 'https://...',
    tracesSampleRate: 1.0,
});
const isProduction = process.env.ENVIRONMENT === 'production'
const isAdmin = (id: UserId) => Promise.resolve(true)

export const publicOnCall = <T extends (...args: any) => any>() =>
    typedOnCallWithMiddlewares<T>([
        sentry(sentryInstance),
        appCheck(isProduction),
        dateSerializer
    ])

export const authenticatedOnCall = <T extends (...args: any) => any>() =>
    typedOnCallWithMiddlewares<T>([
        sentry(sentryInstance),
        appCheck(isProduction),
        authenticated,
        dateSerializer
    ])

export const adminOnCall = <T extends (...args: any) => any>() =>
    typedOnCallWithMiddlewares<T>([
        sentry(sentryInstance),
        appCheck(isProduction),
        admin(isAdmin),
        dateSerializer
    ])
export type LastNewsQuery = (locale: Locale) => Promise<New[]>

export const lastNews = authenticatedOnCall<LastNewsQuery>()((locale) =>
    findAllNews(locale, 3)
)

Testing

import {firestoreTest, testableHttp} from '@miaou/back'
import 'chai/register-should.js'

// my-test.int.test.ts
describe('My test ', () => {
    it('Is order pending', async () => {
        // Given
        const db = firestoreTest()
        const isOrderPending = testableHttp<OrderCommand>('app-is-order-pending', 'tibo')
        await saveOrder(db)<Order>({userId: 'tibo' as UserId})

        // When
        const {data} = await orderCommand('XXXX-XXXX' as OrderId)

        // Then
        data.should.be.false
    })
})

Triggers

Middleware

const sentryInstance = Sentry.init({
    dsn: 'https://...',
    tracesSampleRate: 1.0,
});

export const onWrite = typedOnWriteTriggerWithMiddlewares([
    sentry(sentryInstance),
    dateSerializer,
])

export const onUpdate = typedOnUpdateTriggerWithMiddlewares([
    sentry(sentryInstance),
    dateSerializer,
])

export const onDelete = typedOnDeleteTriggerWithMiddlewares([
    sentry(sentryInstance),
    dateSerializer,
])

export const onCreate = typedOnCreateTriggerWithMiddlewares([
    sentry(sentryInstance),
    dateSerializer,
])
export const onOrderWrite = onWrite<Order>(
    'orders/{oderId}',
    async (orderChange) => {
        const beforeOrder = orderChange.before.data()
        const afterOrder = orderChange.after.data()

        // Delete
        if (!afterOrder && beforeOrder) {
            await deleteOrderView(database)(beforeOrder.id)
            return
        }

        // Create and Update
        if (afterOrder) {
            const order = await getOrder(afterOrder.id)
            const user = await getUser(afterOrder.userId)
            const licence = await getLicence(order.licenceId)
            const transaction = await getTransaction(order.transactionId)
            await saveOrderView(database)({
                ...order,
                user,
                licence,
                transaction,
            })
        }
    }
)

Development

How to use

yarn install

Test

You can use yarn link to debug the module

Release commit semantic

The release is automated by release-semantic plugin. When merge to master:

  • Generate tag version
  • Automate library versioning based on commit history
  • Generate changelog based on commit history
<type>(<scope>): <short summary>
  │       │             │
  │       │             └─⫸ Summary in present tense. Not capitalized. No period at the end.
  │       │
  │       └─⫸ Commit Scope: animations|bazel|benchpress|common|compiler|compiler-cli|core|ect.
  │
  └─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
Usage
fix: testing patch releases
feat: testing minor releases
feat: testing major releases

BREAKING CHANGE: This is a breaking change.
6.1.0

7 months ago

6.3.0

6 months ago

6.1.1

6 months ago

5.0.1

10 months ago

5.0.0

10 months ago

6.0.1

10 months ago

6.0.0

10 months ago

6.2.0

6 months ago

6.0.2

10 months ago

3.6.7

1 year ago

4.0.1

12 months ago

4.0.0

12 months ago

4.0.3

11 months ago

4.0.2

11 months ago

3.6.6

1 year ago

3.6.5

1 year ago

3.6.4

1 year ago

3.6.3

1 year ago

3.4.0

1 year ago

3.6.2

1 year ago

3.6.1

1 year ago

3.4.3

1 year ago

3.6.0

1 year ago

3.4.2

1 year ago

3.5.0

1 year ago

3.4.1

1 year ago

3.3.2

1 year ago

3.3.1

1 year ago

3.3.0

1 year ago

3.1.2

1 year ago

3.2.0

1 year ago

3.1.1

1 year ago

3.1.0

1 year ago

3.0.1

1 year ago

3.0.0

1 year ago

2.1.6

1 year ago

2.1.8

1 year ago

2.1.7

1 year ago

2.1.5

2 years ago

2.1.4

2 years ago

2.1.3

2 years ago

2.1.2

2 years ago

2.1.1

2 years ago

2.1.0

2 years ago

2.0.1

2 years ago

2.0.0

2 years ago

1.1.1

2 years ago

1.1.0

2 years ago

1.0.0

2 years ago