From a5a3d0bb22c1e04b45ff93c665f598534af5444c Mon Sep 17 00:00:00 2001 From: CodeMash Date: Fri, 23 Oct 2026 18:40:27 +0300 Subject: [PATCH 1/2] feat(templates): clone returns the new copy's id The clone hooks (useCloneEmailTemplateMutation, useCloneSmsTemplateMutation, useClonePushTemplateMutation) take their result type from @norbix.ai/ts, which answers IdResponse since 4.37.0 (was EmptyResponse): `data.id` is the new copy's id. @norbix.ai/ts raised to ^4.37.0 (dev) and >=4.37.0 (peer) so the hooks are typed with the id answer. Co-Authored-By: Claude Opus 5.5 --- package-lock.json | 10 ++--- package.json | 4 +- tests/template-clone.test.ts | 82 ++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 tests/template-clone.test.ts diff --git a/package-lock.json b/package-lock.json index aba1f7b..3081606 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@commitlint/cli": "^21.2.2", "@commitlint/config-conventional": "^21.2.2", "@eslint/js": "^10.0.1", - "@norbix.ai/ts": "^4.32.0", + "@norbix.ai/ts": "^4.37.0", "@reduxjs/toolkit": "^2.12.0", "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/github": "^12.0.9", @@ -45,7 +45,7 @@ "node": ">=18" }, "peerDependencies": { - "@norbix.ai/ts": ">=4.32.0", + "@norbix.ai/ts": ">=4.37.0", "@reduxjs/toolkit": ">=2.0.0", "react": ">=18.0.0", "react-redux": ">=9.0.0" @@ -1490,9 +1490,9 @@ } }, "node_modules/@norbix.ai/ts": { - "version": "4.32.0", - "resolved": "https://registry.npmjs.org/@norbix.ai/ts/-/ts-4.32.0.tgz", - "integrity": "sha512-6IVA8btojZtRsyTGSP1j87CD1n+w2kdzhLc9l8IkvpPu5qQUl7VLNSltjcQfXCoG+xX/6AbH/qZDLvXhYDkMcA==", + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/@norbix.ai/ts/-/ts-4.37.0.tgz", + "integrity": "sha512-pUsc0rc8UJBCg8/vLm926iepjDP0QsEiIfKPaJ31ZccyYbY+Wth5fPxQBiWQvuZpO34d9Pqxv0dq/znE54tvSw==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index c97e751..ae4a02f 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "prepublishOnly": "npm run build" }, "peerDependencies": { - "@norbix.ai/ts": ">=4.32.0", + "@norbix.ai/ts": ">=4.37.0", "@reduxjs/toolkit": ">=2.0.0", "react": ">=18.0.0", "react-redux": ">=9.0.0" @@ -68,7 +68,7 @@ "@commitlint/cli": "^21.2.2", "@commitlint/config-conventional": "^21.2.2", "@eslint/js": "^10.0.1", - "@norbix.ai/ts": "^4.32.0", + "@norbix.ai/ts": "^4.37.0", "@reduxjs/toolkit": "^2.12.0", "@semantic-release/commit-analyzer": "^13.0.1", "@semantic-release/github": "^12.0.9", diff --git a/tests/template-clone.test.ts b/tests/template-clone.test.ts new file mode 100644 index 0000000..0038150 --- /dev/null +++ b/tests/template-clone.test.ts @@ -0,0 +1,82 @@ +import { Norbix } from '@norbix.ai/ts'; +import type { CodeMashHub2 } from '@norbix.ai/ts/types/hub'; +import { describe, expect, expectTypeOf, it, vi } from 'vitest'; + +import { createNorbixBaseQuery } from '../src/baseQuery.js'; +import { hubNotifications } from '../src/hooks/hub/notifications.js'; +import type { Result } from '../src/hooks/types.js'; + +/** + * Template clone answers with the new copy's id (gateway 2026-10-23, + * @norbix.ai/ts 4.37.0: `IdResponse`, was `EmptyResponse`). The clone hooks + * hand that answer to the caller in `data`, so the dashboard can open the copy + * right away. Driven through the real `@norbix.ai/ts` client and this + * package's base query with a fake fetch — never a real server. + */ +type Def = { query: (args: unknown) => (norbix: unknown) => unknown }; + +function fakeBuilder() { + return { + query: (def: Record) => def, + mutation: (def: Record) => def, + } as never; +} + +const endpoints = hubNotifications(fakeBuilder()) as unknown as Record; + +type Notifications = Norbix['hub']['notifications']; + +function run(key: string, args: unknown, answer: unknown) { + type FetchFn = typeof globalThis.fetch; + const seen: Array<{ url: string; method: string }> = []; + const fetchImpl = vi.fn(async (...[input, init]: Parameters) => { + seen.push({ url: String(input), method: (init?.method ?? 'GET').toUpperCase() }); + return new globalThis.Response(JSON.stringify(answer), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + }) as unknown as FetchFn; + const norbix = new Norbix({ + bearerToken: 'test-token', + projectId: 'test-project', + hubVersion: 'v2', + baseUrl: { api: 'https://api.norbix.io', hub: 'https://hub.norbix.io' }, + fetch: fetchImpl, + }); + const baseQuery = createNorbixBaseQuery(() => norbix); + const result = baseQuery(endpoints[key]!.query(args) as never, {} as never, {}); + return { seen, result }; +} + +describe('template clone hooks return the new copy id', () => { + it('the clone hooks are typed with the id answer', () => { + expectTypeOf< + Result + >().toEqualTypeOf(); + expectTypeOf< + Result + >().toEqualTypeOf(); + expectTypeOf< + Result + >().toEqualTypeOf(); + }); + + it.each([ + ['cloneEmailTemplate', 'email'], + ['cloneSmsTemplate', 'sms'], + ['clonePushTemplate', 'push'], + ])('%s puts the copy id in data', async (key, channel) => { + const { seen, result } = run(key, { id: 'tpl_1' }, { id: `${channel}_copy` }); + + const out = (await result) as { data?: CodeMashHub2.IdResponse; error?: unknown }; + + expect(out.error).toBeUndefined(); + expect(seen).toEqual([ + { + method: 'POST', + url: `https://hub.norbix.io/v2/notifications/${channel}/templates/tpl_1/clone`, + }, + ]); + expect(out.data?.id).toBe(`${channel}_copy`); + }); +}); From 29831868151cf1686ba9ec2d4dabb43dce9cd8eb Mon Sep 17 00:00:00 2001 From: CodeMash Date: Fri, 23 Oct 2026 18:42:31 +0300 Subject: [PATCH 2/2] chore(security): ignore GHSA-rxp7-6hxx-x8q5, ip-address bundled inside npm like its siblings Same as sdk-ts 96936c5: ip-address 10.5.0 comes only from the npm CLI that @semantic-release/npm bundles; overrides cannot reach it. Dev-only. Co-Authored-By: Claude Opus 5.5 --- osv-scanner.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osv-scanner.toml b/osv-scanner.toml index be5bf4d..be2283f 100644 --- a/osv-scanner.toml +++ b/osv-scanner.toml @@ -68,3 +68,8 @@ reason = "dev-only: bundled inside the npm CLI that @semantic-release/npm runs a id = "GHSA-rj75-hqrm-r3gf" # postcss-selector-parser 7.1.4 (npm bundle) ignoreUntil = 2026-11-03 reason = "dev-only: bundled inside the npm CLI that @semantic-release/npm runs at release time; the latest npm 11 (11.21.0) still bundles 7.1.4 and overrides cannot change bundled packages. Not part of the published package." + +[[IgnoredVulns]] +id = "GHSA-rxp7-6hxx-x8q5" +ignoreUntil = 2027-01-04T00:00:00Z +reason = "ip-address 10.5.0 is bundled inside the npm package (node_modules/npm, inBundle) that the release tooling (semantic-release) installs; npm overrides cannot reach bundled files and the latest npm still bundles this version. Dev-only, never shipped in @norbix.ai/react-redux. Same decision as sdk-ts 96936c5."