{"id":38043253,"url":"https://github.com/agiledigital/idm-ts-types","last_synced_at":"2026-01-16T19:56:03.906Z","repository":{"id":35021990,"uuid":"197519569","full_name":"agiledigital/idm-ts-types","owner":"agiledigital","description":"ForgeRock IDM TypeScript Types","archived":false,"fork":false,"pushed_at":"2025-10-23T06:19:54.000Z","size":3400,"stargazers_count":11,"open_issues_count":12,"forks_count":4,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-10-23T08:29:26.508Z","etag":null,"topics":["forgerock","forgerock-community","idm","openidm","typescript","typescript-types"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agiledigital.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-07-18T05:45:39.000Z","updated_at":"2025-10-23T06:19:19.000Z","dependencies_parsed_at":"2023-12-15T03:40:20.450Z","dependency_job_id":"8916eff2-63ec-40ba-ac37-db904e15e8cc","html_url":"https://github.com/agiledigital/idm-ts-types","commit_stats":{"total_commits":112,"total_committers":7,"mean_commits":16.0,"dds":0.3660714285714286,"last_synced_commit":"b14e87ef89dcd16054e5cb6c1d0a8c3e19f4efec"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"purl":"pkg:github/agiledigital/idm-ts-types","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledigital%2Fidm-ts-types","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledigital%2Fidm-ts-types/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledigital%2Fidm-ts-types/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledigital%2Fidm-ts-types/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agiledigital","download_url":"https://codeload.github.com/agiledigital/idm-ts-types/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledigital%2Fidm-ts-types/sbom","scorecard":{"id":170543,"data":{"date":"2025-08-11","repo":{"name":"github.com/agiledigital/idm-ts-types","commit":"85ede0d7a90d3de31fe7395b25bac27fd177ed8d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":5,"reason":"Found 4/7 approved changesets -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/agiledigital/idm-ts-types/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/agiledigital/idm-ts-types/release.yml/master?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 28 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"34 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-2h3h-q99f-3fhc","Warn: Project is vulnerable to: GHSA-gmw6-94gg-2rc2","Warn: Project is vulnerable to: GHSA-h5c3-5r3r-rr8q","Warn: Project is vulnerable to: GHSA-rmvr-2pp2-xj38","Warn: Project is vulnerable to: GHSA-xx4v-prfh-6cgc","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-rc47-6667-2j5j","Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22","Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-hj9c-8jmm-8c52","Warn: Project is vulnerable to: GHSA-x77j-w7wf-fjmw","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-x2pg-mjhr-2m5x","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-38fc-wpqx-33j7","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-16T16:19:44.736Z","repository_id":35021990,"created_at":"2025-08-16T16:19:44.736Z","updated_at":"2025-08-16T16:19:44.736Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28482136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["forgerock","forgerock-community","idm","openidm","typescript","typescript-types"],"created_at":"2026-01-16T19:56:02.194Z","updated_at":"2026-01-16T19:56:03.901Z","avatar_url":"https://github.com/agiledigital.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ForgeRock IDM TypeScript Types \u003c!-- omit in toc --\u003e\n[![npm version](https://img.shields.io/npm/v/@agiledigital/idm-ts-types.svg?style=flat)](https://www.npmjs.com/package/@agiledigital/idm-ts-types)\n[![GitHub License](https://img.shields.io/github/license/agiledigital/idm-ts-types.svg)](https://github.com/agiledigital/idm-ts-types/blob/master/LICENSE)\n[![Release](https://github.com/agiledigital/idm-ts-types/actions/workflows/release.yml/badge.svg)](https://github.com/agiledigital/idm-ts-types/actions/workflows/release.yml)\n[![type-coverage](https://img.shields.io/badge/dynamic/json.svg?label=type-coverage\u0026prefix=%E2%89%A5\u0026suffix=%\u0026query=$.typeCoverage.atLeast\u0026uri=https%3A%2F%2Fraw.githubusercontent.com%2Fagiledigital%2Fidm-ts-types%2Fmaster%2Fpackage.json)](https://github.com/plantain-00/type-coverage)\n[![Known Vulnerabilities](https://snyk.io/test/github/agiledigital/idm-ts-types/badge.svg?targetFile=package.json)](https://snyk.io/test/github/agiledigital/idm-ts-types?targetFile=package.json)\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)\n\n* TypeScript Support – Write your IDM JavaScript code in TypeScript which has modern language features while still being compatible with Rhino, the JavaScript engine that IDM uses.\n* Type Safety – We've put together some TypeScript types that wrap the IDM API to ensure that all your calls to the API are type safe, plus you get the added benefit of getting type-ahead assistance from your IDE.\n* Managed Object and Connector Type Generation – We've built a parser that can generate TypeScript types from your Managed Object and Connector types, this means that you can use your Managed Object or Connector types directly in TypeScript which enables IDE type-ahead assistance and type safety.\n\n![](assets/animations/wrapper-overview.gif)\n\n**Table of Contents**\n\n- [Features](#features)\n  - [TypeScript Type Code Generation](#typescript-type-code-generation)\n    - [Supported Scenarios](#supported-scenarios)\n    - [Complex Objects](#complex-objects)\n    - [Relationships](#relationships)\n      - [Handling Missing Relationship Types](#handling-missing-relationship-types)\n      - [Relationship Limitations](#relationship-limitations)\n  - [Type-safe Wrapper Functions](#type-safe-wrapper-functions)\n  - [Query Filter DSL](#query-filter-dsl)\n    - [Query Filter Functions](#query-filter-functions)\n      - [Standard Built-in Equivalent Functions](#standard-built-in-equivalent-functions)\n    - [Additional Query Helper Functions](#additional-query-helper-functions)\n  - [Type safe Patches](#type-safe-patches)\n  - [Automatic type narrowing](#automatic-type-narrowing)\n    - [Field Name Limitations](#field-name-limitations)\n  - [ForgeRock API Documentation](#forgerock-api-documentation)\n- [Getting Started](#getting-started)\n- [Configuration](#configuration)\n# Features\n\n## TypeScript Type Code Generation\n\nThe foundational feature is the TypeScript type code generation, all the other features rely on the generated types to function correctly.\n\nThe [gen-idm-ts-types.js](bin/gen-idm-ts-types.js) script parses the Managed Object's (`managed.json`) and connector files (`provisioner.openicf-*.json`), and then generates the Typescript types.\n\n\nA snippet of a simple `managed.json` file:\n```json\n{\n    \"$schema\" : \"http://forgerock.org/json-schema#\",\n    \"type\" : \"object\",\n    \"title\" : \"User\",\n    \"icon\" : \"fa-user\",\n    \"properties\" : {\n        \"_id\" : {\n            \"description\" : \"User ID\",\n            \"type\" : \"string\"\n        },\n        \"userName\" : {\n            \"title\" : \"Username\",\n            \"description\" : \"Username\",\n            \"type\" : \"string\"\n        },\n        \"password\" : {\n            \"title\" : \"Password\",\n            \"description\" : \"Password\",\n            \"type\" : \"string\"\n        },\n        \"givenName\" : {\n            \"title\" : \"First Name\",\n            \"description\" : \"First Name\",\n            \"type\" : \"string\",\n            \"searchable\" : true,\n            \"userEditable\" : true,\n            \"usageDescription\" : null,\n            \"isPersonal\" : true\n        }\n    }\n}\n```\n\nAnd a portion of the resulting Typescript type:\n\n```ts\nexport type ManagedUserDefaults = {\n  _tag?: \"managed/user\";\n\n  /**\n   * User ID\n   */\n  _id?: string;\n\n  /**\n   * Username\n   */\n  userName: string;\n\n  /**\n   * Password\n   */\n  password?: string;\n\n  /**\n   * First Name\n   */\n  givenName: string;\n}\n```\n\n### Supported Scenarios\n\nCode generation supports the following scenarios:\n\n| Scenario | Notes |\n| -------- | ----- |\n| Basic types | `string`, `number`/`integer`, `boolean`, `object`, `array` |\n| [Complex Objects](#complex-objects) | Objects that have defined properties, are generated as separate sub-types, and have unlimited levels of nesting, more info [below](#complex-objects). |\n| [Relationships](#relationships) | Fields that are [relationships](#relationships) simply use the target relationship as the type wrapped in a `ReferenceType`. It gracefully degrades when it can't find the target type to the `Record` type, this usually happens when referencing `internal` types which are not present in `managed.json`. |\n| Nullable fields | Fields marked as _nullable_ in the schema are [unioned](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) with `null`, e.g. `string \\| null`. |\n| Return by default fields | A managed object type is composed of two separate objects, _default_ fields and _non-default_ fields. Unless overridden in the managed object schema, basic types are _return by default_, but relationships are not _return by default_. When using [Type-safe wrapper functions](#type-safe-wrapper-functions) if fields are not specified when reading an object, the type is narrowed to the _default_ fields only.\n| Required fields | If the field is not marked as required then the typescript field name has a `?` appended, which makes it optional. |\n| Title and Description fields | The description and title fields end up as comments on the generated fields | \n\n\n### Complex Objects\n\nComplex Types are also supported, consented mappings is a good example.\n\n```json\n\"consentedMappings\" : {\n    \"title\" : \"Consented Mappings\",\n    \"description\" : \"Consented Mappings\",\n    \"type\" : \"array\",\n    \"items\" : {\n        \"type\" : \"array\",\n        \"title\" : \"Consented Mappings Items\",\n        \"items\" : {\n            \"type\" : \"object\",\n            \"title\" : \"Consented Mappings Item\",\n            \"properties\" : {\n                \"mapping\" : {\n                    \"title\" : \"Mapping\",\n                    \"description\" : \"Mapping\",\n                    \"type\" : \"string\",\n                },\n                \"consentDate\" : {\n                    \"title\" : \"Consent Date\",\n                    \"description\" : \"Consent Date\",\n                    \"type\" : \"string\",\n                }\n            },\n            \"order\" : [\n                \"mapping\",\n                \"consentDate\"\n            ],\n            \"required\" : [\n                \"mapping\",\n                \"consentDate\"\n            ]\n        }\n    },\n    \"returnByDefault\" : false,\n    \"isVirtual\" : false\n}\n```\n\nWhich results in the following Typescript types:\n\n```ts\n/**\n * user Managed Object Non Default fields\n *\n * These fields are only returned when explicitly mentioned or in the relationship case '*_ref' is used.\n */\nexport type ManagedUserNonDefaults = {\n...\n /**\n   * Consented Mappings\n   */\n  consentedMappings?: SubManagedUserConsentedMappings[];\n...\n}\n\n/**\n * user Managed Object\n */\nexport type ManagedUser = ManagedUserDefaults \u0026 ManagedUserNonDefaults;\n\n/**\n * user/consentedMappings Sub Type of {@link ManagedUser}\n */\nexport type SubManagedUserConsentedMappings = {\n  // tslint:disable-next-line: no-duplicate-string\n  _tag?: \"managed/user/consentedMappings\";\n\n  /**\n   * Mapping\n   */\n  mapping: string;\n\n  /**\n   * Consent Date\n   */\n  consentDate: string;\n};\n...\n\n```\n\nSo when used in an example you can simply navigate into the object like this:\n\n![](assets/images/sub-types.png)\n\n### Relationships\n\nFields that are [relationships](#relationships) simply use the target relationship as the type wrapped in a `ReferenceType`. It gracefully degrades to the `Record` type when it can't find the target type, this usually happens when referencing `internal` types which are not present in `managed.json`.\n\nThe code generation also understands relationships, and it uses the target relationship as the type wrapped in a generic `ReferenceType\u003cT\u003e`, for example `ReferenceType\u003cManagedUser\u003e`. \n\nSee the manager relationship which is a self-reference back to `managed/user`.\n\n```json\n\"manager\" : {\n    \"type\" : \"relationship\",\n    \"reversePropertyName\" : \"reports\",\n    \"description\" : \"Manager\",\n    \"title\" : \"Manager\",\n    \"resourceCollection\" : [\n        {\n            \"path\" : \"managed/user\",\n            \"label\" : \"User\",\n            \"query\" : {\n                \"queryFilter\" : \"true\",\n                \"fields\" : [\n                    \"userName\",\n                    \"givenName\",\n                    \"sn\"\n                ]\n            }\n        }\n    ],\n    \"userEditable\" : false\n},\n\n```\n\nWhich ends up with generated code such as:\n\n```ts\nexport type ManagedUserNonDefaults = {\n  /**\n   * Manager\n   */\n  manager?: ReferenceType\u003cManagedUser\u003e;\n}\n```\n\n#### Handling Missing Relationship Types\n\nSince IDM 7 the `authzRoles` relationship in _managed user_ only refers to `internal/role`, which is not defined in `managed.json`, so the code generation will not find it and will gracefully degrade to using either `Record\u003cstring, any\u003e` or `Record\u003cstring, unknown\u003e` depending on the [configuration](#configuration).\n\n#### Relationship Limitations\n\nCurrently, user customisable relationship fields that are part of `_refProperties` do __not__ have their types automatically generated. For example `roles` has this `_refProperties`:\n\n```json\n\"_refProperties\" : {\n    \"description\" : \"Supports metadata within the relationship\",\n    \"type\" : \"object\",\n    \"title\" : \"Provisioning Roles Items _refProperties\",\n    \"properties\" : {\n        \"_id\" : {\n            \"description\" : \"_refProperties object ID\",\n            \"type\" : \"string\"\n        },\n        \"_grantType\" : {\n            \"description\" : \"Grant Type\",\n            \"type\" : \"string\",\n            \"label\" : \"Grant Type\"\n        }\n    }\n}\n```\n\nWhich defines `_grantType`, but the code generation won't create a type with `_grantType` in it. Perhaps in the future this scenario will be supported if there is interest.\n\nAdditionally, when using relationships and specifying which fields should be returned isn't supported when using [automatic type narrowing](#automatic-type-narrowing) as the type narrowing doesn't support forward slashes (eg `manager/givenName`), more information is at [field name limitations](#field-name-limitations).\n\n## Type-safe Wrapper Functions\n\nDuring code generation an additional object called `idm` is generated. The `idm` object is an extension of the built-in `openidm` object, but with wrappers added for all `managed` objects and connectors (`system`) objects.\n\nThese wrapper functions are where the power of the types really shines. As seen in the animation below, VS Code is able to auto-complete managed objects and connectors, as well as showing the fields available including any description/title. \n\n![](assets/animations/wrapper-overview.gif)\n\nThis is an example of a snippet from the bottom of the generated types where the wrapper functions are stored.\n\n```ts\nexport const idm = {\n  ...openidm,\n  managed: {\n    assignment: idmObject\u003cManagedAssignment, ManagedAssignmentDefaults\u003e(\"managed/assignment\"),\n    role: idmObject\u003cManagedRole, ManagedRoleDefaults\u003e(\"managed/role\"),\n    user: idmObject\u003cManagedUser, ManagedUserDefaults\u003e(\"managed/user\")\n  },\n  system: {\n    scimAccount: idmObject\u003cSystemScimAccount, SystemScimAccount\u003e(\"system/scim/account\"),\n    scimGroup: idmObject\u003cSystemScimGroup, SystemScimGroup\u003e(\"system/scim/group\")\n  }\n};\n```\n\nWhen navigating through object type, e.g. `user`, `role`, etc. The same core functions (`create`/`update`/`patch`/`delete`/`query`) are available, with a few key differences:\n\n1. The name of the type is not required, as this is defined as part of the function call context. For example, using `openidm` reading a managed user identifier of `abc123` looks like:\n      ```ts\n      openidm.read(\"managed/user/abc123\")\n      ```\n    Whereas with the wrapper it is instead:\n\n      ```ts\n      idm.managed.user(\"abc123\")\n      ```\n    In addition to general code completion assistance it also means if the managed user object is deleted or renamed then the code no longer compiles, giving your code extra integrity.\n\n2. The return type of the function is the actual object type instead of a generic result type, or query response type. This also makes for robust code, as if a particular property doesn't exist then the code won't compile, for example, using the regular function typo's won't be detected:\n      ```ts\n      const user = openidm.read(\"managed/user/abc123\")\n      // givenName spelt wrong, compiles fine, but breaks at runtime\n      user.givonName\n      ```\n    Whereas with the wrapper it is instead:\n\n      ```ts\n      const user = idm.managed.user(\"abc123\")\n      // Will fail to compile\n      user.givonName\n      ```\n3. [Automatic type narrowing](#automatic-type-narrowing) is a really useful feature where you specify which fields you want back, and the resulting Typescript type knows that only those types are available. More details on this [below](#automatic-type-narrowing).\n4. [Type safe query filter DSL](#query-filter-dsl) generates the `_queryFilter` in a type safe way, which prevents query syntax errors from being possible, as well as making it easier to build complex queries while still being readable. More on this [below](#query-filter-dsl).\n5. The functions are overloaded with three variations which handle the fields in the returned object in different ways:\n   1. A version that leverages the [type narrowing](#automatic-type-narrowing) and returns a narrowed type.\n   2. A version that uses \"unchecked fields\" due to [type narrowing field name limitations](#field-name-limitations) which returns a type that has all possible fields.\n   3. A version that where no fields are specified so only the \"return by default\" fields are available in the returned type.\n\n\nThere is one additional function that is not present in the `openidm` function called `relationship`. This is a convenience function that can build a relationship reference in a type safe manner.\n\nFor example instead of having to manually write:\n\n```javascript\nuser.manager = {\n  \"_ref\": \"managed/user/babs\"\n}\n```\n   \nYou would instead write:\n\n```ts\nuser.manager = idm.managed.user.relationship(\"babs\")\n```\n\n## Query Filter DSL\n\nThe query filter DSL is very powerful construct that allows building a query in a type safe manner. For example if field is deleted from your managed object and a query filter is referencing that field, normally you wouldn't notice it until run time. However, using the query filter DSL the query will no longer compile, saving you from bugs creeping into production unnoticed.\n\nOther benefits are field name completion and value type checking when writing queries. For example if you have a field called `numLoginFailures` that is of type `number`, it will ensure that when using the field in the query is a `number` and won't let you use a `string` by mistake.\n\nThe following animation shows how to write a query using code completion as well as showcasing the `oneOf` function which is a shortcut way to field is one of multiple different values (like the SQL IN operator):\n\n![](assets/animations/query-filter.gif)\n\n### Query Filter Functions\n\n#### Standard Built-in Equivalent Functions\n\n| Operator Name | Function Name | Example | Query Filter Equivalent |\n| --- | --- | --- | --- |\n| Equals | `equals` | `equals(\"accountStatus\", \"active\")` | `/accountStatus eq \"active\"` |\n| Greater | `greater` | `greater(\"loginFailures\", 5)` | `/loginFailures gt 5` |\n| Greater or Equal | `greaterOrEqual` | `greaterOrEqual(\"loginFailures\", 6)` | `/loginFailures ge 6` |\n| Less | `less` | `less(\"loginFailures\", 1)` | `/loginFailures lt 1` |\n| Less or Equal | `lessOrEqual` | `lessOrEqual(\"loginFailures\", 0)` | `/loginFailures le 0` |\n| Contains | `contains` | `contains(\"mail\", \"gmail\")` | `/mail co \"gmail\"` |\n| Starts With | `startsWith` | `startsWith(\"mail\", \"john@\")` | `/mail sw \"john@\"` |\n| And | `and` | `and(equals(\"givenName\", \"John\"), equals(\"sn\", \"Citizen\"))` | `(/givenName eq \"John\" and /sn eq \"Citizen\")` |\n| Or | `or` | `or(equals(\"givenName\", \"John\"), equals(\"givenName\", \"Mary\"))` | `(/givenName eq \"John\" or /givenName eq \"Mary\")` |\n| Not | `not` | `not(presence(\"mail\"))` | `!(/mail pr)` |\n| Presence | `presence` | `presence(\"mail\")` | `/mail pr` |\n| True | `true` | `trueVal` | `trueVal()` |\n| False | `false` | `falseVal` | `falseVal()` |\n\n### Additional Query Helper Functions\n\n**`allOf`**\n\nThe `allOf` function combines multiple filters returning true if all are true, i.e. it `and`'s all the filters together.\n\nFor example, you can write:\n\n```ts\nallOf(\n    equals(\"accountStatus\", \"active\"),\n    equals(\"givenName\", \"John\"),\n    equals(\"sn\", \"Citizen\")\n)\n```\n\nWhich is equivalent to:\n\n```\n((/accountStatus eq \"active\" and /givenName eq \"John\") and /sn eq \"Citizen\")\n```\n\n**`anyOf`**\n\nThe `anyOf` function combines multiple filters returning true if any are true, i.e. it `or`'s all the filters together.\n\n```ts\nanyOf(\n    equals(\"givenName\", \"John\"),\n    equals(\"sn\", \"John\"),\n    contains(\"mail\", \"john\")\n)\n```\n\nWhich is equivalent to:\n\n```\n((/givenName eq \"John or /sn eq \"John\") or /mail co \"john\")\n\n```\n\n**`oneOf`**\n\nThe `oneOf` function is essentially SQL's `IN` operator. Given a field and a collection of values this returns `true` if any are `true`.\n\n```ts\noneOf(\"givenName\", \"John\", \"Mary\", \"Jane\")\n```\n\nWhich is equivalent to:\n\n```\n((/givenName eq \"John\" or /givenName eq \"Mary\") or /givenName eq \"Jane\")\n```\n\n\n## Type safe Patches\n\nThere is also support for type safe patches. It understands which patch operations require which properties as well as what fields are available for a given object type.\n\nThe following animation shows how type safe patch support works:\n\n![](assets/animations/patch-support.gif)\n\nThe type safe patches have an almost identical syntax to the `openidm` function equivalent, with the main exception that the field name is type checked.\n\n```ts\nidm.managed.role.patch(role._id, null, [\n  {\n    \"operation\":\"replace\",\n    \"field\":\"givenName\",\n    \"value\": \"Babs\"\n  }\n])\n```\n\nThe same [field name limitations](#field-name-limitations) that apply to type narrowing also apply to type safe patch support. If you can't use the field name on its own, because you want to append to an array or something similar, then you can use the `uncheckedPatches` syntax:\n\n```ts\nidm.managed.role.patch(\n role._id,\n null,\n {\n   uncheckedPatches: [\n    {\n      \"operation\":\"add\",\n      \"field\":\"/members/-\",\n      \"value\": {\"_ref\":\"managed/user/\" + user._id}\n    }\n  ]\n }\n);\n```\n\nYou can even use `checkedPatches` and `uncheckedPatches` together, like in this example:\n\n```ts\nidm.managed.role.patch(\n role._id,\n null,\n {\n  checkedPatches: [\n    {\n      \"operation\":\"replace\",\n      \"field\":\"givenName\",\n      \"value\": \"Babs\"\n    }\n  ],\n  uncheckedPatches: [\n    {\n      \"operation\":\"add\",\n      \"field\":\"/members/-\",\n      \"value\": {\"_ref\":\"managed/user/\" + user._id}\n    }\n  ]\n }\n)\n```\n\n\nHowever, you can't use the `checkedPatches` syntax on its own, it that case you need to forgo the `checkedPatches` keyword and just use the regular JSON patch array.\n\n## Automatic type narrowing\n\nThe automatic type narrowing is a very useful feature as it ensures that there are no typos in the field names as well as not letting you access fields that can't possibly be in the resulting object.\n\nAn example of code completion assistance can be seen in the animation below:\n\n![](assets/animations/type-narrowing-filter.gif)\n\nThis code example shows an example of using automatic type narrowing and the benefits you get from it understanding which fields you specified.\n\n```ts\nconst user = idm.managed.user.read(\"\u003cmanagedUserId\u003e\", { fields: [\"givenName\", \"sn\"] })\nif (user) {\n  user.givenName // This is fine\n  user.mail // This will throw a compile time error as the \"mail\" field wasn't specified in the fields\n}\n```\n\n### Field Name Limitations\n\nChecked fields are limited to only the direct fields on the resource and do not support:\n\n* Wildcards e.g. `*` or `*_ref`\n* Navigating relationships e.g. `manager/givenName` or `reports/*/givenName`\n* Leading slashes e.g. `/givenName`\n\nIf you can't use the checked version there is an \"escape hatch\" that turns off type checking for the field names. The main caveat then is that TypeScript no longer knows which fields you have selected, so the resulting type has all fields available both default and non-default fields. Which means you need to do your own checking whether as field actually has a value or not.\n\nThis example reads a managed object using un-checked fields, which would only return the `givenName` and `manager` relationship fields, however the code completion will show other fields such as `mail` as available, even though they won't ever be in the results.\n\n```ts\nconst user = idm.managed.user.read(\"\u003cmanagedUserId\u003e\", { unCheckedFields: [\"givenName\", \"manager/*\"] })\nif (user) {\n  user.mail // Not a compile time error, but will be undefined at runtime\n}\n```\n\n## ForgeRock API Documentation\n\nThe [Type-safe Wrapper functions](#type-safe-wrapper-functions) and built-in variables like `openidm` and `identityServer` have official documentation added to the TypeScript types, so that you can easily find how to use the function without needing to browse the ForgeRock documentation.\n\nThe reference for the documentation has used the following URLs:\n\n* https://backstage.forgerock.com/docs/idm/7.2/scripting-guide/scripting-func-ref.html\n* https://backstage.forgerock.com/docs/idm/7.2/crest/crest-query.html\n* And others...\n\n# Getting Started\n\nThe fastest way to get started would be to look at the [`idm-seed`](https://github.com/agiledigital/idm-seed) project as it has working examples that you can play with.\n\nHowever, if you want to integrate it into your own Node JS project then you need at least the `@agiledigital/idm-ts-types` NPM dependency as a dev dependency and some [configuration](#configuration) options specified.\n\nTo make it useful you would want to use [webpack](https://github.com/webpack/webpack) which takes care of converting Typescript back to ES3 compatible JavaScript that the Rhino JavaScript engine, which IDM uses, can handle properly.\n\nThere are quite a few other configuration options required to get the JavaScript to be in the right format so that commands in IDM e.g. `require(\"someJsFile\").someFunctionInThatJsFile()`. The main files you need to configure are [tsconfig.json](https://github.com/agiledigital/idm-seed/blob/master/tsconfig.json) and [webpack.config.ts](https://github.com/agiledigital/idm-seed/blob/master/webpack.config.ts). The [`idm-seed`](https://github.com/agiledigital/idm-seed) project should get you on the right track.\n\n# Configuration\n\nThe `gen-idm-ts-types.js` script is configured using the [node-config](https://github.com/node-config/node-config) package. It expects to find the `idmTsCodeGen` configuration context, and it supports the following values:\n\n| Key Name | Type | Default Value | Description |\n| --- | --- | --- | --- |\n| `idmTsTypesOutputFile` | `string` | none (required) | The path to the file where the Typescript types will be written. |\n| `idmProjectConfigDir` | `string` | none (required) | The path to the directory where the Managed Object's (`managed.json`) and connector files (`provisioner.openicf-*.json`) are located.\n| `useUnknownInsteadOfAny` | `boolean` | `false` | When the properties of an object are not known use `Record\u003cstring, unknown\u003e` for `true` or `Record\u003cstring, unknown\u003e` for `false` (the default). See [handling missing relationship types](#handling-missing-relationship-types) for some more context. |\n| `useUnknownInsteadOfAnyForManagedObj` | `boolean` | The value of `useUnknownInsteadOfAny` | Allows overriding of the `useUnknownInsteadOfAny` property specifically for Managed Objects. |\n| `useUnknownInsteadOfAnyForConnectorObj` | `boolean` | The value of `useUnknownInsteadOfAny` | Allows overriding of the `useUnknownInsteadOfAny` property specifically for Connector Objects. _Not currently implemented_. |\n\nNode-config expects to find a `config` directory relative to your `package.json` file, here are some examples taken from the [`idm-seed` project](https://github.com/agiledigital/idm-seed/tree/master/config).\n\n`config/default.json`\n```json\n{\n    \"idmTsCodeGen\": {\n        \"idmTsTypesOutputFile\": \"./lib/idm.ts\",\n        \"idmProjectConfigDir\": \"./project/conf\",\n        \"useUnknownInsteadOfAny\": false,\n        \"useUnknownInsteadOfAnyForManagedObj\": null,\n        \"useUnknownInsteadOfAnyForConnectorObj\": null\n    }\n}\n```\n\nIt can also be configured so that you can override values via environment variables:\n\n`config/custom-environment-variables.json`\n```json\n{\n    \"idmTsCodeGen\": {\n        \"idmTsTypesOutputFile\": \"IDM_TS_TYPES\",\n        \"idmProjectConfigDir\": \"IDM_CONFIG_DIR\",\n        \"useUnknownInsteadOfAny\": \"IDM_TS_TYPES_USE_UNKNOWN\",\n        \"useUnknownInsteadOfAnyForManagedObj\": \"IDM_TS_TYPES_USE_UNKNOWN_MANAGED\",\n        \"useUnknownInsteadOfAnyForConnectorObj\": \"IDM_TS_TYPES_USE_UNKNOWN_CONNECTOR\"\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagiledigital%2Fidm-ts-types","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagiledigital%2Fidm-ts-types","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagiledigital%2Fidm-ts-types/lists"}