@voltro/plugin-scim 0.83.1 → 0.85.0
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.
- package/CHANGELOG.md +1191 -0
- package/THIRD-PARTY-NOTICES.md +1 -57
- package/dist/index.d.ts +13 -0
- package/dist/index.js +96 -64
- package/package.json +4 -4
package/THIRD-PARTY-NOTICES.md
CHANGED
|
@@ -5,66 +5,10 @@ property of its respective copyright holders and is used under the terms of
|
|
|
5
5
|
its license. This file is provided for attribution; it grants no rights in
|
|
6
6
|
@voltro/plugin-scim itself, which is proprietary (see LICENSE).
|
|
7
7
|
|
|
8
|
-
Generated from the resolved runtime dependency closure (
|
|
8
|
+
Generated from the resolved runtime dependency closure (5 packages).
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
## @effect/experimental@0.61.1
|
|
13
|
-
|
|
14
|
-
License: MIT
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
MIT License
|
|
18
|
-
|
|
19
|
-
Copyright (c) 2023-present The Contributors
|
|
20
|
-
|
|
21
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
23
|
-
in the Software without restriction, including without limitation the rights
|
|
24
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
25
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
26
|
-
furnished to do so, subject to the following conditions:
|
|
27
|
-
|
|
28
|
-
The above copyright notice and this permission notice shall be included in all
|
|
29
|
-
copies or substantial portions of the Software.
|
|
30
|
-
|
|
31
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
32
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
33
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
34
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
35
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
36
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
37
|
-
SOFTWARE.
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## @effect/sql@0.52.1
|
|
41
|
-
|
|
42
|
-
License: MIT
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
MIT License
|
|
46
|
-
|
|
47
|
-
Copyright (c) 2023-present The Contributors
|
|
48
|
-
|
|
49
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
50
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
51
|
-
in the Software without restriction, including without limitation the rights
|
|
52
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
53
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
54
|
-
furnished to do so, subject to the following conditions:
|
|
55
|
-
|
|
56
|
-
The above copyright notice and this permission notice shall be included in all
|
|
57
|
-
copies or substantial portions of the Software.
|
|
58
|
-
|
|
59
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
60
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
61
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
62
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
63
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
64
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
65
|
-
SOFTWARE.
|
|
66
|
-
```
|
|
67
|
-
|
|
68
12
|
## jose@6.2.12
|
|
69
13
|
|
|
70
14
|
License: MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -90,6 +90,16 @@ export declare const scimList: (resources: ReadonlyArray<Record<string, unknown>
|
|
|
90
90
|
readonly startIndex?: number;
|
|
91
91
|
}) => Record<string, unknown>;
|
|
92
92
|
|
|
93
|
+
export declare interface ScimPage<T> {
|
|
94
|
+
readonly rows: ReadonlyArray<T>;
|
|
95
|
+
readonly totalResults: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export declare interface ScimPageOptions {
|
|
99
|
+
readonly startIndex: number;
|
|
100
|
+
readonly count: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
93
103
|
export declare const scimPlugin: (options: ScimPluginOptions) => VoltroPlugin;
|
|
94
104
|
|
|
95
105
|
export declare interface ScimPluginOptions {
|
|
@@ -119,12 +129,15 @@ export declare const scimSchemas: (location: string) => ReadonlyArray<Record<str
|
|
|
119
129
|
export declare interface ScimStore {
|
|
120
130
|
/** `filter` is an `<attr> eq "<value>"` equality (userName / externalId), or `null` = all. */
|
|
121
131
|
readonly listUsers: (filter: ScimFilter | null) => Promise<ReadonlyArray<ScimUserRow>>;
|
|
132
|
+
/** Stable id-ordered page and total matching rows. Do not load all row bodies. */
|
|
133
|
+
readonly pageUsers: (filter: ScimFilter | null, page: ScimPageOptions) => Promise<ScimPage<ScimUserRow>>;
|
|
122
134
|
readonly getUser: (id: string) => Promise<ScimUserRow | null>;
|
|
123
135
|
readonly createUser: (fields: Omit<ScimUserRow, 'id' | 'createdAt' | 'updatedAt'>) => Promise<ScimUserRow>;
|
|
124
136
|
readonly putUser: (id: string, row: ScimUserRow) => Promise<ScimUserRow | null>;
|
|
125
137
|
readonly deleteUser: (id: string) => Promise<boolean>;
|
|
126
138
|
/** `filter` is displayName / externalId equality, or `null` = all. */
|
|
127
139
|
readonly listGroups: (filter: ScimFilter | null) => Promise<ReadonlyArray<ScimGroupRow>>;
|
|
140
|
+
readonly pageGroups: (filter: ScimFilter | null, page: ScimPageOptions) => Promise<ScimPage<ScimGroupRow>>;
|
|
128
141
|
readonly getGroup: (id: string) => Promise<ScimGroupRow | null>;
|
|
129
142
|
readonly createGroup: (fields: Omit<ScimGroupRow, 'id' | 'createdAt' | 'updatedAt'>) => Promise<ScimGroupRow>;
|
|
130
143
|
readonly putGroup: (id: string, row: ScimGroupRow) => Promise<ScimGroupRow | null>;
|
package/dist/index.js
CHANGED
|
@@ -95,18 +95,18 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
95
95
|
}, D = (e) => {
|
|
96
96
|
let t = Number(e.get("startIndex")), n = Number(e.get("count"));
|
|
97
97
|
return {
|
|
98
|
-
startIndex: Number.
|
|
99
|
-
count: e.get("count") !== null && Number.
|
|
98
|
+
startIndex: Number.isSafeInteger(t) && t >= 1 ? t : 1,
|
|
99
|
+
count: e.get("count") !== null && Number.isSafeInteger(n) && n >= 0 ? n : null
|
|
100
100
|
};
|
|
101
101
|
}, O = (e, t) => {
|
|
102
102
|
let n = t.Operations ?? t.operations ?? [], r = (e) => (Array.isArray(e) ? e : e === void 0 ? [] : [e]).map((e) => String(e?.value ?? e)).filter((e) => e !== "" && e !== "undefined"), i = e;
|
|
103
103
|
for (let e of n) {
|
|
104
104
|
let t = (e.op ?? "").toLowerCase(), n = e.path ?? "", a = /^members\[value\s+eq\s+"([^"]*)"\]$/i.exec(n);
|
|
105
105
|
if (t === "add" && n.toLowerCase() === "members") {
|
|
106
|
-
let t = r(e.value).filter((e) => !i.members.includes(e));
|
|
106
|
+
let t = r(e.value), n = t.length > 4 ? new Set(i.members) : void 0, a = t.filter((e) => !(n === void 0 ? i.members.includes(e) : n.has(e)));
|
|
107
107
|
i = {
|
|
108
108
|
...i,
|
|
109
|
-
members: [...i.members, ...
|
|
109
|
+
members: [...i.members, ...a]
|
|
110
110
|
};
|
|
111
111
|
} else if (t === "remove" && a) i = {
|
|
112
112
|
...i,
|
|
@@ -254,19 +254,36 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
254
254
|
members: l().nullable(),
|
|
255
255
|
createdAt: p().default("now"),
|
|
256
256
|
updatedAt: p().default("now").onUpdate("now")
|
|
257
|
-
}).renamedFrom("scim_groups"), F = (e
|
|
258
|
-
|
|
257
|
+
}).renamedFrom("scim_groups"), F = (e) => {
|
|
258
|
+
if (!Number.isSafeInteger(e.startIndex) || e.startIndex < 1 || !Number.isSafeInteger(e.count) || e.count < 0) throw RangeError("SCIM pages require a positive startIndex and a non-negative count, both safe integers");
|
|
259
|
+
}, I = (e, t) => t === null || e[t.attribute] === t.value, L = (e = Date.now) => {
|
|
260
|
+
let t = /* @__PURE__ */ new Map(), n = /* @__PURE__ */ new Map(), r = 0, i = 0, a = (e) => `${e}_${++r}`, o = (e) => {
|
|
261
|
+
let t = -1, n = [];
|
|
262
|
+
return (r, a) => {
|
|
263
|
+
F(a), t !== i && (n = [...e.keys()].sort(), t = i);
|
|
264
|
+
let o = [], s = 0;
|
|
265
|
+
for (let t of n) {
|
|
266
|
+
let n = e.get(t);
|
|
267
|
+
I(n, r) && (s >= a.startIndex - 1 && o.length < a.count && o.push(n), s++);
|
|
268
|
+
}
|
|
269
|
+
return {
|
|
270
|
+
rows: o,
|
|
271
|
+
totalResults: s
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
}, s = o(t), c = o(n);
|
|
259
275
|
return {
|
|
260
|
-
listUsers: async (e) => [...t.values()].filter((t) =>
|
|
276
|
+
listUsers: async (e) => [...t.values()].filter((t) => I(t, e)),
|
|
277
|
+
pageUsers: async (e, t) => s(e, t),
|
|
261
278
|
getUser: async (e) => t.get(e) ?? null,
|
|
262
279
|
createUser: async (n) => {
|
|
263
280
|
let r = {
|
|
264
281
|
...n,
|
|
265
|
-
id:
|
|
282
|
+
id: a("user"),
|
|
266
283
|
createdAt: e(),
|
|
267
284
|
updatedAt: e()
|
|
268
285
|
};
|
|
269
|
-
return t.set(r.id, r), r;
|
|
286
|
+
return t.set(r.id, r), i++, r;
|
|
270
287
|
},
|
|
271
288
|
putUser: async (n, r) => {
|
|
272
289
|
if (!t.has(n)) return null;
|
|
@@ -277,17 +294,21 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
277
294
|
};
|
|
278
295
|
return t.set(n, i), i;
|
|
279
296
|
},
|
|
280
|
-
deleteUser: async (e) =>
|
|
281
|
-
|
|
297
|
+
deleteUser: async (e) => {
|
|
298
|
+
let n = t.delete(e);
|
|
299
|
+
return n && i++, n;
|
|
300
|
+
},
|
|
301
|
+
listGroups: async (e) => [...n.values()].filter((t) => I(t, e)),
|
|
302
|
+
pageGroups: async (e, t) => c(e, t),
|
|
282
303
|
getGroup: async (e) => n.get(e) ?? null,
|
|
283
304
|
createGroup: async (t) => {
|
|
284
305
|
let r = {
|
|
285
306
|
...t,
|
|
286
|
-
id:
|
|
307
|
+
id: a("group"),
|
|
287
308
|
createdAt: e(),
|
|
288
309
|
updatedAt: e()
|
|
289
310
|
};
|
|
290
|
-
return n.set(r.id, r), r;
|
|
311
|
+
return n.set(r.id, r), i++, r;
|
|
291
312
|
},
|
|
292
313
|
putGroup: async (t, r) => {
|
|
293
314
|
if (!n.has(t)) return null;
|
|
@@ -298,9 +319,12 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
298
319
|
};
|
|
299
320
|
return n.set(t, i), i;
|
|
300
321
|
},
|
|
301
|
-
deleteGroup: async (e) =>
|
|
322
|
+
deleteGroup: async (e) => {
|
|
323
|
+
let t = n.delete(e);
|
|
324
|
+
return t && i++, t;
|
|
325
|
+
}
|
|
302
326
|
};
|
|
303
|
-
},
|
|
327
|
+
}, R = (e) => {
|
|
304
328
|
let t = async (t, n) => {
|
|
305
329
|
let r = u(t);
|
|
306
330
|
return e.query((n ? r.where(n) : r).descriptor);
|
|
@@ -321,9 +345,17 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
321
345
|
members: e.members ?? [],
|
|
322
346
|
createdAt: r(e.createdAt),
|
|
323
347
|
updatedAt: r(e.updatedAt)
|
|
324
|
-
})
|
|
348
|
+
}), a = async (t, n, r, i) => {
|
|
349
|
+
F(r);
|
|
350
|
+
let a = u(t), s = n === null ? a : a.where(o(n.attribute, n.value)), [c, l] = await Promise.all([e.query(s.count().descriptor), r.count === 0 ? Promise.resolve([]) : e.query(s.orderBy("id", "asc").offset(r.startIndex - 1).limit(r.count).descriptor)]);
|
|
351
|
+
return {
|
|
352
|
+
rows: l.map(i),
|
|
353
|
+
totalResults: Number(c[0]?.count ?? 0)
|
|
354
|
+
};
|
|
355
|
+
};
|
|
325
356
|
return {
|
|
326
357
|
listUsers: async (e) => (await t(N, e ? o(e.attribute, e.value) : void 0)).map(n),
|
|
358
|
+
pageUsers: (e, t) => a(N, e, t, n),
|
|
327
359
|
getUser: async (e) => {
|
|
328
360
|
let r = await t(N, o("id", e));
|
|
329
361
|
return r[0] ? n(r[0]) : null;
|
|
@@ -360,6 +392,7 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
360
392
|
}) : null,
|
|
361
393
|
deleteUser: async (n) => (await t(N, o("id", n)))[0] ? (await e.delete("_voltro_scim_users", n), !0) : !1,
|
|
362
394
|
listGroups: async (e) => (await t(P, e ? o(e.attribute, e.value) : void 0)).map(i),
|
|
395
|
+
pageGroups: (e, t) => a(P, e, t, i),
|
|
363
396
|
getGroup: async (e) => {
|
|
364
397
|
let n = await t(P, o("id", e));
|
|
365
398
|
return n[0] ? i(n[0]) : null;
|
|
@@ -393,54 +426,50 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
393
426
|
}) : null,
|
|
394
427
|
deleteGroup: async (n) => (await t(P, o("id", n)))[0] ? (await e.delete("_voltro_scim_groups", n), !0) : !1
|
|
395
428
|
};
|
|
396
|
-
},
|
|
429
|
+
}, z = (e, t) => ({
|
|
397
430
|
status: e,
|
|
398
431
|
body: JSON.stringify(t),
|
|
399
432
|
contentType: "application/scim+json"
|
|
400
|
-
}),
|
|
433
|
+
}), B = (e) => {
|
|
401
434
|
try {
|
|
402
435
|
return JSON.parse(new TextDecoder().decode(e.rawBody) || "{}");
|
|
403
436
|
} catch {
|
|
404
437
|
return {};
|
|
405
438
|
}
|
|
406
|
-
},
|
|
407
|
-
let { startIndex: n, count: r } = D(t), i = n - 1;
|
|
408
|
-
return {
|
|
409
|
-
page: e.slice(i, r === null ? void 0 : i + r),
|
|
410
|
-
total: e.length,
|
|
411
|
-
startIndex: n
|
|
412
|
-
};
|
|
413
|
-
}, V = () => R(400, T(400, "unsupported filter — only `<attribute> eq \"value\"` on the indexed attributes", "invalidFilter")), H = async (e, t, n) => (await e.listUsers({
|
|
439
|
+
}, V = () => z(400, T(400, "unsupported filter — only `<attribute> eq \"value\"` on the indexed attributes", "invalidFilter")), H = async (e, t, n) => (await e.listUsers({
|
|
414
440
|
attribute: "userName",
|
|
415
441
|
value: t
|
|
416
|
-
})).some((e) => e.id !== n), U = (e) =>
|
|
417
|
-
if (!i(r.headers, t)) return
|
|
442
|
+
})).some((e) => e.id !== n), U = (e) => z(409, T(409, `a user with userName '${e}' already exists`, "uniqueness")), W = async (e, t, n, r) => {
|
|
443
|
+
if (!i(r.headers, t)) return z(401, T(401, "invalid or missing bearer token"));
|
|
418
444
|
let [, a, o] = r.path.slice(n.length).replace(/\/+$/, "").split("/"), s = r.method.toUpperCase(), c = new URLSearchParams(r.query), l = `${n}/Users`;
|
|
419
445
|
if (s === "GET" && !o) {
|
|
420
|
-
if (a === "ServiceProviderConfig") return
|
|
421
|
-
if (a === "Schemas") return
|
|
422
|
-
if (a === "ResourceTypes") return
|
|
446
|
+
if (a === "ServiceProviderConfig") return z(200, k(`${n}/ServiceProviderConfig`));
|
|
447
|
+
if (a === "Schemas") return z(200, w(j(`${n}/Schemas`)));
|
|
448
|
+
if (a === "ResourceTypes") return z(200, w(M(n)));
|
|
423
449
|
}
|
|
424
450
|
if (a === "Users") {
|
|
425
451
|
if (s === "GET" && !o) {
|
|
426
452
|
let t = E(c.get("filter"), ["userName", "externalId"]);
|
|
427
453
|
if (t.kind === "invalid") return V();
|
|
428
|
-
let {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
454
|
+
let { startIndex: n, count: r } = D(c), i = await e.pageUsers(t.kind === "filter" ? t : null, {
|
|
455
|
+
startIndex: n,
|
|
456
|
+
count: Math.min(r ?? 100, 1e3)
|
|
457
|
+
});
|
|
458
|
+
return z(200, w(i.rows.map((e) => x(e, l)), {
|
|
459
|
+
totalResults: i.totalResults,
|
|
460
|
+
startIndex: n
|
|
432
461
|
}));
|
|
433
462
|
}
|
|
434
463
|
if (s === "GET" && o) {
|
|
435
464
|
let t = await e.getUser(o);
|
|
436
|
-
return t ?
|
|
465
|
+
return t ? z(200, x(t, l)) : z(404, T(404, "user not found"));
|
|
437
466
|
}
|
|
438
467
|
if (s === "POST" && !o) {
|
|
439
|
-
let t = S(
|
|
440
|
-
if (t.userName === "") return
|
|
468
|
+
let t = S(B(r));
|
|
469
|
+
if (t.userName === "") return z(400, T(400, "userName is required", "invalidValue"));
|
|
441
470
|
if (await H(e, t.userName)) return U(t.userName);
|
|
442
471
|
try {
|
|
443
|
-
return
|
|
472
|
+
return z(201, x(await e.createUser(t), l));
|
|
444
473
|
} catch (n) {
|
|
445
474
|
if (await H(e, t.userName)) return U(t.userName);
|
|
446
475
|
throw n;
|
|
@@ -448,24 +477,24 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
448
477
|
}
|
|
449
478
|
if (s === "PUT" && o) {
|
|
450
479
|
let t = await e.getUser(o);
|
|
451
|
-
if (!t) return
|
|
480
|
+
if (!t) return z(404, T(404, "user not found"));
|
|
452
481
|
let n = {
|
|
453
482
|
...t,
|
|
454
|
-
...S(
|
|
483
|
+
...S(B(r))
|
|
455
484
|
};
|
|
456
485
|
if (await H(e, n.userName, o)) return U(n.userName);
|
|
457
486
|
let i = await e.putUser(o, n);
|
|
458
|
-
return i ?
|
|
487
|
+
return i ? z(200, x(i, l)) : z(404, T(404, "user not found"));
|
|
459
488
|
}
|
|
460
489
|
if (s === "PATCH" && o) {
|
|
461
490
|
let t = await e.getUser(o);
|
|
462
|
-
if (!t) return
|
|
463
|
-
let n = C(t,
|
|
491
|
+
if (!t) return z(404, T(404, "user not found"));
|
|
492
|
+
let n = C(t, B(r));
|
|
464
493
|
if (n.userName !== t.userName && await H(e, n.userName, o)) return U(n.userName);
|
|
465
494
|
let i = await e.putUser(o, n);
|
|
466
|
-
return i ?
|
|
495
|
+
return i ? z(200, x(i, l)) : z(404, T(404, "user not found"));
|
|
467
496
|
}
|
|
468
|
-
if (s === "DELETE" && o) return await e.deleteUser(o) ? { status: 204 } :
|
|
497
|
+
if (s === "DELETE" && o) return await e.deleteUser(o) ? { status: 204 } : z(404, T(404, "user not found"));
|
|
469
498
|
}
|
|
470
499
|
if (a === "Groups") {
|
|
471
500
|
let t = `${n}/Groups`, i = (e) => ({
|
|
@@ -482,19 +511,22 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
482
511
|
if (s === "GET" && !o) {
|
|
483
512
|
let t = E(c.get("filter"), ["displayName", "externalId"]);
|
|
484
513
|
if (t.kind === "invalid") return V();
|
|
485
|
-
let {
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
514
|
+
let { startIndex: n, count: r } = D(c), a = await e.pageGroups(t.kind === "filter" ? t : null, {
|
|
515
|
+
startIndex: n,
|
|
516
|
+
count: Math.min(r ?? 100, 1e3)
|
|
517
|
+
});
|
|
518
|
+
return z(200, w(a.rows.map(i), {
|
|
519
|
+
totalResults: a.totalResults,
|
|
520
|
+
startIndex: n
|
|
489
521
|
}));
|
|
490
522
|
}
|
|
491
523
|
if (s === "GET" && o) {
|
|
492
524
|
let t = await e.getGroup(o);
|
|
493
|
-
return t ?
|
|
525
|
+
return t ? z(200, i(t)) : z(404, T(404, "group not found"));
|
|
494
526
|
}
|
|
495
527
|
if (s === "POST" && !o) {
|
|
496
|
-
let t =
|
|
497
|
-
return
|
|
528
|
+
let t = B(r), n = (t.members ?? []).map((e) => String(e.value)).filter(Boolean);
|
|
529
|
+
return z(201, i(await e.createGroup({
|
|
498
530
|
displayName: String(t.displayName ?? ""),
|
|
499
531
|
externalId: t.externalId ?? null,
|
|
500
532
|
members: n
|
|
@@ -502,24 +534,24 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
502
534
|
}
|
|
503
535
|
if (s === "PUT" && o) {
|
|
504
536
|
let t = await e.getGroup(o);
|
|
505
|
-
if (!t) return
|
|
506
|
-
let n =
|
|
537
|
+
if (!t) return z(404, T(404, "group not found"));
|
|
538
|
+
let n = B(r), a = (n.members ?? []).map((e) => String(e.value)).filter(Boolean), s = await e.putGroup(o, {
|
|
507
539
|
...t,
|
|
508
540
|
displayName: String(n.displayName ?? t.displayName),
|
|
509
541
|
externalId: n.externalId ?? t.externalId,
|
|
510
542
|
members: a
|
|
511
543
|
});
|
|
512
|
-
return s ?
|
|
544
|
+
return s ? z(200, i(s)) : z(404, T(404, "group not found"));
|
|
513
545
|
}
|
|
514
546
|
if (s === "PATCH" && o) {
|
|
515
547
|
let t = await e.getGroup(o);
|
|
516
|
-
if (!t) return
|
|
517
|
-
let n = await e.putGroup(o, O(t,
|
|
518
|
-
return n ?
|
|
548
|
+
if (!t) return z(404, T(404, "group not found"));
|
|
549
|
+
let n = await e.putGroup(o, O(t, B(r)));
|
|
550
|
+
return n ? z(200, i(n)) : z(404, T(404, "group not found"));
|
|
519
551
|
}
|
|
520
|
-
if (s === "DELETE" && o) return await e.deleteGroup(o) ? { status: 204 } :
|
|
552
|
+
if (s === "DELETE" && o) return await e.deleteGroup(o) ? { status: 204 } : z(404, T(404, "group not found"));
|
|
521
553
|
}
|
|
522
|
-
return
|
|
554
|
+
return z(404, T(404, "unsupported SCIM endpoint"));
|
|
523
555
|
}, G = "@voltro/plugin-scim", K = (r) => {
|
|
524
556
|
if (r.token.trim() === "") throw Error("scimPlugin({ token }) requires a non-empty bearer token — got an empty string. SCIM exposes the full user + group directory and can deactivate accounts, so it is never mounted ungated. Set the environment variable your IdP presents (e.g. SCIM_TOKEN) and pass it through, or remove scimPlugin() from the plugin list.");
|
|
525
557
|
let i = r.basePath ?? "/scim/v2", a = n({
|
|
@@ -537,10 +569,10 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
537
569
|
method: "*",
|
|
538
570
|
path: i,
|
|
539
571
|
originGuard: "exempt",
|
|
540
|
-
handle: async (e) => o ? W(o, r.token, i, e) :
|
|
572
|
+
handle: async (e) => o ? W(o, r.token, i, e) : z(503, T(503, "scim store not bound"))
|
|
541
573
|
}],
|
|
542
574
|
bindDataStore: (e) => {
|
|
543
|
-
o =
|
|
575
|
+
o = R(e);
|
|
544
576
|
},
|
|
545
577
|
onActivate: (t) => e.sync(() => {
|
|
546
578
|
t.logger.info("scim active", { basePath: i });
|
|
@@ -548,4 +580,4 @@ var m = "urn:ietf:params:scim:schemas:core:2.0:User", h = "urn:ietf:params:scim:
|
|
|
548
580
|
});
|
|
549
581
|
};
|
|
550
582
|
//#endregion
|
|
551
|
-
export { _ as SCIM_ERROR_SCHEMA, h as SCIM_GROUP_SCHEMA, g as SCIM_LIST_SCHEMA, m as SCIM_USER_SCHEMA, O as applyScimGroupPatch, C as applyScimPatch,
|
|
583
|
+
export { _ as SCIM_ERROR_SCHEMA, h as SCIM_GROUP_SCHEMA, g as SCIM_LIST_SCHEMA, m as SCIM_USER_SCHEMA, O as applyScimGroupPatch, C as applyScimPatch, R as dataStoreScimStore, S as fromScimUser, W as handleScim, W as handleScimRequest, L as memoryScimStore, D as parsePagination, E as parseScimFilter, M as resourceTypes, T as scimError, w as scimList, K as scimPlugin, j as scimSchemas, k as serviceProviderConfig, x as toScimUser };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-scim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"description": "SCIM 2.0 provisioning — Users + Groups REST endpoints (/scim/v2) so an enterprise IdP (Okta, Entra, OneLogin) can create/update/deactivate users in your app. Bearer-token gated; the SCIM envelope + filtering handled for you.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"node": ">=24.0.0"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@voltro/database": "0.
|
|
37
|
-
"@voltro/protocol": "0.
|
|
36
|
+
"@voltro/database": "0.85.0",
|
|
37
|
+
"@voltro/protocol": "0.85.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"effect": "
|
|
40
|
+
"effect": "4.0.1"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|