{"id":18829911,"url":"https://github.com/rxstack/platform-callbacks","last_synced_at":"2026-01-29T08:43:59.264Z","repository":{"id":34024361,"uuid":"160844019","full_name":"rxstack/platform-callbacks","owner":"rxstack","description":"Set of helpers for @rxstack/platform","archived":false,"fork":false,"pushed_at":"2024-10-18T12:10:47.000Z","size":631,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-08T06:48:33.180Z","etag":null,"topics":["hooks","nodejs","platform","rxstack","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rxstack.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-07T15:50:55.000Z","updated_at":"2024-10-18T12:09:30.000Z","dependencies_parsed_at":"2023-01-15T04:02:42.949Z","dependency_job_id":null,"html_url":"https://github.com/rxstack/platform-callbacks","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rxstack%2Fplatform-callbacks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rxstack%2Fplatform-callbacks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rxstack%2Fplatform-callbacks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rxstack%2Fplatform-callbacks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rxstack","download_url":"https://codeload.github.com/rxstack/platform-callbacks/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":231820075,"owners_count":18431387,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hooks","nodejs","platform","rxstack","typescript"],"created_at":"2024-11-08T01:47:00.870Z","updated_at":"2026-01-29T08:43:54.239Z","avatar_url":"https://github.com/rxstack.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RxStack Platform Callbacks\n\n[![Node.js CI](https://github.com/rxstack/platform-callbacks/actions/workflows/node.js.yml/badge.svg)](https://github.com/rxstack/platform-callbacks/actions/workflows/node.js.yml)\n[![Maintainability](https://api.codeclimate.com/v1/badges/0c6cfc515a30d1a04c48/maintainability)](https://codeclimate.com/github/rxstack/platform-callbacks/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/0c6cfc515a30d1a04c48/test_coverage)](https://codeclimate.com/github/rxstack/platform-callbacks/test_coverage)\n\n\u003e Set of helpers for [`@rxstack/platform`](https://github.com/rxstack/rxstack/tree/master/packages/platform)\n\n## Table of content\n\n- [Installation](#installation)\n- [Callbacks](#callbacks)\n    - [alter](#callbacks-alter)\n    - [rename](#callbacks-rename)\n    - [associateWithCurrentUser](#callbacks-associate-with-current-user)\n    - [queryWithCurrentUser](#callbacks-query-with-current-user)\n    - [restrictToAuthenticatedUser](#callbacks-restrict-to-authenticated-user)\n    - [restrictToAnonymousUser](#callbacks-restrict-to-anonymous-user)\n    - [restrictToOwner](#callbacks-restrict-to-owner)\n    - [restrictToRole](#callbacks-restrict-to-role)\n    - [objectExists](#callbacks-object-exists)\n    - [populate](#callbacks-populate)\n    - [queryFilter](#callbacks-query-filter)\n    - [setNow](#callbacks-set-now)\n    - [softDelete](#callbacks-soft-delete)\n    - [transform](#callbacks-transform)\n    - [validate](#callbacks-validate)\n    - [validateUnique](#callbacks-validate-unique)\n\n\n## \u003ca name=\"installation\"\u003e\u003c/a\u003e Installation\n\n```\nnpm install @rxstack/platform-callbacks --save\n```\n\n## \u003ca name=\"callbacks\"\u003e\u003c/a\u003e Callbacks\n\n\u003e **Note:** `preExecute` applies changes on `request.body` and `postExecute` on `event.getData()`\n\n### \u003ca name=\"callbacks-alter\"\u003e\u003c/a\u003e alter\n\nPick or pluck properties in data\n\nAvailable on:\n\n- `preExecute`\n- `postExecute`\n\n`Options`: \n\n- `method`: [`lodash/pick`](https://lodash.com/docs/4.17.11#pick) | [`lodash/omit`](https://lodash.com/docs/4.17.11#omit)\n- `fieldNames`: an array of field names.\n- `dataPath`: path to data (optional)\n\nExample: \n\n```typescript\n// ...\nimport {alter} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    alter('pick', ['name', 'user.fname'])\n  ],\n  onPreExecute: [\n    // ...\n    alter('omit', ['_id', 'name'])\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-rename\"\u003e\u003c/a\u003e rename\n\nRename property and removes the original one.\n\nAvailable on:\n\n- `preExecute`\n- `postExecute`\n\n`Options`: \n\n- `key`: property name to rename\n- `newKey`: new property name\n- `dataPath`: path to data (optional)\n\nExample: \n\n```typescript\n// ...\nimport {rename} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    rename('title', 'name')\n  ],\n  onPreExecute: [\n    // ...\n    rename('_id', 'id', 'user')\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-associate-with-current-user\"\u003e\u003c/a\u003e associateWithCurrentUser\n\nAdds current user identifier to `request.body`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `options: CurrentUserOptions` \n    - `idField`: user identifier property. Optional, defaults to `id`\n    - `targetField`: property where `user identifier` should be set. Optional, defaults to `userId`\n\nExample: \n\n```typescript\n// ...\nimport {associateWithCurrentUser} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    associateWithCurrentUser({idField: 'username', targetField: 'owner'})\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-query-with-current-user\"\u003e\u003c/a\u003e queryWithCurrentUser\n\nAdds current user identifier to `request.attributes.get('query')` or `request.attributes.get('criteria')`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `options: CurrentUserOptions` \n    - `idField`: user identifier property. Optional, defaults to `id`\n    - `targetField`: property where `user identifier` should be set. Optional, defaults to `userId`\n\nExample: \n\n```typescript\n// ...\nimport {queryWithCurrentUser} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    queryWithCurrentUser({idField: 'username', targetField: 'owner'})\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-restrict-to-authenticated-user\"\u003e\u003c/a\u003e restrictToAuthenticatedUser\n\nRestricts resource to authenticated user `request.token`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `fullyAuthenticated`: if user is fully authenticated (token is not refreshed) (optional)\n\nExample: \n\n```typescript\n// ...\nimport {restrictToAuthenticatedUser} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    restrictToAuthenticatedUser(false)\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-restrict-to-anonymous-user\"\u003e\u003c/a\u003e restrictToAnonymousUser\n\nRestricts resource to anonymous user `request.token`.\n\nAvailable on:\n\n- `preExecute`\n\nExample: \n\n```typescript\n// ...\nimport {restrictToAnonymousUser} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    restrictToAnonymousUser()\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-restrict-to-owner\"\u003e\u003c/a\u003e restrictToOwner\n\nRestricts resource to current user `request.token.getUser()`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `options: CurrentUserOptions` \n    - `idField`: user identifier property. Optional, defaults to `id`\n    - `targetField`: property where `user identifier` should be get. Optional, defaults to `userId`\n\nExample: \n\n```typescript\n// ...\nimport {restrictToOwner} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    restrictToOwner({idField: 'username', targetField: 'owner'})\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-restrict-to-role\"\u003e\u003c/a\u003e restrictToRole\n\nRestricts resource to current user role `request.token.getRoles()`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `role`: role to match \n\nExample: \n\n```typescript\n// ...\nimport {restrictToRole} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    restrictToRole('ROLE_ADMIN')\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-object-exists\"\u003e\u003c/a\u003e objectExists\n\nChecks if object exists in database.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `schema: ObjectExistSchema\u003cT\u003e`\n    - `service`: The type of service to fetch the record\n    - `targetField`: field in the `request.body`\n    - `inverseField`: field in the service model \n    - `method`: service method (optional),  defaults to `findOne`\n    - `criteria`: additional criteria (optional) [see here](https://github.com/rxstack/rxstack/tree/master/packages/platform#services-querying)\n    - `dataPath`: path to data (optional)\n\nExample: \n\n```typescript\n// ...\nimport {objectExists} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    objectExists({\n      service: UserService,\n      targetField: 'user',\n      inverseField: 'username',\n      method: 'findOne',\n      criteria: {id: {'$ne': 'user-2'}},\n      dataPath: 'posts'\n    })\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-populate\"\u003e\u003c/a\u003e populate\n\nJoins related records.\n\nAvailable on:\n\n- `postExecute`\n\n`Options`: \n\n- `schema: PopulateSchema\u003cT\u003e`\n    - `service`: The type of service to fetch the records\n    - `targetField`: field in the `event.getData()`\n    - `inverseField`: field in the service model \n    - `method`: service method (optional), defaults to `findMany`\n    - `nameAs`: replaces the original property name (optional)\n    - `query`: additional query (optional) [see here](https://github.com/rxstack/rxstack/tree/master/packages/platform#services-querying)\n\nExample: \n\n```typescript\n// ...\nimport {populate} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPostExecute: [\n    // ...\n    populate({\n      service: UserService,\n      targetField: 'users',\n      inverseField: 'username',\n      method: 'findMany',\n      query: {where: {enabled: {'$eq': true}}, limit: 5, skip: 0, sort: { id: -1 } },\n      nameAs: 'owners'\n    })\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-populate\"\u003e\u003c/a\u003e queryFilter\n\nFilter the query with [`@rxstack/query-filter`](https://github.com/rxstack/rxstack/tree/master/packages/query-filter).\nModifies `request.attributes.get('query')`.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `schema: QueryFilterSchema`\n\nExample: \n\n```typescript\n// ...\nimport {queryFilter} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    queryFilter(taskQuerySchema)\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-set-now\"\u003e\u003c/a\u003e setNow\n\nSet the current date-time in certain fields\n\nAvailable on:\n\n- `preExecute`\n- `postExecute`\n\n`Options`: \n\n- `fieldNames`: array of field names.\n\nExample: \n\n```typescript\n// ...\nimport {setNow} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    setNow('createdAt', 'updatedAt')\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-soft-delete\"\u003e\u003c/a\u003e softDelete\n\nFlag records as logically deleted instead of physically removing them (sets the deleted date). \nIt can be used only with [`ResurceOperations`](https://github.com/rxstack/rxstack/tree/master/packages/platform#operations)\nInternally it modifies the `request.attributes.get(query)` or checks if `deleteField` is null\n\n\u003e **Important:** make sure you add it last on remove operations because it will skip the remaining hooks.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `schema: SoftDeleteOptions`\n    - `addOnCreate`: Adds delete field with `null` value on create operations (optional), defaults to `false`\n    - `deleteField`: name of the field to set the date when the record was logically deleted (optional), defaults to `deletedAt`\n\nExample: \n\n```typescript\n// ...\nimport {softDelete} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    softDelete({\n      addOnCreate: true,\n      deleteField: 'deletedAt'\n    })\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-transform\"\u003e\u003c/a\u003e transform\n\nTransforms values from `request.body` or `event.getData()`. It uses [`class-transformer`](https://github.com/typestack/class-transformer)\n\nAvailable on:\n\n- `preExecute`\n- `postExecute`\n\n`Options`: \n\n- `type`: Target which Types are being specified.\n- `options`: [ClassTransformOptions](https://github.com/typestack/class-transformer/blob/develop/src/ClassTransformOptions.ts)\n\nExample: \n\nfirst create the model:\n\n```typescript\nimport {Expose} from 'class-transformer';\n\nexport class TaskTransformer {\n\n  @Expose({name: 'id'})\n  _id: string;\n\n  @Expose({groups: ['create']})\n  name: string;\n}\n```\n\nthen add the hook to operation:\n\n```typescript\n// ...\nimport {transform} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    transform(TaskTransformer, {groups: ['create']})\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-validate\"\u003e\u003c/a\u003e validate\n\nValidates object(s) using [class-validator](https://github.com/typestack/class-validator)\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `type`: validation schema or target which types are being specified.\n- `options`: [`ValidatorOptions`](https://github.com/typestack/class-validator/blob/master/src/validation/ValidatorOptions.ts) (optional)\n\n\nExample with type: \n\n```typescript\n// ...\nimport {validate} from '@rxstack/platform-callbacks';\nimport {IsBoolean, IsNotEmpty, Length} from 'class-validator';\n\nexport class TaskModel {\n\n  @IsNotEmpty({\n    groups: ['group1']\n  })\n  id: string;\n\n  @Length(2, 20, {\n    groups: ['group2']\n  })\n  name: string;\n\n  @IsBoolean({\n    groups: ['group1']\n  })\n  completed: boolean;\n}\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    validate(TaskModel, { groups: ['group1'] })\n  ]\n})\n```\n\n### \u003ca name=\"callbacks-validate-unique\"\u003e\u003c/a\u003e validateUnique\n\nValidates that a particular field (or fields) is (are) unique.\n\nAvailable on:\n\n- `preExecute`\n\n`Options`: \n\n- `service`: The type of service to fetch the records\n- `properties`: List of fields on which this object should be unique\n- `errorPath`: the path where the error should be mapped\n- `method`: service method (optional), defaults to `findMany`\n- `message`: error message (optional), default to `Value is not unique`\n\nExample: \n\n```typescript\n// ...\nimport {validateUnique} from '@rxstack/platform-callbacks';\n\n@Operation\u003cResourceOperationMetadata\u003cTask\u003e\u003e({\n  // ...\n  onPreExecute: [\n    // ...\n    validateUnique({\n      service: TaskService,\n      properties: ['name'],\n      errorPath: 'name',\n      method: 'findMany',\n      message: 'Property name should be unique'\n    })\n  ]\n})\n```\n\n## License\n\nLicensed under the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxstack%2Fplatform-callbacks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frxstack%2Fplatform-callbacks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frxstack%2Fplatform-callbacks/lists"}