@fusebase/fusebase-gate-sdk 2.2.2-sdk.1 → 2.2.2-sdk.3

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.
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Access API
3
+ *
4
+ * Generated from contract introspection
5
+ * Domain: access
6
+ */
7
+ import type { Client } from "../runtime/transport";
8
+ import type { MyOrgAccessResponseContract, orgIdInPathRequired } from "../types";
9
+ export declare class AccessApi {
10
+ private client;
11
+ constructor(client: Client);
12
+ /**
13
+ * Get current user's organization access status
14
+ * Returns the authenticated user's access status for the specified organization. Unlike org-scoped read endpoints, this route is available before membership exists so clients can distinguish authenticated-but-not-provisioned users from signed-out users.
15
+ */
16
+ getMyOrgAccess(params: {
17
+ path: {
18
+ orgId: orgIdInPathRequired;
19
+ };
20
+ headers?: Record<string, string>;
21
+ }): Promise<MyOrgAccessResponseContract>;
22
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * Access API
4
+ *
5
+ * Generated from contract introspection
6
+ * Domain: access
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.AccessApi = void 0;
10
+ class AccessApi {
11
+ constructor(client) {
12
+ this.client = client;
13
+ }
14
+ /**
15
+ * Get current user's organization access status
16
+ * Returns the authenticated user's access status for the specified organization. Unlike org-scoped read endpoints, this route is available before membership exists so clients can distinguish authenticated-but-not-provisioned users from signed-out users.
17
+ */
18
+ async getMyOrgAccess(params) {
19
+ return this.client.request({
20
+ method: "GET",
21
+ path: "/:orgId/me/access",
22
+ pathParams: params.path,
23
+ headers: params.headers,
24
+ opId: "getMyOrgAccess",
25
+ expectedContentType: "application/json",
26
+ });
27
+ }
28
+ }
29
+ exports.AccessApi = AccessApi;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Notes API
3
+ *
4
+ * Generated from contract introspection
5
+ * Domain: notes
6
+ */
7
+ import type { Client } from "../runtime/transport";
8
+ import type { CreateWorkspaceNoteFolderRequestContract, CreateWorkspaceNoteFolderResponseContract, CreateWorkspaceNoteRequestContract, CreateWorkspaceNoteResponseContract, orgIdInPathRequired, WorkspaceIdInPathRequired, WorkspaceNoteContentResponseContract, WorkspaceNoteFolderListResponseContract, WorkspaceNoteIdInPathRequired, WorkspaceNoteListResponseContract, WorkspaceNoteParentIdInQueryOptional } from "../types";
9
+ export declare class NotesApi {
10
+ private client;
11
+ constructor(client: Client);
12
+ /**
13
+ * Create workspace note
14
+ * Creates a note in the requested workspace. When parentId is omitted, gate uses `default`. Optional initial text or html can be appended after creation.
15
+ */
16
+ createWorkspaceNote(params: {
17
+ path: {
18
+ orgId: orgIdInPathRequired;
19
+ workspaceId: WorkspaceIdInPathRequired;
20
+ };
21
+ headers?: Record<string, string>;
22
+ body: CreateWorkspaceNoteRequestContract;
23
+ }): Promise<CreateWorkspaceNoteResponseContract>;
24
+ /**
25
+ * Create workspace note folder
26
+ * Creates a folder in the requested workspace. When parentId is omitted, gate uses `root`.
27
+ */
28
+ createWorkspaceNoteFolder(params: {
29
+ path: {
30
+ orgId: orgIdInPathRequired;
31
+ workspaceId: WorkspaceIdInPathRequired;
32
+ };
33
+ headers?: Record<string, string>;
34
+ body: CreateWorkspaceNoteFolderRequestContract;
35
+ }): Promise<CreateWorkspaceNoteFolderResponseContract>;
36
+ /**
37
+ * Read workspace note
38
+ * Returns the note title, parent metadata, and rendered html content for the requested workspace note.
39
+ */
40
+ getWorkspaceNote(params: {
41
+ path: {
42
+ orgId: orgIdInPathRequired;
43
+ workspaceId: WorkspaceIdInPathRequired;
44
+ noteId: WorkspaceNoteIdInPathRequired;
45
+ };
46
+ headers?: Record<string, string>;
47
+ }): Promise<WorkspaceNoteContentResponseContract>;
48
+ /**
49
+ * List workspace note folders
50
+ * Returns non-portal note folders for the requested workspace.
51
+ */
52
+ listWorkspaceNoteFolders(params: {
53
+ path: {
54
+ orgId: orgIdInPathRequired;
55
+ workspaceId: WorkspaceIdInPathRequired;
56
+ };
57
+ headers?: Record<string, string>;
58
+ }): Promise<WorkspaceNoteFolderListResponseContract>;
59
+ /**
60
+ * List workspace notes
61
+ * Returns non-portal notes for the requested workspace and parent folder. When parentId is omitted, gate defaults to the workspace root folder id `root`.
62
+ */
63
+ listWorkspaceNotes(params: {
64
+ path: {
65
+ orgId: orgIdInPathRequired;
66
+ workspaceId: WorkspaceIdInPathRequired;
67
+ };
68
+ query?: {
69
+ parentId?: WorkspaceNoteParentIdInQueryOptional;
70
+ };
71
+ headers?: Record<string, string>;
72
+ }): Promise<WorkspaceNoteListResponseContract>;
73
+ }
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ /**
3
+ * Notes API
4
+ *
5
+ * Generated from contract introspection
6
+ * Domain: notes
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.NotesApi = void 0;
10
+ class NotesApi {
11
+ constructor(client) {
12
+ this.client = client;
13
+ }
14
+ /**
15
+ * Create workspace note
16
+ * Creates a note in the requested workspace. When parentId is omitted, gate uses `default`. Optional initial text or html can be appended after creation.
17
+ */
18
+ async createWorkspaceNote(params) {
19
+ return this.client.request({
20
+ method: "POST",
21
+ path: "/:orgId/workspaces/:workspaceId/notes",
22
+ pathParams: params.path,
23
+ headers: params.headers,
24
+ body: params.body,
25
+ opId: "createWorkspaceNote",
26
+ expectedContentType: "application/json",
27
+ });
28
+ }
29
+ /**
30
+ * Create workspace note folder
31
+ * Creates a folder in the requested workspace. When parentId is omitted, gate uses `root`.
32
+ */
33
+ async createWorkspaceNoteFolder(params) {
34
+ return this.client.request({
35
+ method: "POST",
36
+ path: "/:orgId/workspaces/:workspaceId/notes/folders",
37
+ pathParams: params.path,
38
+ headers: params.headers,
39
+ body: params.body,
40
+ opId: "createWorkspaceNoteFolder",
41
+ expectedContentType: "application/json",
42
+ });
43
+ }
44
+ /**
45
+ * Read workspace note
46
+ * Returns the note title, parent metadata, and rendered html content for the requested workspace note.
47
+ */
48
+ async getWorkspaceNote(params) {
49
+ return this.client.request({
50
+ method: "GET",
51
+ path: "/:orgId/workspaces/:workspaceId/notes/:noteId",
52
+ pathParams: params.path,
53
+ headers: params.headers,
54
+ opId: "getWorkspaceNote",
55
+ expectedContentType: "application/json",
56
+ });
57
+ }
58
+ /**
59
+ * List workspace note folders
60
+ * Returns non-portal note folders for the requested workspace.
61
+ */
62
+ async listWorkspaceNoteFolders(params) {
63
+ return this.client.request({
64
+ method: "GET",
65
+ path: "/:orgId/workspaces/:workspaceId/notes/folders",
66
+ pathParams: params.path,
67
+ headers: params.headers,
68
+ opId: "listWorkspaceNoteFolders",
69
+ expectedContentType: "application/json",
70
+ });
71
+ }
72
+ /**
73
+ * List workspace notes
74
+ * Returns non-portal notes for the requested workspace and parent folder. When parentId is omitted, gate defaults to the workspace root folder id `root`.
75
+ */
76
+ async listWorkspaceNotes(params) {
77
+ return this.client.request({
78
+ method: "GET",
79
+ path: "/:orgId/workspaces/:workspaceId/notes",
80
+ pathParams: params.path,
81
+ query: params.query,
82
+ headers: params.headers,
83
+ opId: "listWorkspaceNotes",
84
+ expectedContentType: "application/json",
85
+ });
86
+ }
87
+ }
88
+ exports.NotesApi = NotesApi;
package/dist/index.d.ts CHANGED
@@ -5,8 +5,10 @@
5
5
  */
