@7365admin1/core 3.54.0 → 3.56.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 CHANGED
@@ -1,5 +1,54 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.56.0
4
+
5
+ ### Minor Changes
6
+
7
+ - dc09517: Separate Seven365's roles from a client's, and enforce it on the server
8
+
9
+ `role.controller.ts requireRoleOrg` sends every role with no `org` to the staff
10
+ console gate, on the assumption that org-less means "a platform role". It does
11
+ not. A role with `type: "organization"` and no `org` is a TEMPLATE that clients
12
+ are invited with — "Org Owner" is one document behind 119 live members and 320
13
+ invitations on staging — and the console could rewrite it.
14
+
15
+ On 2026-09-07 it did. The console's role editor renders `useAdminPermission`,
16
+ the eleven PLATFORM resources, and the save wrote all 34 of those strings onto
17
+ that template. An empty permission list means "everything"
18
+ (`console-permission.util.ts consoleRoleAllowsAll`), so the role granted
19
+ everything right up to the moment it held a non-empty list — and the list it
20
+ then held contained no client module at all. Every holder, in every client, lost
21
+ every module at once.
22
+
23
+ `role-scope.util.ts` adds the missing distinction — platform (`type: "admin"`),
24
+ client template (no `org`), client (`org` set) — and two refusals built on it:
25
+
26
+ - the four role WRITES refuse a shared client template outright. Reads are
27
+ untouched: 119 members read that role on every session, and refusing them is
28
+ the same outage from the other direction.
29
+ - `createRole`, `updateRole` and `updatePermissionsById` refuse a console
30
+ permission string being ADDED to a role that is not a platform role. Strings
31
+ already stored pass through, so no save that works today begins to fail —
32
+ including the 114 org roles whose `subscriptions:*` grants are a
33
+ resource-NAME collision with the console's, not a platform grant.
34
+
35
+ No document is written, migrated or classified. `tools/role-scope-lockout-check`
36
+ measures the change from the account side, per account type, the way org-api
37
+ #470 does for site scoping: 400 staging accounts across 12 types, **zero
38
+ refusals in every type**, and zero roles that could no longer be re-saved.
39
+
40
+ ## 3.55.0
41
+
42
+ ### Minor Changes
43
+
44
+ - 8cbae97: Notification settings: deliver the marketplace in-app messages, and stop offering a channel that cannot deliver.
45
+
46
+ `NotificationModule` was missing the two tags `iservice365-API-core` sends for marketplace orders, so every in-app marketplace notification failed validation and was dropped inside the `catch` around the persist — the push arrived, the message never reached the app, and the "In the app" switch governed something that never happened. Both tags are now accepted; no other tag changed.
47
+
48
+ `GET /notification-preferences` now sends only the channels a category can actually deliver on. Email has no sender anywhere in the estate, so the screen was drawing a switch that could not move beside a sentence apologising for it, and then counting the two that could as "on everywhere". Every client renders what the server sends, so the dead row disappears from the web screen and both mobile screens at once. Where the reason was something a person actually needs — a booking confirmation goes to the address on the form — it is now said in the category's own description.
49
+
50
+ No stored preference changes, and no notification that was being delivered stops.
51
+
3
52
  ## 3.54.0
4
53
 
5
54
  ### Minor Changes
package/dist/index.d.ts CHANGED
@@ -12911,6 +12911,8 @@ declare enum NotificationModule {
12911
12911
  FACILITY_BOOKING = "facilityBooking",
12912
12912
  ONLINE_FORM = "onlineForm",
12913
12913
  PRELOVED_MARKETPLACE = "prelovedMarketplace",
12914
+ MARKETPLACE_ORDER = "marketplace-order",
12915
+ MARKETPLACE_VENDOR_ORDER = "marketplace-vendor-order",
12914
12916
  INCIDENT_REPORT = "incidentReport",
12915
12917
  EMERGENCY_CONTACT = "emergencyContact",
12916
12918
  VIRTUAL_PATROL = "virtualPatrol",
@@ -13477,10 +13479,16 @@ declare class NotificationService {
13477
13479
  *
13478
13480
  * ## Channels are declared per category, not assumed
13479
13481
  *
13480
- * `channels` says what this category can *physically* deliver on today. The
13481
- * screen draws every channel for every category and dims the ones that cannot
13482
- * deliver, with the reason in `channelNote` the house pattern is to show a
13483
- * control and explain why it is unavailable, never to hide it.
13482
+ * `channels` says what this category can *physically* deliver on today, and it
13483
+ * is what the settings screen is built from: `getForUser` sends only the
13484
+ * channels a category can actually use, so a person is never shown a switch
13485
+ * that will not move. `channelNote` is the reason a channel is off, kept here
13486
+ * for whoever reads this file and pinned by a test — it is not sent to a
13487
+ * client, because an apology beside a dead control is not a setting.
13488
+ *
13489
+ * Where the reason is something a person actually needs (a booking
13490
+ * confirmation goes to the address on the form), it is said in the category's
13491
+ * own `description`, which the screen does show.
13484
13492
  *
13485
13493
  * Email is `false` everywhere for a real reason: the module emails this system
13486
13494
  * sends are addressed to an email string stored on a record (a booking's
@@ -13671,10 +13679,12 @@ type NotificationPreferenceView = {
13671
13679
  channels: Array<{
13672
13680
  key: string;
13673
13681
  label: string;
13674
- /** false = drawn, dimmed, and not switchable */
13682
+ /**
13683
+ * Always true. Only channels this category can really deliver on are
13684
+ * sent at all; the field stays so a client written against the older
13685
+ * shape, which filtered on it, keeps working unchanged.
13686
+ */
13675
13687
  supported: boolean;
13676
- /** plain-English reason, present only when unsupported */
13677
- note?: string;
13678
13688
  enabled: boolean;
13679
13689
  }>;
13680
13690
  }>;