@lessly/sdk-app 63.2.3 → 63.2.4
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/dist/_types/runtime/access-reason.d.ts +7 -0
- package/dist/index.cjs +23 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +23 -1
- package/dist/index.js.map +1 -1
- package/docs/recipes/access.md +24 -5
- package/package.json +1 -1
package/docs/recipes/access.md
CHANGED
|
@@ -190,7 +190,11 @@ accessReason(app.mail.domain.create);
|
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
Use it in every example below; nothing in an App should assemble this text by
|
|
193
|
-
hand.
|
|
193
|
+
hand. It never throws and never renders the word `undefined`: an object with a
|
|
194
|
+
key but no usable level degrades to the key-only sentence, and an input with no
|
|
195
|
+
usable key at all falls back to `"Not available for your role. Ask an admin of
|
|
196
|
+
this product."` (plus one `console.warn` outside production, because that input
|
|
197
|
+
is a caller bug).
|
|
194
198
|
|
|
195
199
|
It takes **one** operation. Choosing which operation to explain — the first one
|
|
196
200
|
`can()` denied, out of the several a button performs — is the caller's job, and
|
|
@@ -227,11 +231,26 @@ exactly what the gateway does with an uncatalogued key.
|
|
|
227
231
|
>
|
|
228
232
|
> ```ts
|
|
229
233
|
> import type { Operation } from '@lessly/sdk-app';
|
|
230
|
-
>
|
|
231
|
-
>
|
|
232
|
-
>
|
|
233
|
-
>
|
|
234
|
+
>
|
|
235
|
+
> const ok = (v: unknown): v is string => typeof v === 'string' && v.trim() !== '';
|
|
236
|
+
>
|
|
237
|
+
> export const accessReason = (op: Operation | string): string => {
|
|
238
|
+
> if (ok(op)) return `Requires access to ${op}. Ask an admin of this product.`;
|
|
239
|
+
> // A generated method is a CALLABLE carrying operationKey/level, so not just 'object'.
|
|
240
|
+
> if (op !== null && (typeof op === 'object' || typeof op === 'function')) {
|
|
241
|
+
> const { operationKey, level } = op as { operationKey?: unknown; level?: unknown };
|
|
242
|
+
> if (ok(operationKey)) {
|
|
243
|
+
> return ok(level) && ['read', 'write', 'admin'].includes(level)
|
|
244
|
+
> ? `Requires level:${level} (${operationKey}). Ask an admin of this product.`
|
|
245
|
+
> : `Requires access to ${operationKey}. Ask an admin of this product.`;
|
|
246
|
+
> }
|
|
247
|
+
> }
|
|
248
|
+
> return 'Not available for your role. Ask an admin of this product.';
|
|
249
|
+
> };
|
|
234
250
|
> ```
|
|
251
|
+
>
|
|
252
|
+
> It never throws — a render helper that crashes takes the whole screen with it —
|
|
253
|
+
> and never renders `level:undefined`.
|
|
235
254
|
|
|
236
255
|
**Why both values.** The reason says what an admin has to *grant*, not what the
|
|
237
256
|
caller happens to be — a role name gives them nothing to act on, and "your role
|