6
6
  export * from "./runtime";
7
7
  export * from "./types";
8
+ export { AccessApi } from "./apis/AccessApi";
8
9
  export { EmailsApi } from "./apis/EmailsApi";
9
10
  export { HealthApi } from "./apis/HealthApi";
11
+ export { NotesApi } from "./apis/NotesApi";
10
12
  export { OrgUsersApi } from "./apis/OrgUsersApi";
11
13
  export { PortalsApi } from "./apis/PortalsApi";
12
14
  export { SystemApi } from "./apis/SystemApi";
package/dist/index.js CHANGED
@@ -19,13 +19,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
19
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
20
  };
21
21
  Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.WorkspacesApi = exports.TokensApi = exports.SystemApi = exports.PortalsApi = exports.OrgUsersApi = exports.HealthApi = exports.EmailsApi = void 0;
22
+ exports.WorkspacesApi = exports.TokensApi = exports.SystemApi = exports.PortalsApi = exports.OrgUsersApi = exports.NotesApi = exports.HealthApi = exports.EmailsApi = exports.AccessApi = void 0;
23
23
  __exportStar(require("./runtime"), exports);
24
24
  __exportStar(require("./types"), exports);
25
+ var AccessApi_1 = require("./apis/AccessApi");
26
+ Object.defineProperty(exports, "AccessApi", { enumerable: true, get: function () { return AccessApi_1.AccessApi; } });
25
27
  var EmailsApi_1 = require("./apis/EmailsApi");
