diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 5ab0c93b9..68e0e21fa 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -2,6 +2,7 @@ on: push: branches: - main + - release-* workflow_dispatch: permissions: diff --git a/docs/contribute/Ideas/v4.md b/docs/contribute/Ideas/v4.md index 9041e6c18..5c2ae4bc4 100644 --- a/docs/contribute/Ideas/v4.md +++ b/docs/contribute/Ideas/v4.md @@ -15,6 +15,7 @@ Default services: - CryptoService - Registry - EventService +- CacheService - SessionManager - Logger? diff --git a/docs/pages/Concepts/Context.md b/docs/pages/Concepts/Context.md index eb63b8ad7..6df30ac0d 100644 --- a/docs/pages/Concepts/Context.md +++ b/docs/pages/Concepts/Context.md @@ -1,6 +1,8 @@ # Context -The Context is used to expose Session and globally all information aroudn the current operation. +The Context is used to expose Session and globally all information around the current operation. It is the execution Context, it leverages NodeJS [Asynchronous context tracking](https://nodejs.org/api/async_context.html) + +You can access the context from anywhere using the hook `useContext` from `@webda/core`. As we have the ability to execute outside of `http` context the Context is not directly linked to the `http` request. diff --git a/docs/pages/Concepts/Models/Models.md b/docs/pages/Concepts/Models/Models.md index b0e2438f5..7c9b3301c 100644 --- a/docs/pages/Concepts/Models/Models.md +++ b/docs/pages/Concepts/Models/Models.md @@ -53,6 +53,15 @@ class MyModel extends CoreModel { } ``` +An action is defined as global if it is on a static method. You can also rename the action by providing a name. + +```js title="src/mymodel.ts" +class MyModel extends CoreModel { + @Action({ name: "myAction" }) + static globalAction() {} +} +``` + ## Model schemas The schema is generated with [ts-json-schema-generator](https://github.com/vega/ts-json-schema-generator) diff --git a/docs/pages/Concepts/Services/Events.md b/docs/pages/Concepts/Services/Events.md index 250308f00..a1ea32850 100644 --- a/docs/pages/Concepts/Services/Events.md +++ b/docs/pages/Concepts/Services/Events.md @@ -1,79 +1,24 @@ # Events -The framework use the EventEmitter for events. +The framework does not use the EventEmitter for events since v4. -`emit()` this will not wait for any promise returned by listeners +We aligned on CloudEvents and its subscription system to allow easier integration with other systems. -`emitSync()` this will wait for resolution on all promises returned by listeners +To emit an event, just define the event as a class and use its `emit` method. +If you await the method then you will wait for its delivery and local listeners to be processed. -We also have a mechanism to listen asynchronously to events. They will then be posted to a Queue for them -to be consumed through a `AsyncEvent.worker()` +To listen to an event you can use the `on`. -```mermaid -sequenceDiagram - participant S as Service - participant As as AsyncEventService - participant Q as Queue - participant Aw as AsyncEventService Worker - As->>S: Bind event to a sendQueue listener - activate As - S->>As: Emit event - As->>Q: Push the event to the queue - deactivate As - Aw->>Q: Consume queue - Aw->>Aw: Call the original listener -``` - -### Webda.Init - -### Webda.Init.Services - -### Webda.Create.Services - -### Webda.NewContext - -### Webda.Request - -### Store.Save - -### Store.Saved - -### Store.Update - -### Store.Updated - -### Store.PartialUpdate - -### Store.PArtialUpdated - -### Store.Delete +Subscription must be named from your service, this allows it to be overriden by configuration to execute asynchronously. -### Store.Deleted - -### Store.Get - -### Store.Find - -### Store.Found - -### Store.WebCreate - -### Store.WebUpdate - -### Store.WebGet - -### Store.WebDelete - -### Store.Action - -### Store.Actionned - -## Runtime Events - -To implement some clients listeners we can allow listeners by uuid +``` +emit -> @Emits() +on(name: string, event: string | Subscription , callback: async () => {}) +``` -addModelListener(model: string, uuid: string) // fullUuid? -removeModelListener(model: string, uuid: string) // fullUuid? +Local -> execute within current node process +PubSub -> execute on all nodes within the cluster +Queue -> execute once by some workers -Get the current map -The Pub/Sub will then send all events for this uuid. +EventService->worker(...subscription: string) -> if Queue subscription +EventService->init() -> will sub to all PubSub/Local on startup diff --git a/docs/pages/Concepts/Stores/Stores.md b/docs/pages/Concepts/Stores/Stores.md index 9b87786a9..ed4d612d5 100644 --- a/docs/pages/Concepts/Stores/Stores.md +++ b/docs/pages/Concepts/Stores/Stores.md @@ -4,129 +4,43 @@ sidebar_position: 4 # Stores -The store services allow you to store object in a NoSQL database it handles for you mapping between objects. Objects are mapped to a model to allow security policy and schema verification. +The store services allow you to store object in a database it handles for you mapping between objects. Objects are mapped to a model to allow security policy and schema verification. -We have currently File, DynamoDB and MongoDB storage +Available stores are: -:::warning - -If you run several instances of your application, you should have a pub/sub to notify the other instances of the changes or disable cache by setting `disableCache` to `true` +- MemoryStore +- FileStore +- [DynamoDB](./DynamoDB.md) +- [MongoDB](./MongoDB.md) +- [PostgresStore](./PostgresStore.md) -::: +Stores are managing one or several models. -## Expose REST API +Example of a Store managing the model `MyModel` -Inside the configuration you can add a block for expose the store as a REST API +```mermaid -```js title="webda.config.json" -{ - ... - "expose": { - "url": "/storeurl", // By default the URL is the store name in lower case - "restrict": { - "update": true, // Prevent the creation of an object the PUT method wont be exposed - "delete": false // Allow delete for the object - } - } - ... -} ``` -The above configuration will end up creating the following routes: - -- `POST /storeurl` -- `GET /storeurl/{uuid}` -- `DELETE /storeurl/{uuid}` - -You can see that by default, once the store exposed all the methods are available unless you restrict them. - -## Configuring Mapping - -As an example we will use the Users / Idents stores used by the Authentication module. +The configuration would look like -A User has several Idents so in NoSQL we need to deduplicate a part of the Ident object inside an array inside the User object - -The following is the Idents store configuration - -```js title="webda.config.json" +```javascript title="webda.config.json" { ... - "map": { - "Users": { // Target store - "key": "user", // Property inside Ident Object - "target": "idents", // Property on the User Object - "fields": "type", // Fields from the Ident Object ( uuid is added by default ) - "cascade": true // If User object is delete then delete all the linked Idents - } + "stores": { + "mystore": { + "model": "mymodel", + } } -``` - -So if you have a user like - -```javascript -{ - ... - "uuid": "user_01" -} -``` - -Then you save a new Ident object like - -```javascript -{ ... - "uuid": "ident_01", - "user": "user_01", - "type": "Google" } ``` -Once the Ident saved, the User object will look like - -```javascript -{ - ... - "uuid": "user_01", - "idents": [{"uuid":"ident_01","type":"Google"}] - ... -} -``` - -Then if you update the field type on your Ident object the User object will reflect the change, as well as if you delete the ident object it will be removed from the User object. - -If cascade = true, then if you delete the User object, all attached Idents will be delete aswell. - -## Events - -The Stores emit events to let you implement some auto completion of the object if needed or taking any others action even deny the action by throwing an exception - -The store event looks like - -```javascript -{ - 'object': object, - 'store': this -} -``` - -Store.Save: Before saving the object -Store.Saved: After saving the object -Store.Update: Before updating the object -Store.Updated: After updating the object -Store.Delete: Before deleting the object -Store.Deleted: After deleting the object -Store.Get: When getting the object - -### Owner Policy - -POST: Add the current user in the user field of the object -PUT: Verify the current user is the user inside the user field -GET: Verify the current user is the user inside the user field, or a public=true field exists on the object -DELETE: Verify the current user is the user inside the user field +:::warning -### Void policy +If you run several instances of your application, you should have a pub/sub to notify the other instances of the changes or disable cache by setting `disableCache` to `true` -No verification, not recommended at all +::: ## Validation diff --git a/docs/pages/Deployments/Kubernetes/Kubernetes.md b/docs/pages/Deployments/Kubernetes/Kubernetes.md index 6f6fecf9f..a19ba5772 100644 --- a/docs/pages/Deployments/Kubernetes/Kubernetes.md +++ b/docs/pages/Deployments/Kubernetes/Kubernetes.md @@ -3,3 +3,8 @@ You can deploy directly to Kubernetes. The CronService is also compatible and translate the `@Cron` annotation into `CronJob` within Kubernetes. + +## Updates + +Check if resources are compatible with next version of Kubernetes. +https://github.com/kubepug/kubepug diff --git a/docs/pages/Protocols.md b/docs/pages/Protocols.md index a62b318c2..3ca1849c4 100644 --- a/docs/pages/Protocols.md +++ b/docs/pages/Protocols.md @@ -7,3 +7,29 @@ sidebar_position: 2.091 ## REST ## GraphQL + +# Internal Protocols + +StorageFinder supports a variety of protocols for different storage systems. The following is a list of supported protocols + +`gs://` - Google Cloud Storage +`s3://` - Amazon S3 +`http://` - HTTP +`https://` - HTTPS +`file://` - Local File System + +PubSub service can be used to send and receive messages. The following is a list of supported protocols + +`amqp://` - RabbitMQ +`sqs://` - Amazon SQS +`sns://` - Amazon SNS +`gcp-pubsub://` - Google Cloud PubSub + +CryptoService manage encryption and decryption of data. The following is a list of supported protocols + +`aes://` - AES +`rsa://` - RSA +`pgp://` - PGP +`jwt://` - JWT +`jwe://` - JWE +`jws://` - JWS diff --git a/package.json b/package.json index 6610fad4e..4c02e2aa4 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "prettier-plugin-organize-imports": "^3.0.0", "sinon": "^17.0.0", "ts-node": "^10.1.0", - "typescript": "~5.3.2" + "typescript": "~5.4.5" }, "author": "loopingz", "license": "MIT", diff --git a/packages/async/README.md b/packages/async/README.md index 87cfdadb3..5890c14ce 100644 --- a/packages/async/README.md +++ b/packages/async/README.md @@ -18,7 +18,19 @@ You have different types of runner available. It allows you to launch other language/binary from within your application and capure the output. +## Scheduler + +You can schedule an action to be executed at a specific time. + +```typescript +this.getService("AsyncJobService").scheduleJob( + AsyncAction.createAction("test", "echo", ["Hello World"]), + new Date(Date.now() + 1000) +); +``` + + ## Sponsors