ldap-rest 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,6 +5,53 @@ import type { DM } from '../../bin';
5
5
  import type { AttributeValue } from '../../lib/ldapActions';
6
6
  import { Hooks } from '../../hooks';
7
7
  import type { ChangesToNotify } from '../ldap/onChange';
8
+ /**
9
+ * OpenAPI schemas specific to the James integration.
10
+ *
11
+ * @openapi-component
12
+ * JamesQuotaUsage:
13
+ * type: object
14
+ * description: |
15
+ * Quota information for a mailbox user as returned by the James
16
+ * WebAdmin API (`GET /quota/users/{mail}`). Contains separate
17
+ * counters for message count and storage size.
18
+ * properties:
19
+ * count:
20
+ * type: object
21
+ * description: Message-count quota.
22
+ * properties:
23
+ * used:
24
+ * type: integer
25
+ * description: Number of messages currently stored.
26
+ * example: 142
27
+ * max:
28
+ * type: integer
29
+ * nullable: true
30
+ * description: |
31
+ * Maximum number of messages allowed. `null` means unlimited.
32
+ * example: 10000
33
+ * size:
34
+ * type: object
35
+ * description: Storage-size quota (bytes).
36
+ * properties:
37
+ * used:
38
+ * type: integer
39
+ * description: Bytes currently used.
40
+ * example: 524288000
41
+ * max:
42
+ * type: integer
43
+ * nullable: true
44
+ * description: |
45
+ * Maximum bytes allowed. `null` means unlimited.
46
+ * example: 2147483648
47
+ * example:
48
+ * count:
49
+ * used: 142
50
+ * max: 10000
51
+ * size:
52
+ * used: 524288000
53
+ * max: 2147483648
54
+ */
8
55
  export default class James extends TwakePlugin {
9
56
  name: string;
10
57
  roles: Role[];
@@ -13,6 +13,7 @@ This guide will help you create powerful, production-ready plugins for LDAP-Rest
13
13
  - [Configuration Best Practices](#configuration-best-practices)
14
14
  - [Complete Plugin Example](#complete-plugin-example)
15
15
  - [Testing Your Plugin](#testing-your-plugin)
16
+ - [Documenting REST endpoints (OpenAPI)](./openapi.md)
16
17
 
17
18
  ---
18
19
 
@@ -1282,7 +1283,7 @@ source ~/.test-env && npm run test:dev
1282
1283
  ## Additional Resources
1283
1284
 
1284
1285
  - [Contributing Guide](../../CONTRIBUTING.md) - Git workflow and PR guidelines
1285
- - [Hooks Reference](../../HOOKS.md) - Complete list of available hooks
1286
+ - [Hooks Reference](./hooks.md) - Complete list of available hooks
1286
1287
  - [Core Plugin Examples](../../src/plugins/) - Browse existing plugins
1287
1288
  - [Test Examples](../../test/plugins/) - See how core plugins are tested
1288
1289
 
@@ -0,0 +1,144 @@
1
+ # Documenting plugin endpoints (OpenAPI)
2
+
3
+ The published API reference at <https://linagora.github.io/ldap-rest/api/> is
4
+ generated from `openapi.json`, which itself is built statically by
5
+ [`scripts/generate-openapi.ts`](../../scripts/generate-openapi.ts) — it walks
6
+ every plugin's `api()` method and reads the JSDoc comments above each route.
7
+
8
+ You don't need to touch the generator to enrich your plugin's documentation.
9
+ Two JSDoc directives drive the entire pipeline:
10
+
11
+ - `@openapi` — placed **just above an `app.method(path, handler)` call**,
12
+ describes that single route.
13
+ - `@openapi-component` — placed anywhere in the file, registers reusable
14
+ schemas under `components.schemas` so multiple routes can `$ref` them.
15
+
16
+ Both directives carry inline **YAML** that follows the
17
+ [OpenAPI 3.0 Operation Object](https://spec.openapis.org/oas/v3.0.3#operation-object)
18
+ (or [Schema Object](https://spec.openapis.org/oas/v3.0.3#schema-object) for
19
+ components). The generator parses the YAML and merges it on top of the
20
+ defaults it would have emitted, so you only describe what you want to enrich.
21
+
22
+ ## Per-route metadata: `@openapi`
23
+
24
+ ```ts
25
+ /**
26
+ * @openapi
27
+ * summary: Get group by CN
28
+ * description: |
29
+ * The `:cn` segment may be either the group's RDN value or its full DN.
30
+ * Returns the raw LDAP entry.
31
+ * responses:
32
+ * '200':
33
+ * description: Group entry.
34
+ * content:
35
+ * application/json:
36
+ * schema: { $ref: '#/components/schemas/Group' }
37
+ * example:
38
+ * dn: cn=admins,ou=groups,dc=example,dc=com
39
+ * cn: admins
40
+ * description: Server administrators
41
+ * '404':
42
+ * description: Group not found.
43
+ */
44
+ app.get(`${this.config.api_prefix}/v1/ldap/groups/:cn`, asyncHandler(...));
45
+ ```
46
+
47
+ Anything below the `@openapi` line (up to the next `@directive` or the end of
48
+ the JSDoc block) is YAML. The keys you provide override the auto-generated
49
+ ones; everything you omit keeps the generator's defaults.
50
+
51
+ ### What you can override
52
+
53
+ Any field of an OpenAPI Operation Object, including:
54
+
55
+ | Field | Notes |
56
+ | ------------- | -------------------------------------------------------------------------------- |
57
+ | `summary` | Short, one-line title. |
58
+ | `description` | Long description (markdown). |
59
+ | `tags` | Array of strings; defaults to the plugin's tag. |
60
+ | `parameters` | Concatenated with auto-generated path params (your entries win on duplicates). |
61
+ | `requestBody` | Replace the generic `application/json` placeholder with a real schema + example. |
62
+ | `responses` | Replace per status code. |
63
+ | `security` | List of security requirement objects (works as-is). |
64
+ | `deprecated` | `true` to mark the operation as deprecated. |
65
+ | `operationId` | Stable identifier for code generators. |
66
+
67
+ ### What is autodetected
68
+
69
+ The generator already extracts:
70
+
71
+ - the **HTTP method** (`get`, `post`, …) from the call expression;
72
+ - the **path** (substituting local `const prefix = ...` variables, the
73
+ `${this.config.api_prefix}` template, and a few well-known config knobs);
74
+ - **path parameters** from `:param` segments;
75
+ - a default **summary** built from the verb and the last path segment;
76
+ - the plugin's **tag** (configured in `pluginTags` in the generator).
77
+
78
+ So a minimal, correct `@openapi` block is often only two or three keys.
79
+
80
+ ## Reusable schemas: `@openapi-component`
81
+
82
+ Place this anywhere in your plugin file (the convention is right above the
83
+ class). The body is a YAML map of `<SchemaName>: <SchemaDefinition>` pairs:
84
+
85
+ ```ts
86
+ /**
87
+ * @openapi-component
88
+ * Group:
89
+ * type: object
90
+ * required: [dn, cn]
91
+ * properties:
92
+ * dn: { type: string, example: cn=admins,ou=groups,dc=example,dc=com }
93
+ * cn: { type: string, example: admins }
94
+ * member:
95
+ * type: array
96
+ * items: { type: string }
97
+ * Error:
98
+ * type: object
99
+ * properties:
100
+ * error: { type: string }
101
+ * code: { type: integer }
102
+ */
103
+ export default class LdapGroups extends DmPlugin {
104
+ // ...
105
+ }
106
+ ```
107
+
108
+ Refer to them from any route using `$ref`:
109
+
110
+ ```yaml
111
+ schema: { $ref: '#/components/schemas/Group' }
112
+ ```
113
+
114
+ Component names are global to the spec, so prefix them with the plugin's
115
+ domain (`Group`, `ScimUser`, `PasswordPolicy`) to avoid collisions.
116
+
117
+ ## Tips
118
+
119
+ - **Examples beat specs.** A single concrete `example:` block is worth a
120
+ dozen `description:` lines for someone trying the API for the first time.
121
+ - **YAML alignment.** The generator strips the leading `*` from each line
122
+ before parsing, then dedents the block, so you can use any consistent
123
+ indentation as long as it's even within the block.
124
+ - **Multiline strings.** Use YAML block scalars (`description: |`) for
125
+ paragraphs and code samples — they round-trip cleanly through Redoc.
126
+ - **Annotation is opt-in.** Routes without an `@openapi` block are
127
+ **excluded** from the published spec — the generator prints a
128
+ `⚠️ Skipping undocumented route` warning so the author notices, but
129
+ the route does not surface in Redoc. The published doc therefore
130
+ reflects intentionally-documented API surface only, not every Express
131
+ call we happened to find.
132
+ - **A plugin with zero annotated routes disappears entirely** from the
133
+ spec, by the same rule.
134
+
135
+ ## Regenerate locally
136
+
137
+ ```sh
138
+ npm run generate:openapi # writes openapi.json
139
+ npm run build:pages # rebuilds the static site under _site/
140
+ ```
141
+
142
+ Open `_site/api/index.html` to preview the Redoc rendering. The published
143
+ site at <https://linagora.github.io/ldap-rest/api/> is rebuilt automatically
144
+ on every `v*` tag push.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ldap-rest",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Light directory manager",
5
5
  "keywords": [
6
6
  "Identity-Manager"
@@ -120,6 +120,10 @@
120
120
  "types": "./dist/src/plugins/ldap/organization.d.ts",
121
121
  "import": "./dist/plugins/ldap/organization.js"
122
122
  },
123
+ "./plugin-ldap-organizations": {
124
+ "types": "./dist/src/plugins/ldap/organizations.d.ts",
125
+ "import": "./dist/plugins/ldap/organizations.js"
126
+ },
123
127
  "./plugin-ldap-passwordpolicy": {
124
128
  "types": "./dist/src/plugins/ldap/passwordPolicy.d.ts",
125
129
  "import": "./dist/plugins/ldap/passwordPolicy.js"
@@ -552,6 +556,7 @@
552
556
  "build:dev": "./.dev.mk builddev",
553
557
  "build:docker": "./.dev.mk builddocker",
554
558
  "build:dockerfile": "./.dev.mk Dockerfile",
559
+ "build:pages": "tsx scripts/build-pages.ts",
555
560
  "build:prod": "npm run clean && NODE_ENV=production rollup -c && npm run build:browser && node scripts/moveBrowserLibs.mjs && npm run build:dockerfile",
556
561
  "build:watch": "rollup -c --watch",
557
562
  "check": "npm run check:ts && npm run lint && npm run format:check",
@@ -598,6 +603,7 @@
598
603
  "@rollup/plugin-typescript": "^12.1.4",
599
604
  "@types/chai": "^5.2.2",
600
605
  "@types/express": "^5.0.3",
606
+ "@types/js-yaml": "^4.0.9",
601
607
  "@types/mocha": "^10.0.10",
602
608
  "@types/multer": "^2.0.0",
603
609
  "@types/node": "^24.5.1",
@@ -611,6 +617,7 @@
611
617
  "eslint-plugin-node": "^11.1.0",
612
618
  "eslint-plugin-prettier": "^5.5.4",
613
619
  "fast-glob": "^3.3.3",
620
+ "js-yaml": "^4.1.1",
614
621
  "mocha": "^11.7.2",
615
622
  "nock": "^14.0.10",
616
623
  "prettier": "^3.6.2",