@fusebase/fusebase-gate-sdk 2.3.34-sdk.4 → 2.3.34-sdk.9
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/apis/AppApisApi.d.ts +1 -1
- package/dist/apis/AppApisApi.js +1 -1
- package/dist/apis/OrgUsersApi.d.ts +6 -2
- package/dist/apis/OrgUsersApi.js +2 -1
- package/dist/types/app-api/app-api.d.ts +7 -0
- package/dist/types/app-magic-link/app-magic-link.d.ts +25 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/org-user/org-user.d.ts +11 -0
- package/package.json +1 -1
- package/release-notes/2.3.34-sdk.9.md +9 -0
- package/release-notes/latest.md +4 -77
- package/release-notes/2.3.34-sdk.3.md +0 -9
- package/release-notes/2.3.34-sdk.4.md +0 -82
|
@@ -11,7 +11,7 @@ export declare class AppApisApi {
|
|
|
11
11
|
constructor(client: Client);
|
|
12
12
|
/**
|
|
13
13
|
* Call app API operation
|
|
14
|
-
* Invokes a published app API operation through the owner app runtime using a runtime app token minted for the current authenticated caller context.
|
|
14
|
+
* Invokes a published app API operation through the owner app runtime using a runtime app token minted for the current authenticated caller context. Pass `onBehalfOfUserToken` (a platform app token, i.e. the user's `fbsfeaturetoken`) to run the call on behalf of an end user: Gate verifies it fail-closed and forwards the resolved user to the runtime as `X-Fusebase-Verified-User-Id` / `X-Fusebase-Verified-User-Source: obo`, so apps no longer need to hand-roll dual-token forwarding. The operation's `allowedCallers` / `requiredPermissions` are still evaluated against the calling identity, not the on-behalf-of user.
|
|
15
15
|
*/
|
|
16
16
|
callAppApi(params: {
|
|
17
17
|
path: {
|
package/dist/apis/AppApisApi.js
CHANGED
|
@@ -13,7 +13,7 @@ class AppApisApi {
|
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Call app API operation
|
|
16
|
-
* Invokes a published app API operation through the owner app runtime using a runtime app token minted for the current authenticated caller context.
|
|
16
|
+
* Invokes a published app API operation through the owner app runtime using a runtime app token minted for the current authenticated caller context. Pass `onBehalfOfUserToken` (a platform app token, i.e. the user's `fbsfeaturetoken`) to run the call on behalf of an end user: Gate verifies it fail-closed and forwards the resolved user to the runtime as `X-Fusebase-Verified-User-Id` / `X-Fusebase-Verified-User-Source: obo`, so apps no longer need to hand-roll dual-token forwarding. The operation's `allowedCallers` / `requiredPermissions` are still evaluated against the calling identity, not the on-behalf-of user.
|
|
17
17
|
*/
|
|
18
18
|
async callAppApi(params) {
|
|
19
19
|
return this.client.request({
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Domain: org-users
|
|
6
6
|
*/
|
|
7
7
|
import type { Client } from "../runtime/transport";
|
|
8
|
-
import type { ClientAccountScheduledDeletionRequestContract, ClientAccountScheduledDeletionResponseContract, orgIdInPathRequired, OrgMemberRemoveResponseContract, OrgUserAddRequestContract, OrgUserAddResponseContract, OrgUserIdInPathRequired, OrgUserListResponseContract, OrgUserWorkspaceIdInPathRequired, OrgWorkspaceMemberListResponseContract, WorkspaceMemberRemoveResponseContract } from "../types";
|
|
8
|
+
import type { ClientAccountScheduledDeletionRequestContract, ClientAccountScheduledDeletionResponseContract, orgIdInPathRequired, OrgMemberExpectedJoinedAfterInQueryOptional, OrgMemberExpectedRoleInQueryOptional, OrgMemberRemoveResponseContract, OrgUserAddRequestContract, OrgUserAddResponseContract, OrgUserIdInPathRequired, OrgUserListResponseContract, OrgUserWorkspaceIdInPathRequired, OrgWorkspaceMemberListResponseContract, WorkspaceMemberRemoveResponseContract } from "../types";
|
|
9
9
|
export declare class OrgUsersApi {
|
|
10
10
|
private client;
|
|
11
11
|
constructor(client: Client);
|
|
@@ -54,13 +54,17 @@ export declare class OrgUsersApi {
|
|
|
54
54
|
}): Promise<OrgWorkspaceMemberListResponseContract>;
|
|
55
55
|
/**
|
|
56
56
|
* Remove organization member
|
|
57
|
-
* Removes an organization member by numeric userId. Gate resolves the internal orgMember.globalId before calling org-service, and org-service cleans up workspace/group memberships for that org. Requires org.members.write and org access.
|
|
57
|
+
* Removes an organization member by numeric userId. Gate resolves the internal orgMember.globalId before calling org-service, and org-service cleans up workspace/group memberships for that org. Optional query preconditions make the removal conditional instead of unconditional: `expectedRole` requires the member to still hold that org role, and `expectedJoinedAfter` (unix seconds) requires the membership to have been created at or after that moment — use it when cancelling an invite so a pre-existing member is never dropped. Either mismatch fails with 409 and removes nothing; a precondition sent with an empty or unparsable value fails with 400 rather than degrading into an unconditional removal. Requires org.members.write and org access.
|
|
58
58
|
*/
|
|
59
59
|
removeOrgMember(params: {
|
|
60
60
|
path: {
|
|
61
61
|
orgId: orgIdInPathRequired;
|
|
62
62
|
userId: OrgUserIdInPathRequired;
|
|
63
63
|
};
|
|
64
|
+
query?: {
|
|
65
|
+
expectedRole?: OrgMemberExpectedRoleInQueryOptional;
|
|
66
|
+
expectedJoinedAfter?: OrgMemberExpectedJoinedAfterInQueryOptional;
|
|
67
|
+
};
|
|
64
68
|
headers?: Record<string, string>;
|
|
65
69
|
}): Promise<OrgMemberRemoveResponseContract>;
|
|
66
70
|
/**
|
package/dist/apis/OrgUsersApi.js
CHANGED
|
@@ -70,13 +70,14 @@ class OrgUsersApi {
|
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Remove organization member
|
|
73
|
-
* Removes an organization member by numeric userId. Gate resolves the internal orgMember.globalId before calling org-service, and org-service cleans up workspace/group memberships for that org. Requires org.members.write and org access.
|
|
73
|
+
* Removes an organization member by numeric userId. Gate resolves the internal orgMember.globalId before calling org-service, and org-service cleans up workspace/group memberships for that org. Optional query preconditions make the removal conditional instead of unconditional: `expectedRole` requires the member to still hold that org role, and `expectedJoinedAfter` (unix seconds) requires the membership to have been created at or after that moment — use it when cancelling an invite so a pre-existing member is never dropped. Either mismatch fails with 409 and removes nothing; a precondition sent with an empty or unparsable value fails with 400 rather than degrading into an unconditional removal. Requires org.members.write and org access.
|
|
74
74
|
*/
|
|
75
75
|
async removeOrgMember(params) {
|
|
76
76
|
return this.client.request({
|
|
77
77
|
method: "DELETE",
|
|
78
78
|
path: "/:orgId/users/:userId",
|
|
79
79
|
pathParams: params.path,
|
|
80
|
+
query: params.query,
|
|
80
81
|
headers: params.headers,
|
|
81
82
|
opId: "removeOrgMember",
|
|
82
83
|
expectedContentType: "application/json",
|
|
@@ -37,6 +37,13 @@ export interface CallAppApiRequestContract {
|
|
|
37
37
|
path?: Record<string, string>;
|
|
38
38
|
query?: Record<string, string | number | boolean>;
|
|
39
39
|
body?: unknown;
|
|
40
|
+
/**
|
|
41
|
+
* On-behalf-of: a platform app token (`fbsfeaturetoken` / `x-app-feature-token`)
|
|
42
|
+
* identifying the end user this call runs for. Gate verifies it fail-closed and
|
|
43
|
+
* forwards the resolved user to the runtime as `X-Fusebase-Verified-User-*`
|
|
44
|
+
* headers; the calling identity still governs the operation's access policy.
|
|
45
|
+
*/
|
|
46
|
+
onBehalfOfUserToken?: string;
|
|
40
47
|
}
|
|
41
48
|
export interface CallAppApiResponseContract {
|
|
42
49
|
ok: boolean;
|
|
@@ -19,6 +19,18 @@ export interface CreateAppMagicLinkRequestContract {
|
|
|
19
19
|
* When false, the user must already exist or the call rejects with NotFound.
|
|
20
20
|
*/
|
|
21
21
|
addToAccessPrincipals?: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Optional link lifetime in seconds. Omit for the 24h (86400) default.
|
|
24
|
+
* A provided value is clamped server-side to the 3600 (1h)..604800 (7d)
|
|
25
|
+
* range rather than rejected, so a slightly out-of-range value still yields
|
|
26
|
+
* a usable link.
|
|
27
|
+
* `0` or a negative value is NOT "no expiry" and does NOT expire the link
|
|
28
|
+
* immediately — it clamps UP to the 3600 (1h) minimum, so 1h is the
|
|
29
|
+
* shortest lifetime you can create.
|
|
30
|
+
* Whole seconds: a fractional value is floored server-side.
|
|
31
|
+
* @TJS-type integer
|
|
32
|
+
*/
|
|
33
|
+
ttlSeconds?: number;
|
|
22
34
|
/**
|
|
23
35
|
* Opaque app payload (not interpreted by the platform) stored on the link and
|
|
24
36
|
* echoed back byte-for-byte at activation. Use it to bind the link to an
|
|
@@ -51,7 +63,8 @@ export interface CreateAppMagicLinkResponseContract {
|
|
|
51
63
|
*/
|
|
52
64
|
magicLinkUrl: string;
|
|
53
65
|
/**
|
|
54
|
-
* Unix timestamp (seconds) when the link expires (createdAt +
|
|
66
|
+
* Unix timestamp (seconds) when the link expires (createdAt + ttlSeconds,
|
|
67
|
+
* defaulting to 24h when ttlSeconds is omitted).
|
|
55
68
|
*/
|
|
56
69
|
expiresAt: number;
|
|
57
70
|
}
|
|
@@ -228,6 +241,17 @@ export interface BulkAppMagicLinkInvitationContract {
|
|
|
228
241
|
* When false, the user must already exist or the invite fails with NotFound.
|
|
229
242
|
*/
|
|
230
243
|
addToAccessPrincipals?: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Optional link lifetime in seconds. Omit for the 24h (86400) default.
|
|
246
|
+
* A provided value is clamped server-side to the 3600 (1h)..604800 (7d)
|
|
247
|
+
* range rather than rejected.
|
|
248
|
+
* `0` or a negative value is NOT "no expiry" and does NOT expire the link
|
|
249
|
+
* immediately — it clamps UP to the 3600 (1h) minimum, so 1h is the
|
|
250
|
+
* shortest lifetime you can create.
|
|
251
|
+
* Whole seconds: a fractional value is floored server-side.
|
|
252
|
+
* @TJS-type integer
|
|
253
|
+
*/
|
|
254
|
+
ttlSeconds?: number;
|
|
231
255
|
/**
|
|
232
256
|
* Opaque app payload (not interpreted by the platform) stored on the link and
|
|
233
257
|
* echoed back byte-for-byte at activation.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export * from "./mcp-manager/mcp-manager";
|
|
|
18
18
|
export type { MeAuthContract, MeOrgGroupContract, MePreferencesContract, MeResponseContract, MeScopeContract, MeUserContract } from "./me/me";
|
|
19
19
|
export * from "./note/note";
|
|
20
20
|
export * from "./org-group/org-group";
|
|
21
|
-
export type { ClientAccountScheduledDeletionRequestContract, ClientAccountScheduledDeletionResponseContract, CreateWorkspaceRequestContract, OrgInviteContract, OrgMagicLinkContract, OrgMemberRemoveResponseContract, OrgPortalContract, OrgPortalListResponseContract, OrgUserAddRequestContract, OrgUserAddResponseContract, OrgUserContract, OrgUserIdInPathRequired, OrgUserListResponseContract, OrgUserWorkspaceIdInPathRequired, OrgWorkspaceContract, OrgWorkspaceInviteContract, OrgWorkspaceListResponseContract, OrgWorkspaceMemberContract, OrgWorkspaceMemberListResponseContract, WorkspaceMemberRemoveResponseContract } from "./org-user/org-user";
|
|
21
|
+
export type { ClientAccountScheduledDeletionRequestContract, ClientAccountScheduledDeletionResponseContract, CreateWorkspaceRequestContract, OrgInviteContract, OrgMagicLinkContract, OrgMemberExpectedJoinedAfterInQueryOptional, OrgMemberExpectedRoleInQueryOptional, OrgMemberRemoveResponseContract, OrgPortalContract, OrgPortalListResponseContract, OrgUserAddRequestContract, OrgUserAddResponseContract, OrgUserContract, OrgUserIdInPathRequired, OrgUserListResponseContract, OrgUserWorkspaceIdInPathRequired, OrgWorkspaceContract, OrgWorkspaceInviteContract, OrgWorkspaceListResponseContract, OrgWorkspaceMemberContract, OrgWorkspaceMemberListResponseContract, WorkspaceMemberRemoveResponseContract } from "./org-user/org-user";
|
|
22
22
|
export * from "./orgs/orgs";
|
|
23
23
|
export type { VerifyPortalFeatureContextTokenRequestContract, VerifyPortalFeatureContextTokenResponseContract } from "./portal-feature-context/portal-feature-context";
|
|
24
24
|
export type { AddPortalAppPageRequestContract, AddPortalAppPageResponseContract, AddPortalBlockRequestContract, AddPortalBlockResponseContract, AddPortalNoteBlockRequestContract, AddPortalNoteBlockResponseContract, BulkInviteResultItemContract, BulkInviteToPortalRequestContract, BulkInviteToPortalResponseContract, BulkPortalInvitationContract, CreatePortalFolderRequestContract, CreatePortalFolderResponseContract, CreatePortalPageWithNoteRequestContract, CreatePortalPageWithNoteResponseContract, CreatePortalRequestContract, CreatePortalResponseContract, DuplicatePortalItemRequestContract, DuplicatePortalItemResponseContract, DuplicatePortalRequestContract, InvitePortalManagerRequestContract, InvitePortalManagerResponseContract, InviteToPortalRequestContract, InviteToPortalResponseContract, ListPortalContentResponseContract, PortalContentItemContract, PortalDetailContract, PublishPortalDraftResponseContract, UpdatePortalAccessRequestContract, UpdatePortalAccessResponseContract, UpdatePortalCustomCodeRequestContract, UpdatePortalCustomCodeResponseContract, globalIdInPathRequired } from "./portals/portals";
|
|
@@ -146,6 +146,17 @@ export interface OrgUserAddResponseContract {
|
|
|
146
146
|
workspaceMember?: OrgWorkspaceMemberContract;
|
|
147
147
|
magicLink?: OrgMagicLinkContract;
|
|
148
148
|
}
|
|
149
|
+
/**
|
|
150
|
+
* Optional CAS guard for removeOrgMember: the membership is only removed when
|
|
151
|
+
* its current org role still equals this value.
|
|
152
|
+
*/
|
|
153
|
+
export type OrgMemberExpectedRoleInQueryOptional = string;
|
|
154
|
+
/**
|
|
155
|
+
* Optional provenance guard for removeOrgMember (unix timestamp in seconds):
|
|
156
|
+
* the membership is only removed when it was created at or after this moment,
|
|
157
|
+
* so cancelling an invite can never drop a pre-existing member.
|
|
158
|
+
*/
|
|
159
|
+
export type OrgMemberExpectedJoinedAfterInQueryOptional = number;
|
|
149
160
|
export interface OrgMemberRemoveResponseContract {
|
|
150
161
|
ok: true;
|
|
151
162
|
userId: number;
|
package/package.json
CHANGED
package/release-notes/latest.md
CHANGED
|
@@ -1,82 +1,9 @@
|
|
|
1
|
-
# Release Notes 2.3.34-sdk.
|
|
1
|
+
# Release Notes 2.3.34-sdk.9
|
|
2
2
|
|
|
3
3
|
- Current ref: `HEAD`
|
|
4
|
-
- Previous tag: `v2.3.
|
|
5
|
-
- Generated at: 2026-07-
|
|
4
|
+
- Previous tag: `v2.3.34-sdk.9`
|
|
5
|
+
- Generated at: 2026-07-23T15:54:33.520Z
|
|
6
6
|
|
|
7
7
|
## Included Drafts
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
- `docs/release-notes/2026-07-13-getme-no-health-read.md` - getMe no longer requires health.read
|
|
11
|
-
|
|
12
|
-
## Summary
|
|
13
|
-
|
|
14
|
-
### Markdown (v3) notes CRUD
|
|
15
|
-
|
|
16
|
-
Add Gate contracts, controllers, and MCP-visible operations for v3 markdown notes: create, read, replace, and append markdown stored as the source of truth in note-service (no editor-service involved). Part of Notes v3 Iteration 1 (NIM-42034, NIM-42042).
|
|
17
|
-
|
|
18
|
-
### getMe no longer requires health.read
|
|
19
|
-
|
|
20
|
-
`GET /me` (`getMe`) no longer declares a required Gate permission. Any authenticated **user** or **token** subject may call it with a valid session, without `health.read` in the grant.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## API / SDK Changes
|
|
24
|
-
|
|
25
|
-
### Markdown (v3) notes CRUD
|
|
26
|
-
|
|
27
|
-
- Added `createWorkspaceMarkdownNote` (`POST /:orgId/workspaces/:workspaceId/markdown-notes`).
|
|
28
|
-
- Added `getWorkspaceMarkdownNote` (`GET .../markdown-notes/:noteId`) returning the markdown source of truth plus `revision`.
|
|
29
|
-
- Added `updateWorkspaceMarkdownNoteContent` (`PUT .../markdown-notes/:noteId/content`) replacing the full markdown document with a required optimistic `revision` lock.
|
|
30
|
-
- Added `appendWorkspaceMarkdownNoteContent` (`POST .../markdown-notes/:noteId/content/append`) with an optional `revision` lock.
|
|
31
|
-
- Stale-revision writes return HTTP 409 with `data.errorCode = markdown_note_revision_conflict` and `data.currentRevision`.
|
|
32
|
-
- Regenerated SDK/OpenAPI artifacts include the new Notes API methods and contracts.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## Consumer Impact
|
|
36
|
-
|
|
37
|
-
### Markdown (v3) notes CRUD
|
|
38
|
-
|
|
39
|
-
AI/MCP callers can manage markdown-native (v3) notes end-to-end without HTML conversion. Classic (v2) notes are untouched and keep using the existing notes operations. The operations depend on the note-service markdown API (NIM-42040/NIM-42041); until note-service ships it, calls fail upstream.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## Verification
|
|
43
|
-
|
|
44
|
-
### Markdown (v3) notes CRUD
|
|
45
|
-
|
|
46
|
-
- `npm run build`
|
|
47
|
-
- `npm run build:sdk`
|
|
48
|
-
- `npm run mcp:skills:generate`
|
|
49
|
-
- `npm run mcp:skills:validate`
|
|
50
|
-
- `npm test` (unit suites for the new controller, client, and contracts)
|
|
51
|
-
|
|
52
|
-
### getMe no longer requires health.read
|
|
53
|
-
|
|
54
|
-
- `npm run test:unit -- tests/unit/authz-op-registry-bridge.test.ts`
|
|
55
|
-
- `npm run build`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## Follow-ups
|
|
59
|
-
|
|
60
|
-
### Markdown (v3) notes CRUD
|
|
61
|
-
|
|
62
|
-
- Switch the plain-HTTP note-service markdown client to the generated `@internal/note-service` SDK once note-service publishes the markdown endpoints.
|
|
63
|
-
- Add e2e-sdk/mcp-e2e coverage once the note-service contract is live (fake-note-service markdown routes should mirror the real service).
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Consumer impact
|
|
67
|
-
|
|
68
|
-
### getMe no longer requires health.read
|
|
69
|
-
|
|
70
|
-
- **Apps without `health.read` in the published grant** can call `getMe` again (service tokens, visitor browser tokens).
|
|
71
|
-
- **Apps that already include `health.read`** are unchanged.
|
|
72
|
-
- Do **not** remove `health.read` from grants solely because of this change — other ops may still require it.
|
|
73
|
-
- Continue using `FBS_ORG_ID` / `getMyOrgAccess` for org resolution; do not rely on `getMe().auth.scopes` for visitor sessions.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
## Why
|
|
77
|
-
|
|
78
|
-
### getMe no longer requires health.read
|
|
79
|
-
|
|
80
|
-
- `getMe` is the primary identity introspection op for Fusebase Apps.
|
|
81
|
-
- Requiring `health.read` caused production lockouts when app grants omitted it after `fusebase analyze gate` / `--sync-gate-permissions` (see issue `041-benchmarking-app`, escalation `2026-07-13-platform-gate-2.3.29-auth-breaking-changes.md`).
|
|
82
|
-
- `resolveOperationPermissions` now reports `required_permission: null` for `getMe`, aligned with `getHealth`.
|
|
9
|
+
- None
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Release Notes 2.3.34-sdk.4
|
|
2
|
-
|
|
3
|
-
- Current ref: `HEAD`
|
|
4
|
-
- Previous tag: `v2.3.28-sdk.3`
|
|
5
|
-
- Generated at: 2026-07-23T05:48:58.238Z
|
|
6
|
-
|
|
7
|
-
## Included Drafts
|
|
8
|
-
|
|
9
|
-
- `docs/release-notes/2026-07-02-markdown-notes-crud.md` - Markdown (v3) notes CRUD
|
|
10
|
-
- `docs/release-notes/2026-07-13-getme-no-health-read.md` - getMe no longer requires health.read
|
|
11
|
-
|
|
12
|
-
## Summary
|
|
13
|
-
|
|
14
|
-
### Markdown (v3) notes CRUD
|
|
15
|
-
|
|
16
|
-
Add Gate contracts, controllers, and MCP-visible operations for v3 markdown notes: create, read, replace, and append markdown stored as the source of truth in note-service (no editor-service involved). Part of Notes v3 Iteration 1 (NIM-42034, NIM-42042).
|
|
17
|
-
|
|
18
|
-
### getMe no longer requires health.read
|
|
19
|
-
|
|
20
|
-
`GET /me` (`getMe`) no longer declares a required Gate permission. Any authenticated **user** or **token** subject may call it with a valid session, without `health.read` in the grant.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## API / SDK Changes
|
|
24
|
-
|
|
25
|
-
### Markdown (v3) notes CRUD
|
|
26
|
-
|
|
27
|
-
- Added `createWorkspaceMarkdownNote` (`POST /:orgId/workspaces/:workspaceId/markdown-notes`).
|
|
28
|
-
- Added `getWorkspaceMarkdownNote` (`GET .../markdown-notes/:noteId`) returning the markdown source of truth plus `revision`.
|
|
29
|
-
- Added `updateWorkspaceMarkdownNoteContent` (`PUT .../markdown-notes/:noteId/content`) replacing the full markdown document with a required optimistic `revision` lock.
|
|
30
|
-
- Added `appendWorkspaceMarkdownNoteContent` (`POST .../markdown-notes/:noteId/content/append`) with an optional `revision` lock.
|
|
31
|
-
- Stale-revision writes return HTTP 409 with `data.errorCode = markdown_note_revision_conflict` and `data.currentRevision`.
|
|
32
|
-
- Regenerated SDK/OpenAPI artifacts include the new Notes API methods and contracts.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
## Consumer Impact
|
|
36
|
-
|
|
37
|
-
### Markdown (v3) notes CRUD
|
|
38
|
-
|
|
39
|
-
AI/MCP callers can manage markdown-native (v3) notes end-to-end without HTML conversion. Classic (v2) notes are untouched and keep using the existing notes operations. The operations depend on the note-service markdown API (NIM-42040/NIM-42041); until note-service ships it, calls fail upstream.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
## Verification
|
|
43
|
-
|
|
44
|
-
### Markdown (v3) notes CRUD
|
|
45
|
-
|
|
46
|
-
- `npm run build`
|
|
47
|
-
- `npm run build:sdk`
|
|
48
|
-
- `npm run mcp:skills:generate`
|
|
49
|
-
- `npm run mcp:skills:validate`
|
|
50
|
-
- `npm test` (unit suites for the new controller, client, and contracts)
|
|
51
|
-
|
|
52
|
-
### getMe no longer requires health.read
|
|
53
|
-
|
|
54
|
-
- `npm run test:unit -- tests/unit/authz-op-registry-bridge.test.ts`
|
|
55
|
-
- `npm run build`
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
## Follow-ups
|
|
59
|
-
|
|
60
|
-
### Markdown (v3) notes CRUD
|
|
61
|
-
|
|
62
|
-
- Switch the plain-HTTP note-service markdown client to the generated `@internal/note-service` SDK once note-service publishes the markdown endpoints.
|
|
63
|
-
- Add e2e-sdk/mcp-e2e coverage once the note-service contract is live (fake-note-service markdown routes should mirror the real service).
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
## Consumer impact
|
|
67
|
-
|
|
68
|
-
### getMe no longer requires health.read
|
|
69
|
-
|
|
70
|
-
- **Apps without `health.read` in the published grant** can call `getMe` again (service tokens, visitor browser tokens).
|
|
71
|
-
- **Apps that already include `health.read`** are unchanged.
|
|
72
|
-
- Do **not** remove `health.read` from grants solely because of this change — other ops may still require it.
|
|
73
|
-
- Continue using `FBS_ORG_ID` / `getMyOrgAccess` for org resolution; do not rely on `getMe().auth.scopes` for visitor sessions.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
## Why
|
|
77
|
-
|
|
78
|
-
### getMe no longer requires health.read
|
|
79
|
-
|
|
80
|
-
- `getMe` is the primary identity introspection op for Fusebase Apps.
|
|
81
|
-
- Requiring `health.read` caused production lockouts when app grants omitted it after `fusebase analyze gate` / `--sync-gate-permissions` (see issue `041-benchmarking-app`, escalation `2026-07-13-platform-gate-2.3.29-auth-breaking-changes.md`).
|
|
82
|
-
- `resolveOperationPermissions` now reports `required_permission: null` for `getMe`, aligned with `getHealth`.
|