26
28
  Object.defineProperty(exports, "EmailsApi", { enumerable: true, get: function () { return EmailsApi_1.EmailsApi; } });
27
29
  var HealthApi_1 = require("./apis/HealthApi");
28
30
  Object.defineProperty(exports, "HealthApi", { enumerable: true, get: function () { return HealthApi_1.HealthApi; } });
31
+ var NotesApi_1 = require("./apis/NotesApi");
32
+ Object.defineProperty(exports, "NotesApi", { enumerable: true, get: function () { return NotesApi_1.NotesApi; } });
29
33
  var OrgUsersApi_1 = require("./apis/OrgUsersApi");
30
34
  Object.defineProperty(exports, "OrgUsersApi", { enumerable: true, get: function () { return OrgUsersApi_1.OrgUsersApi; } });
31
35
  var PortalsApi_1 = require("./apis/PortalsApi");
@@ -0,0 +1,19 @@
1
+ export type OrgMembershipStatus = "ready" | "none" | "expired" | "disabled";
2
+ export type OrgAccessSource = "owner" | "member" | "none";
3
+ export interface AuthenticatedUserSummaryContract {
4
+ id: number;
5
+ email?: string | null;
6
+ firstname?: string | null;
7
+ lastname?: string | null;
8
+ }
9
+ export interface MyOrgAccessResponseContract {
10
+ authenticated: true;
11
+ orgId: string;
12
+ hasOrgAccess: boolean;
13
+ membershipStatus: OrgMembershipStatus;
14
+ source: OrgAccessSource;
15
+ role?: string | null;
16
+ expiresAt?: number | null;
17
+ memberTTL?: number | null;
18
+ user: AuthenticatedUserSummaryContract;
19
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -4,7 +4,9 @@
4
4
  * Re-exports all Contract types used by the SDK
5
5
  * Generated by SDK codegen
6
6
  */
7
+ export type { AuthenticatedUserSummaryContract, MyOrgAccessResponseContract } from "./access/access";
7
8
  export type { OrgEmailSendRequestContract, OrgEmailSendResponseContract } from "./email/email";
9
+ export * from "./note/note";
8
10
  export type { OrgInviteContract, OrgMagicLinkContract, OrgPortalContract, OrgPortalListResponseContract, OrgUserAddRequestContract, OrgUserAddResponseContract, OrgUserContract, OrgUserListResponseContract, OrgWorkspaceContract, OrgWorkspaceInviteContract, OrgWorkspaceListResponseContract, OrgWorkspaceMemberContract } from "./org-user/org-user";
9
11
  export * from "./shared/common";
10
12
  export * from "./shared/enums";
@@ -20,6 +20,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
+ __exportStar(require("./note/note"), exports);
23
24
  __exportStar(require("./shared/common"), exports);
24
25
  __exportStar(require("./shared/enums"), exports);
25
26
  __exportStar(require("./system/system"), exports);
@@ -0,0 +1,59 @@
1
+ export type WorkspaceIdInPathRequired = string;
2
+ export type WorkspaceNoteIdInPathRequired = string;
3
+ export interface WorkspaceNoteSummaryContract {
4
+ globalId: string;
5
+ title?: string | null;
6
+ parentId?: string | null;
7
+ }
8
+ export interface WorkspaceNoteContentContract extends WorkspaceNoteSummaryContract {
9
+ html: string;
10
+ }
11
+ export interface WorkspaceNoteFolderListResponseContract {
12
+ folders: WorkspaceNoteSummaryContract[];
13
+ }
14
+ export interface WorkspaceNoteListResponseContract {
15
+ notes: WorkspaceNoteSummaryContract[];
16
+ }
17
+ export interface WorkspaceNoteContentResponseContract {
18
+ note: WorkspaceNoteContentContract;
19
+ }
20
+ export type WorkspaceNoteParentIdInQueryOptional = string | null;
21
+ export type WorkspaceNoteContentFormatContract = "text" | "html";
22
+ export interface WorkspaceNoteListQueryContract {
23
+ /**
24
+ * Folder global id to list notes from. When omitted, gate defaults to `root`.
25
+ */
26
+ parentId?: WorkspaceNoteParentIdInQueryOptional;
27
+ }
28
+ export interface CreateWorkspaceNoteFolderRequestContract {
29
+ title: string;
30
+ /**
31
+ * Parent folder global id. Defaults to `root`.
32
+ */
33
+ parentId?: string | null;
34
+ }
35
+ export interface CreateWorkspaceNoteFolderResponseContract {
36
+ folder: WorkspaceNoteSummaryContract;
37
+ }
38
+ export interface CreateWorkspaceNoteRequestContract {
39
+ title: string;
40
+ /**
41
+ * Parent folder global id. Defaults to `default`.
42
+ */
43
+ parentId?: string | null;
44
+ /**
45
+ * Optional initial text or html appended to the note after creation.
46
+ */
47
+ content?: string | null;
48
+ /**
49
+ * Content format used with `content`. Defaults to `text`.
50
+ */
51
+ format?: WorkspaceNoteContentFormatContract | null;
52
+ }
53
+ export interface CreateWorkspaceNoteResponseContract {
54
+ note: WorkspaceNoteSummaryContract;
55
+ }
56
+ export declare const WorkspaceNoteContentFormatContract: {
57
+ readonly Text: "text";
58
+ readonly Html: "html";
59
+ };
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkspaceNoteContentFormatContract = void 0;
4
+ exports.WorkspaceNoteContentFormatContract = {
5
+ Text: "text",
6
+ Html: "html"
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fusebase/fusebase-gate-sdk",
3
- "version": "2.2.2-sdk.1",
3
+ "version": "2.2.2-sdk.3",
4
4
  "description": "TypeScript SDK for Fusebase Gate APIs - Generated from contract introspection",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,85 @@
1
+ # Release Notes 2.2.2-sdk.3
2
+
3
+ - Current ref: `HEAD`
4
+ - Previous tag: `v2.2.2-sdk.2`
5
+ - Generated at: 2026-03-30T12:29:12.945Z
6
+
7
+ ## Included Drafts
8
+
9
+ - `docs/release-notes/2026-03-30-notes-list-ops.md` - 2026-03-30-notes-list-ops
10
+ - `docs/release-notes/2026-03-30-notes-mcp-opaque-ids.md` - 2026-03-30-notes-mcp-opaque-ids
11
+
12
+ ## Summary
13
+
14
+ ### 2026-03-30-notes-list-ops
15
+
16
+ Add Gate notes read and write endpoints for listing, reading, and creating workspace notes and folders.
17
+
18
+ ### 2026-03-30-notes-mcp-opaque-ids
19
+
20
+ Notes notes-tool validation and HTTP routing now match the note-service behavior more closely: MCP no longer treats note-service IDs as UUIDs, and the HTTP/SDK notes folder listing route no longer gets shadowed by the generic note-read route.
21
+
22
+
23
+ ## API / SDK Changes
24
+
25
+ ### 2026-03-30-notes-list-ops
26
+
27
+ - Added `listWorkspaceNoteFolders` for `GET /:orgId/workspaces/:workspaceId/notes/folders`.
28
+ - Added `listWorkspaceNotes` for `GET /:orgId/workspaces/:workspaceId/notes`.
29
+ - Added `getWorkspaceNote` for `GET /:orgId/workspaces/:workspaceId/notes/:noteId`.
30
+ - Added `createWorkspaceNoteFolder` for `POST /:orgId/workspaces/:workspaceId/notes/folders`.
31
+ - Added `createWorkspaceNote` for `POST /:orgId/workspaces/:workspaceId/notes`.
32
+ - Added the `notes.read` and `notes.write` service permissions for the new note operations.
33
+
34
+ ### 2026-03-30-notes-mcp-opaque-ids
35
+
36
+ - MCP notes tools no longer require UUID-formatted values for note-service IDs.
37
+ - `GET /:orgId/workspaces/:workspaceId/notes/folders` now resolves to the folder-list operation instead of being captured by `/:noteId`.
38
+ - Service runtime schema registration now overlays explicit opaque-string schemas for notes path/query params.
39
+
40
+
41
+ ## Consumer Impact
42
+
43
+ ### 2026-03-30-notes-list-ops
44
+
45
+ - Consumers can now discover workspace note folders, fetch notes under a specific folder, read rendered html for a single note, and create folders or notes through Gate.
46
+ - `listWorkspaceNotes` defaults to the workspace root when `parentId` is omitted.
47
+ - `createWorkspaceNoteFolder` defaults `parentId` to `root`.
48
+ - `createWorkspaceNote` defaults `parentId` to `default` and can append initial text or html content after creation.
49
+
50
+ ### 2026-03-30-notes-mcp-opaque-ids
51
+
52
+ - MCP consumers can pass real note-service IDs like `workspace-default-1` or `folder-projects-1` without hitting `INVALID_ARGS` UUID validation failures.
53
+ - SDK and raw HTTP consumers can call the notes folder-list endpoint without it being misrouted into note-content fetching.
54
+ - Notes E2E suites now reset fake note fixtures between tests so SDK/MCP coverage stays order-independent.
55
+
56
+
57
+ ## Verification
58
+
59
+ ### 2026-03-30-notes-list-ops
60
+
61
+ - `npm run build`
62
+ - `node --loader tsx scripts/build-sdk.mts`
63
+ - `node --loader tsx scripts/generate-mcp-skills.mts`
64
+ - `node --loader tsx scripts/validate-mcp-skills.mts`
65
+
66
+ ### 2026-03-30-notes-mcp-opaque-ids
67
+
68
+ - `npm run lint -- src/api/contracts/ops/notes/notes.ts src/api/contracts/schemas/runtime-schema-defs.ts src/api/contracts/schemas/runtime-schema-overrides.ts tests/unit/notes-contracts.test.ts tests/unit/notes-controller.test.ts`
69
+ - `npm run test:unit -- --runTestsByPath tests/unit/notes-contracts.test.ts tests/unit/notes-controller.test.ts`
70
+ - `npm run lint -- src/controllers/notes/notes.ts tests/helpers/fake-notes-store.ts tests/helpers/fake-note-service.ts tests/helpers/reset-fake-notes.ts tests/e2e-sdk/notes/0.list-workspace-notes.test.ts tests/e2e-sdk/notes/1.get-workspace-note.test.ts tests/e2e-sdk/notes/2.create-workspace-note.test.ts tests/mcp-e2e/notes/0.list-workspace-notes.test.ts tests/mcp-e2e/notes/1.get-workspace-note.test.ts tests/mcp-e2e/notes/2.create-workspace-note.test.ts tests/unit/notes-controller.test.ts tests/unit/notes-contracts.test.ts tests/unit/notes-routes.test.ts`
71
+ - `npm run test:unit -- --runTestsByPath tests/unit/notes-controller.test.ts tests/unit/notes-contracts.test.ts tests/unit/notes-routes.test.ts`
72
+ - `npm run mcp:skills:generate`
73
+ - `npm run mcp:skills:validate`
74
+ - Blocked locally: `env USE_BUILD_ARTIFACT=true npm run test:mcp-e2e:full` failed because `db:migrate:test` could not connect to MySQL at `localhost:3306`
75
+
76
+
77
+ ## Follow-ups
78
+
79
+ ### 2026-03-30-notes-list-ops
80
+
81
+ - Confirm whether client and visitor roles should receive `notes.read` or `notes.write` in read-only org contexts.
82
+
83
+ ### 2026-03-30-notes-mcp-opaque-ids
84
+
85
+ - Re-run the MCP E2E suite in CI or an environment with the test MySQL instance available to confirm the notes MCP failures are resolved end to end.
@@ -1,9 +1,85 @@
1
- # Release Notes 2.2.2-sdk.1
1
+ # Release Notes 2.2.2-sdk.3
2
2
 
3
3
  - Current ref: `HEAD`
4
- - Previous tag: `v2.2.2-sdk.1`
5
- - Generated at: 2026-03-27T16:03:26.172Z
4
+ - Previous tag: `v2.2.2-sdk.2`
5
+ - Generated at: 2026-03-30T12:29:12.945Z
6
6
 
7
7
  ## Included Drafts
8
8
 
9
- - None
9
+ - `docs/release-notes/2026-03-30-notes-list-ops.md` - 2026-03-30-notes-list-ops
10
+ - `docs/release-notes/2026-03-30-notes-mcp-opaque-ids.md` - 2026-03-30-notes-mcp-opaque-ids
11
+
12
+ ## Summary
13
+
14
+ ### 2026-03-30-notes-list-ops
15
+
16
+ Add Gate notes read and write endpoints for listing, reading, and creating workspace notes and folders.
17
+
18
+ ### 2026-03-30-notes-mcp-opaque-ids
19
+
20
+ Notes notes-tool validation and HTTP routing now match the note-service behavior more closely: MCP no longer treats note-service IDs as UUIDs, and the HTTP/SDK notes folder listing route no longer gets shadowed by the generic note-read route.
21
+
22
+
23
+ ## API / SDK Changes
24
+
25
+ ### 2026-03-30-notes-list-ops
26
+
27
+ - Added `listWorkspaceNoteFolders` for `GET /:orgId/workspaces/:workspaceId/notes/folders`.
28
+ - Added `listWorkspaceNotes` for `GET /:orgId/workspaces/:workspaceId/notes`.
29
+ - Added `getWorkspaceNote` for `GET /:orgId/workspaces/:workspaceId/notes/:noteId`.
30
+ - Added `createWorkspaceNoteFolder` for `POST /:orgId/workspaces/:workspaceId/notes/folders`.
31
+ - Added `createWorkspaceNote` for `POST /:orgId/workspaces/:workspaceId/notes`.
32
+ - Added the `notes.read` and `notes.write` service permissions for the new note operations.
33
+
34
+ ### 2026-03-30-notes-mcp-opaque-ids
35
+
36
+ - MCP notes tools no longer require UUID-formatted values for note-service IDs.
37
+ - `GET /:orgId/workspaces/:workspaceId/notes/folders` now resolves to the folder-list operation instead of being captured by `/:noteId`.
38
+ - Service runtime schema registration now overlays explicit opaque-string schemas for notes path/query params.
39
+
40
+
41
+ ## Consumer Impact
42
+
43
+ ### 2026-03-30-notes-list-ops
44
+
45
+ - Consumers can now discover workspace note folders, fetch notes under a specific folder, read rendered html for a single note, and create folders or notes through Gate.
46
+ - `listWorkspaceNotes` defaults to the workspace root when `parentId` is omitted.
47
+ - `createWorkspaceNoteFolder` defaults `parentId` to `root`.
48
+ - `createWorkspaceNote` defaults `parentId` to `default` and can append initial text or html content after creation.
49
+
50
+ ### 2026-03-30-notes-mcp-opaque-ids
51
+
52
+ - MCP consumers can pass real note-service IDs like `workspace-default-1` or `folder-projects-1` without hitting `INVALID_ARGS` UUID validation failures.
53
+ - SDK and raw HTTP consumers can call the notes folder-list endpoint without it being misrouted into note-content fetching.
54
+ - Notes E2E suites now reset fake note fixtures between tests so SDK/MCP coverage stays order-independent.
55
+
56
+
57
+ ## Verification
58
+
59
+ ### 2026-03-30-notes-list-ops
60
+
61
+ - `npm run build`
62
+ - `node --loader tsx scripts/build-sdk.mts`
63
+ - `node --loader tsx scripts/generate-mcp-skills.mts`
64
+ - `node --loader tsx scripts/validate-mcp-skills.mts`
65
+
66
+ ### 2026-03-30-notes-mcp-opaque-ids
67
+
68
+ - `npm run lint -- src/api/contracts/ops/notes/notes.ts src/api/contracts/schemas/runtime-schema-defs.ts src/api/contracts/schemas/runtime-schema-overrides.ts tests/unit/notes-contracts.test.ts tests/unit/notes-controller.test.ts`
69
+ - `npm run test:unit -- --runTestsByPath tests/unit/notes-contracts.test.ts tests/unit/notes-controller.test.ts`
70
+ - `npm run lint -- src/controllers/notes/notes.ts tests/helpers/fake-notes-store.ts tests/helpers/fake-note-service.ts tests/helpers/reset-fake-notes.ts tests/e2e-sdk/notes/0.list-workspace-notes.test.ts tests/e2e-sdk/notes/1.get-workspace-note.test.ts tests/e2e-sdk/notes/2.create-workspace-note.test.ts tests/mcp-e2e/notes/0.list-workspace-notes.test.ts tests/mcp-e2e/notes/1.get-workspace-note.test.ts tests/mcp-e2e/notes/2.create-workspace-note.test.ts tests/unit/notes-controller.test.ts tests/unit/notes-contracts.test.ts tests/unit/notes-routes.test.ts`
71
+ - `npm run test:unit -- --runTestsByPath tests/unit/notes-controller.test.ts tests/unit/notes-contracts.test.ts tests/unit/notes-routes.test.ts`
72
+ - `npm run mcp:skills:generate`
73
+ - `npm run mcp:skills:validate`
74
+ - Blocked locally: `env USE_BUILD_ARTIFACT=true npm run test:mcp-e2e:full` failed because `db:migrate:test` could not connect to MySQL at `localhost:3306`
75
+
76
+
77
+ ## Follow-ups
78
+
79
+ ### 2026-03-30-notes-list-ops
80
+
81
+ - Confirm whether client and visitor roles should receive `notes.read` or `notes.write` in read-only org contexts.
82
+
83
+ ### 2026-03-30-notes-mcp-opaque-ids
84
+
85
+ - Re-run the MCP E2E suite in CI or an environment with the test MySQL instance available to confirm the notes MCP failures are resolved end to end.
@@ -1,9 +0,0 @@
1
- # Release Notes 2.2.2-sdk.1
2
-
3
- - Current ref: `HEAD`
4
- - Previous tag: `v2.2.2-sdk.1`
5
- - Generated at: 2026-03-27T16:03:26.172Z
6
-
7
- ## Included Drafts
8
-
9
- - None