Comparing version 7.1.1 to 7.2.0
@@ -875,5 +875,5 @@ import { BerWriter, BerReader } from 'asn1'; | ||
* - sub - Indicates that the entry specified as the search base, and all of its subordinates to any depth, should be considered. | ||
* - children - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* - children or subordinates - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
*/ | ||
scope?: 'base' | 'children' | 'one' | 'sub'; | ||
scope?: 'base' | 'children' | 'one' | 'sub' | 'subordinates'; | ||
/** | ||
@@ -1003,3 +1003,3 @@ * Specifies how the server must treat references to other entries: | ||
* - sub - Indicates that the entry specified as the search base, and all of its subordinates to any depth, should be considered. | ||
* - children - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* - children or subordinates - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* @param {string} [options.derefAliases='never'] - Specifies how the server must treat references to other entries: | ||
@@ -1019,2 +1019,3 @@ * - never - Never dereferences entries, returns alias objects instead. The alias contains the reference to the real entry. | ||
search(baseDN: DN | string, options?: SearchOptions, controls?: Control | Control[]): Promise<SearchResult>; | ||
searchPaginated(baseDN: DN | string, options?: SearchOptions, controls?: Control | Control[]): AsyncGenerator<SearchResult>; | ||
/** | ||
@@ -1025,2 +1026,3 @@ * Unbinds this client from the LDAP server. | ||
unbind(): Promise<void>; | ||
[Symbol.asyncDispose](): Promise<void>; | ||
private _sendBind; | ||
@@ -1057,3 +1059,3 @@ private _sendSearch; | ||
baseDN: string; | ||
scope: 'base' | 'children' | 'one' | 'sub'; | ||
scope: 'base' | 'children' | 'one' | 'sub' | 'subordinates'; | ||
derefAliases: 'always' | 'find' | 'never' | 'search'; | ||
@@ -1060,0 +1062,0 @@ sizeLimit: number; |
{ | ||
"name": "ldapts", | ||
"version": "7.1.1", | ||
"version": "7.2.0", | ||
"description": "LDAP client", | ||
@@ -73,3 +73,3 @@ "main": "./dist/index.cjs", | ||
"asn1": "~0.2.6", | ||
"debug": "~4.3.6", | ||
"debug": "~4.3.7", | ||
"strict-event-emitter-types": "~2.0.0", | ||
@@ -80,4 +80,4 @@ "uuid": "~10.0.0", | ||
"devDependencies": { | ||
"@types/chai": "~4.3.18", | ||
"@types/chai-as-promised": "~7.1.8", | ||
"@types/chai": "~4.3.19", | ||
"@types/chai-as-promised": "~8.0.0", | ||
"@types/debug": "~4.1.12", | ||
@@ -91,6 +91,6 @@ "@types/mocha": "~10.0.7", | ||
"chai-as-promised": "~8.0.0", | ||
"eslint": "~9.9.1", | ||
"eslint-config-decent": "^2.2.0", | ||
"eslint": "~9.10.0", | ||
"eslint-config-decent": "^2.2.1", | ||
"husky": "~9.1.5", | ||
"lint-staged": "~15.2.9", | ||
"lint-staged": "~15.2.10", | ||
"markdownlint-cli": "~0.41.0", | ||
@@ -103,6 +103,6 @@ "mocha": "~10.7.3", | ||
"ts-mockito": "~2.6.1", | ||
"tsx": "~4.18.0", | ||
"typescript": "~5.5.4", | ||
"tsx": "~4.19.0", | ||
"typescript": "~5.6.2", | ||
"unbuild": "2.0.0" | ||
} | ||
} |
@@ -26,2 +26,3 @@ # LDAPts | ||
- [Return buffer for specific attribute](#return-buffer-for-specific-attribute) | ||
- [searchPaginated](#searchpaginated) | ||
- [unbind](#unbind) | ||
@@ -361,3 +362,3 @@ - [Usage Examples](#usage-examples) | ||
| [timeLimit=10] (number) | The maximum length of time, in seconds, that the server should spend processing the search. A value of zero indicates no limit. Note that the server may also impose a time limit for the search operation, and in that case the smaller of the client-requested and server-imposed time limits will be enforced. | | ||
| [paged=false] (boolean|SearchPageOptions) | Used to allow paging and specify the page size | | ||
| [paged=false] (boolean|SearchPageOptions) | Used to allow paging and specify the page size. Note that even with paged options the result will contain all of the search results. If you need to paginate over results have a look at to [searchPaginated](#searchpaginated) method. | | ||
| [attributes=] (string[]) | A set of attributes to request for inclusion in entries that match the search criteria and are returned to the client. If a specific set of attribute descriptions are listed, then only those attributes should be included in matching entries. The special value “_” indicates that all user attributes should be included in matching entries. The special value “+” indicates that all operational attributes should be included in matching entries. The special value “1.1” indicates that no attributes should be included in matching entries. Some servers may also support the ability to use the “@” symbol followed by an object class name (e.g., “@inetOrgPerson”) to request all attributes associated with that object class. If the set of attributes to request is empty, then the server should behave as if the value “_” was specified to request that all user attributes be included in entries that are returned. | | ||
@@ -378,2 +379,29 @@ | [explicitBufferAttributes=] (string[]) | List of explicit attribute names to return as Buffer objects | | ||
### searchPaginated | ||
`search(baseDN, options, [controls])` | ||
Performs a search operation against the LDAP server and retrieve results in a paginated way. | ||
The searchPagination the same `options` with [search](#search) method but returns an iterator. | ||
Example: | ||
```ts | ||
const paginator = client.searchPaginated('o=5be4c382c583e54de6a3ff52,dc=jumpcloud,dc=com', { | ||
filter: 'objectclass=*', | ||
paged: { | ||
pageSize: 10, | ||
}, | ||
}); | ||
let total = 0; | ||
for await (const searchResult of paginator) { | ||
total += searchResult.searchEntries.length; | ||
console.log(searchResult.searchEntries); | ||
} | ||
console.log(`total results: ${total}`); | ||
``` | ||
#### Filter Strings | ||
@@ -543,2 +571,16 @@ | ||
## `using` declaration with Typescript | ||
For more details look have a look at [using Declarations and Explicit Resource Management](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html) | ||
```ts | ||
{ | ||
await using client = new Client({ | ||
url: 'ldap://127.0.0.1:1389', | ||
}); | ||
await client.bind(bindDN, password); | ||
} | ||
// unbind is called | ||
``` | ||
## Development | ||
@@ -545,0 +587,0 @@ |
@@ -93,5 +93,5 @@ import * as net from 'net'; | ||
* - sub - Indicates that the entry specified as the search base, and all of its subordinates to any depth, should be considered. | ||
* - children - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* - children or subordinates - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
*/ | ||
scope?: 'base' | 'children' | 'one' | 'sub'; | ||
scope?: 'base' | 'children' | 'one' | 'sub' | 'subordinates'; | ||
/** | ||
@@ -538,3 +538,3 @@ * Specifies how the server must treat references to other entries: | ||
* - sub - Indicates that the entry specified as the search base, and all of its subordinates to any depth, should be considered. | ||
* - children - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* - children or subordinates - Indicates that the entry specified by the search base should not be considered, but all of its subordinates to any depth should be considered. | ||
* @param {string} [options.derefAliases='never'] - Specifies how the server must treat references to other entries: | ||
@@ -630,2 +630,77 @@ * - never - Never dereferences entries, returns alias objects instead. The alias contains the reference to the real entry. | ||
public async *searchPaginated(baseDN: DN | string, options: SearchOptions = {}, controls?: Control | Control[]): AsyncGenerator<SearchResult> { | ||
if (!this.isConnected) { | ||
await this._connect(); | ||
} | ||
if (controls) { | ||
if (Array.isArray(controls)) { | ||
controls = controls.slice(0); | ||
} else { | ||
controls = [controls]; | ||
} | ||
// Make sure PagedResultsControl is not specified since it's handled internally | ||
for (const control of controls) { | ||
if (control instanceof PagedResultsControl) { | ||
throw new Error('Should not specify PagedResultsControl'); | ||
} | ||
} | ||
} else { | ||
controls = []; | ||
} | ||
let pageSize = 100; | ||
if (typeof options.paged === 'object' && options.paged.pageSize) { | ||
pageSize = options.paged.pageSize; | ||
} else if (options.sizeLimit && options.sizeLimit > 1) { | ||
// According to the RFC, servers should ignore the paging control if | ||
// pageSize >= sizelimit. Some might still send results, but it's safer | ||
// to stay under that figure when assigning a default value. | ||
pageSize = options.sizeLimit - 1; | ||
} | ||
let pagedResultsControl: PagedResultsControl | undefined; | ||
pagedResultsControl = new PagedResultsControl({ | ||
value: { | ||
size: pageSize, | ||
}, | ||
}); | ||
controls.push(pagedResultsControl); | ||
let filter: Filter; | ||
if (options.filter) { | ||
if (typeof options.filter === 'string') { | ||
filter = FilterParser.parseString(options.filter); | ||
} else { | ||
filter = options.filter; | ||
} | ||
} else { | ||
filter = new PresenceFilter({ attribute: 'objectclass' }); | ||
} | ||
const searchRequest = new SearchRequest({ | ||
messageId: -1, // NOTE: This will be set from _sendRequest() | ||
baseDN: typeof baseDN === 'string' ? baseDN : baseDN.toString(), | ||
scope: options.scope, | ||
filter, | ||
attributes: options.attributes, | ||
explicitBufferAttributes: options.explicitBufferAttributes, | ||
returnAttributeValues: options.returnAttributeValues, | ||
sizeLimit: options.sizeLimit, | ||
timeLimit: options.timeLimit, | ||
controls, | ||
}); | ||
do { | ||
const searchResult: SearchResult = { | ||
searchEntries: [], | ||
searchReferences: [], | ||
}; | ||
// eslint-disable-next-line no-await-in-loop | ||
pagedResultsControl = await this._sendSearch(searchRequest, searchResult, true, pageSize, pagedResultsControl, false); | ||
yield searchResult; | ||
} while (pagedResultsControl); | ||
} | ||
/** | ||
@@ -647,2 +722,6 @@ * Unbinds this client from the LDAP server. | ||
public [Symbol.asyncDispose](): Promise<void> { | ||
return this.unbind(); | ||
} | ||
private async _sendBind(req: BindRequest): Promise<void> { | ||
@@ -659,3 +738,10 @@ if (!this.isConnected) { | ||
private async _sendSearch(searchRequest: SearchRequest, searchResult: SearchResult, paged: boolean, pageSize: number, pagedResultsControl?: PagedResultsControl): Promise<void> { | ||
private async _sendSearch( | ||
searchRequest: SearchRequest, | ||
searchResult: SearchResult, | ||
paged: boolean, | ||
pageSize: number, | ||
pagedResultsControl?: PagedResultsControl, | ||
fetchAll = true, | ||
): Promise<PagedResultsControl | undefined> { | ||
searchRequest.messageId = this._nextMessageId(); | ||
@@ -693,5 +779,11 @@ | ||
pagedResultsControl.value.cookie = pagedResultsFromResponse.value.cookie; | ||
await this._sendSearch(searchRequest, searchResult, paged, pageSize, pagedResultsControl); | ||
if (fetchAll) { | ||
await this._sendSearch(searchRequest, searchResult, paged, pageSize, pagedResultsControl, true); | ||
} else { | ||
return pagedResultsControl; | ||
} | ||
} | ||
} | ||
return undefined; | ||
} | ||
@@ -698,0 +790,0 @@ |
@@ -22,3 +22,3 @@ import type { BerReader, BerWriter } from 'asn1'; | ||
public scope: 'base' | 'children' | 'one' | 'sub'; | ||
public scope: 'base' | 'children' | 'one' | 'sub' | 'subordinates'; | ||
@@ -68,2 +68,3 @@ public derefAliases: 'always' | 'find' | 'never' | 'search'; | ||
case 'children': | ||
case 'subordinates': | ||
writer.writeEnumeration(3); | ||
@@ -70,0 +71,0 @@ break; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
574656
12485
603
Updateddebug@~4.3.7