From e79abec75296ab8068e615e0537d19b11a531a51 Mon Sep 17 00:00:00 2001 From: RelayFile Adapters Bot Date: Sun, 26 Apr 2026 20:38:22 +0200 Subject: [PATCH 1/2] feat(adapter-notion): extract canonical Notion query helpers Tracks relayfile-adapters#24 - one canonical home for Notion API request knowledge so cloud route.ts, cloud api fallback, and sage nango-integrations syncs all consume the same operation builders instead of holding duplicate request-shape logic. New exports under @relayfile/adapter-notion: - searchPages(), searchDatabases(), queryDatabase() - getPage(), getBlockChildren() - buildDatabaseFilter() for Notion database query filters - Response types for Notion list, page, database, block, and generic objects Operation payloads are the UNION of what cloud + sage consumers need. Validated against: 1. Nango integration-templates for Notion (canonical baseline) 2. sage nango-integrations/notion-sage/syncs/*.ts (production-proven) 3. cloud packages/web/app/api/v1/notion/query/route.ts + api fallback Live verification: Search helpers were POSTed through the real Nango proxy using sage NANGO_SECRET_KEY, with connection IDs dynamically discovered via nango.listConnections(). Optional env-provided page/database/block IDs verify the ID-specific helpers when available. Version: minor bump (additive - new exports, no breaking changes). Follow-up PRs (tracked in relayfile-adapters#24): - cloud refactor: import from @relayfile/adapter-notion, drop local copies - sage refactor: same for nango-integrations/notion-sage/syncs/* Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 16 +- packages/notion/src/__tests__/queries.test.ts | 232 +++++++++++ packages/notion/src/index.ts | 18 + packages/notion/src/queries.ts | 381 ++++++++++++++++++ 4 files changed, 639 insertions(+), 8 deletions(-) create mode 100644 packages/notion/src/__tests__/queries.test.ts create mode 100644 packages/notion/src/queries.ts diff --git a/package-lock.json b/package-lock.json index caf9db5..3d6742d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2927,7 +2927,7 @@ }, "packages/core": { "name": "@relayfile/adapter-core", - "version": "0.1.1", + "version": "0.1.4", "license": "MIT", "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", @@ -2954,10 +2954,10 @@ }, "packages/github": { "name": "@relayfile/adapter-github", - "version": "0.1.1", + "version": "0.1.4", "license": "MIT", "dependencies": { - "@relayfile/adapter-core": "file:../core" + "@relayfile/adapter-core": "^0.1.1" }, "devDependencies": { "@relayfile/sdk": "^0.1.7", @@ -2974,7 +2974,7 @@ }, "packages/gitlab": { "name": "@relayfile/adapter-gitlab", - "version": "0.1.1", + "version": "0.1.4", "license": "MIT", "dependencies": { "@relayfile/sdk": "^0.1.7" @@ -2990,7 +2990,7 @@ }, "packages/linear": { "name": "@relayfile/adapter-linear", - "version": "0.1.2", + "version": "0.1.5", "license": "MIT", "dependencies": { "@agent-relay/sdk": "^3.2.22", @@ -3007,7 +3007,7 @@ }, "packages/notion": { "name": "@relayfile/adapter-notion", - "version": "0.1.1", + "version": "0.1.4", "license": "MIT", "dependencies": { "@agent-relay/sdk": "^3.2.22", @@ -3022,7 +3022,7 @@ }, "packages/slack": { "name": "@relayfile/adapter-slack", - "version": "0.1.2", + "version": "0.1.5", "license": "MIT", "dependencies": { "@agent-relay/sdk": "^3.2.22", @@ -3039,7 +3039,7 @@ }, "packages/teams": { "name": "@relayfile/adapter-teams", - "version": "0.1.1", + "version": "0.1.4", "license": "MIT", "dependencies": { "@relayfile/sdk": "^0.1.7" diff --git a/packages/notion/src/__tests__/queries.test.ts b/packages/notion/src/__tests__/queries.test.ts new file mode 100644 index 0000000..abff2f2 --- /dev/null +++ b/packages/notion/src/__tests__/queries.test.ts @@ -0,0 +1,232 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; +import { + buildDatabaseFilter, + getBlockChildren, + getPage, + queryDatabase, + searchDatabases, + searchPages, +} from '../queries.js'; +import type { + NotionBlock, + NotionDatabase, + NotionListResponse, + NotionPage, +} from '../queries.js'; + +describe('Notion query helpers', () => { + it('builds a page search operation without undefined payload keys', () => { + const operation = searchPages({ query: 'investors', page_size: 10 }); + + assert.deepStrictEqual(operation, { + method: 'POST', + endpoint: '/v1/search', + data: { + query: 'investors', + page_size: 10, + filter: { + property: 'object', + value: 'page', + }, + }, + }); + assertNoUndefinedDeep(operation); + }); + + it('builds a database search operation with pagination', () => { + const operation = searchDatabases({ page_size: 5, start_cursor: 'cursor' }); + + assert.deepStrictEqual(operation, { + method: 'POST', + endpoint: '/v1/search', + data: { + page_size: 5, + start_cursor: 'cursor', + filter: { + property: 'object', + value: 'database', + }, + }, + }); + }); + + it('builds a database query operation with encoded ids and preserves filters, sorts, and pagination', () => { + const filter = { + property: 'Status', + select: { equals: 'Active' }, + }; + const sorts = [ + { property: 'Priority', direction: 'descending' }, + { timestamp: 'last_edited_time', direction: 'ascending' }, + ]; + const operation = queryDatabase('db id', { + filter, + sorts, + page_size: 25, + start_cursor: 'cursor-2', + }); + + assert.deepStrictEqual(operation, { + method: 'POST', + endpoint: '/v1/databases/db%20id/query', + data: { + filter, + sorts, + page_size: 25, + start_cursor: 'cursor-2', + }, + }); + }); + + it('builds a page fetch operation without a payload', () => { + const operation = getPage('page id'); + + assert.deepStrictEqual(operation, { + method: 'GET', + endpoint: '/v1/pages/page%20id', + }); + assert.ok(!('data' in operation)); + }); + + it('builds a block children operation with pagination in the query string', () => { + const operation = getBlockChildren('block id', { + page_size: 50, + start_cursor: 'abc', + }); + + assert.deepStrictEqual(operation, { + method: 'GET', + endpoint: '/v1/blocks/block%20id/children?page_size=50&start_cursor=abc', + }); + assert.ok(!('data' in operation)); + }); + + it('uses the expected default operators for common database filter types', () => { + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Name', + type: 'title', + value: 'investors', + }), { + property: 'Name', + title: { contains: 'investors' }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Summary', + type: 'rich_text', + value: 'memo', + }), { + property: 'Summary', + rich_text: { contains: 'memo' }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Published', + type: 'checkbox', + value: true, + }), { + property: 'Published', + checkbox: { equals: true }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Stage', + type: 'select', + value: 'Seed', + }), { + property: 'Stage', + select: { equals: 'Seed' }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Tags', + type: 'multi_select', + value: 'finance', + }), { + property: 'Tags', + multi_select: { contains: 'finance' }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Launch date', + type: 'date', + value: '2026-04-01', + }), { + property: 'Launch date', + date: { on_or_after: '2026-04-01' }, + }); + + assert.deepStrictEqual(buildDatabaseFilter({ + property: 'Employees', + type: 'number', + value: 10, + }), { + property: 'Employees', + number: { equals: 10 }, + }); + }); + + it('lets an explicit operator override the default when supported', () => { + const filter = buildDatabaseFilter({ + property: 'Name', + type: 'title', + value: 'inv', + operator: 'starts_with', + }); + + assert.deepStrictEqual(filter, { + property: 'Name', + title: { starts_with: 'inv' }, + }); + }); + + it('keeps exported response types assignable', () => { + const pageList: NotionListResponse = { + object: 'list', + results: [{ object: 'page', id: 'page-1', properties: {} }], + has_more: false, + next_cursor: null, + }; + const database: NotionDatabase = { + object: 'database', + id: 'db-1', + title: [], + description: [], + properties: {}, + }; + const block: NotionBlock = { + object: 'block', + id: 'block-1', + type: 'paragraph', + has_children: false, + }; + + expectType(pageList.results?.[0]); + expectType(database); + expectType(block); + assert.strictEqual(pageList.results?.[0]?.id, 'page-1'); + assert.strictEqual(database.id, 'db-1'); + assert.strictEqual(block.id, 'block-1'); + }); +}); + +function assertNoUndefinedDeep(value: unknown): void { + if (Array.isArray(value)) { + for (const item of value) { + assertNoUndefinedDeep(item); + } + return; + } + + if (!value || typeof value !== 'object') { + return; + } + + for (const [key, entry] of Object.entries(value)) { + assert.notStrictEqual(entry, undefined, `Expected ${key} to be defined`); + assertNoUndefinedDeep(entry); + } +} + +function expectType(_value: T): void {} diff --git a/packages/notion/src/index.ts b/packages/notion/src/index.ts index 93e094a..242e574 100644 --- a/packages/notion/src/index.ts +++ b/packages/notion/src/index.ts @@ -15,4 +15,22 @@ export * from './path-mapper.js'; export * from './search.js'; export * from './sync.js'; export * from './types.js'; +export { + buildDatabaseFilter, + getBlockChildren, + getPage, + queryDatabase, + searchDatabases, + searchPages, +} from './queries.js'; +export type { + NotionDatabaseFilter, + NotionDatabaseFilterInput, + NotionDatabaseFilterType, + NotionObject, + NotionPaginationOptions, + NotionProxyOperation, + NotionQueryDatabaseOptions, + NotionSearchOptions, +} from './queries.js'; export * from './writeback.js'; diff --git a/packages/notion/src/queries.ts b/packages/notion/src/queries.ts new file mode 100644 index 0000000..c3da097 --- /dev/null +++ b/packages/notion/src/queries.ts @@ -0,0 +1,381 @@ +export interface NotionProxyOperation { + endpoint: string; + method: 'GET' | 'POST'; + data?: Record; + headers?: Record; +} + +export interface NotionPaginationOptions { + page_size?: number; + start_cursor?: string; +} + +export interface NotionSearchOptions extends NotionPaginationOptions { + query?: string; + sort?: { + direction: 'ascending' | 'descending'; + timestamp: 'last_edited_time'; + }; +} + +export interface NotionQueryDatabaseOptions extends NotionPaginationOptions { + filter?: NotionDatabaseFilter; + sorts?: Array>; +} + +export type NotionDatabaseFilterType = + | 'title' + | 'rich_text' + | 'number' + | 'checkbox' + | 'select' + | 'multi_select' + | 'date' + | 'people' + | 'files' + | 'url' + | 'email' + | 'phone_number' + | 'relation' + | 'formula' + | 'created_time' + | 'created_by' + | 'last_edited_time' + | 'last_edited_by'; + +export interface NotionDatabaseFilterInput { + property: string; + value: unknown; + type?: NotionDatabaseFilterType; + operator?: string; +} + +export type NotionDatabaseFilter = Record; + +export interface NotionListResponse { + object?: 'list'; + results?: T[]; + next_cursor?: string | null; + has_more?: boolean; + type?: string; + page_or_database?: Record; +} + +export interface NotionObject { + object?: string; + id?: string; + created_time?: string; + last_edited_time?: string; + archived?: boolean; + in_trash?: boolean; + url?: string; + public_url?: string | null; + properties?: Record; + parent?: Record; + created_by?: Record; + last_edited_by?: Record; + [key: string]: unknown; +} + +export interface NotionPage extends NotionObject { + object?: 'page'; + properties?: Record; +} + +export interface NotionDatabase extends NotionObject { + object?: 'database'; + title?: unknown[]; + description?: unknown[]; + properties?: Record; +} + +export interface NotionBlock extends NotionObject { + object?: 'block'; + type?: string; + has_children?: boolean; +} + +const TIMESTAMP_FILTER_TYPES = new Set([ + 'created_time', + 'last_edited_time', +]); + +const CONTAINS_FILTER_TYPES = new Set([ + 'multi_select', + 'people', + 'relation', + 'created_by', + 'last_edited_by', +]); + +const BOOLEAN_EMPTY_OPERATORS = new Set([ + 'is_empty', + 'is_not_empty', +]); + +const EMPTY_OBJECT_OPERATORS = new Set([ + 'past_week', + 'past_month', + 'past_year', + 'this_week', + 'next_week', + 'next_month', + 'next_year', +]); + +export function searchPages(options: NotionSearchOptions = {}): NotionProxyOperation { + return buildSearchOperation('page', options); +} + +export function searchDatabases(options: NotionSearchOptions = {}): NotionProxyOperation { + return buildSearchOperation('database', options); +} + +export function queryDatabase( + databaseId: string, + options: NotionQueryDatabaseOptions = {}, +): NotionProxyOperation { + const data = compactRecord({ + filter: options.filter, + sorts: options.sorts, + page_size: options.page_size, + start_cursor: emptyStringToUndefined(options.start_cursor), + }); + + return { + method: 'POST', + endpoint: `/v1/databases/${encodeURIComponent(databaseId)}/query`, + ...(Object.keys(data).length > 0 ? { data } : {}), + }; +} + +export function getPage(pageId: string): NotionProxyOperation { + return { + method: 'GET', + endpoint: `/v1/pages/${encodeURIComponent(pageId)}`, + }; +} + +export function getBlockChildren( + blockId: string, + options: NotionPaginationOptions = {}, +): NotionProxyOperation { + return { + method: 'GET', + endpoint: withQueryString(`/v1/blocks/${encodeURIComponent(blockId)}/children`, { + page_size: options.page_size, + start_cursor: emptyStringToUndefined(options.start_cursor), + }), + }; +} + +export function buildDatabaseFilter(input: NotionDatabaseFilterInput): NotionDatabaseFilter { + const property = input.property.trim(); + const filterType = input.type ?? inferDatabaseFilterType(input.value); + const operator = input.operator ?? inferDefaultOperator(filterType, input.value); + + if (!property && !TIMESTAMP_FILTER_TYPES.has(filterType)) { + throw new Error('Notion database filters require a non-empty property name.'); + } + + if (TIMESTAMP_FILTER_TYPES.has(filterType)) { + return { + timestamp: filterType, + [filterType]: buildOperatorExpression(operator, input.value), + }; + } + + if (filterType === 'formula') { + return { + property, + formula: buildFormulaExpression(operator, input.value), + }; + } + + if (CONTAINS_FILTER_TYPES.has(filterType) && Array.isArray(input.value)) { + const values = input.value.filter(isDefined); + if (values.length === 0) { + throw new Error(`Notion ${filterType} filters require at least one value.`); + } + + if (values.length === 1) { + return { + property, + [filterType]: buildOperatorExpression(operator, values[0]), + }; + } + + return { + or: values.map((value) => ({ + property, + [filterType]: buildOperatorExpression(operator, value), + })), + }; + } + + return { + property, + [filterType]: buildOperatorExpression(operator, input.value), + }; +} + +function buildSearchOperation( + objectType: 'page' | 'database', + options: NotionSearchOptions, +): NotionProxyOperation { + return { + method: 'POST', + endpoint: '/v1/search', + data: compactRecord({ + query: emptyStringToUndefined(options.query), + sort: options.sort, + page_size: options.page_size, + start_cursor: emptyStringToUndefined(options.start_cursor), + filter: { + property: 'object', + value: objectType, + }, + }), + }; +} + +function inferDatabaseFilterType(value: unknown): NotionDatabaseFilterType { + if (typeof value === 'number') { + return 'number'; + } + + if (typeof value === 'boolean') { + return 'checkbox'; + } + + if (Array.isArray(value)) { + return 'multi_select'; + } + + if (value instanceof Date || isIsoDateString(value)) { + return 'date'; + } + + return 'rich_text'; +} + +function inferDefaultOperator(type: NotionDatabaseFilterType, value: unknown): string { + switch (type) { + case 'created_time': + case 'last_edited_time': + return 'after'; + case 'date': + return 'on_or_after'; + case 'title': + case 'rich_text': + return 'contains'; + case 'multi_select': + case 'people': + case 'relation': + case 'created_by': + case 'last_edited_by': + return 'contains'; + case 'files': + return value === false ? 'is_empty' : 'is_not_empty'; + case 'formula': + return 'equals'; + default: + return 'equals'; + } +} + +function buildFormulaExpression(operator: string, value: unknown): Record { + const subtype = inferFormulaSubtype(value); + return { + [subtype]: buildOperatorExpression(operator, normalizeFilterValue(value)), + }; +} + +function inferFormulaSubtype(value: unknown): 'checkbox' | 'date' | 'number' | 'string' { + if (typeof value === 'boolean') { + return 'checkbox'; + } + + if (typeof value === 'number') { + return 'number'; + } + + if (value instanceof Date || isIsoDateString(value)) { + return 'date'; + } + + return 'string'; +} + +function buildOperatorExpression(operator: string, value: unknown): Record { + if (BOOLEAN_EMPTY_OPERATORS.has(operator)) { + return { [operator]: true }; + } + + if (EMPTY_OBJECT_OPERATORS.has(operator)) { + return { [operator]: {} }; + } + + if (value === undefined || value === null) { + return { [operator]: true }; + } + + return { + [operator]: normalizeFilterValue(value), + }; +} + +function normalizeFilterValue(value: unknown): unknown { + if (value instanceof Date) { + return value.toISOString(); + } + + return value; +} + +function withQueryString( + endpoint: string, + params: Record, +): string { + const searchParams = new URLSearchParams(); + + for (const [key, value] of Object.entries(params)) { + if (value === undefined) { + continue; + } + + searchParams.set(key, String(value)); + } + + const query = searchParams.toString(); + return query ? `${endpoint}?${query}` : endpoint; +} + +function compactRecord( + input: Record, +): Record { + const output: Record = {}; + + for (const [key, value] of Object.entries(input)) { + if (value !== undefined) { + output[key] = value; + } + } + + return output; +} + +function emptyStringToUndefined(value: string | undefined): string | undefined { + return value && value.trim().length > 0 ? value : undefined; +} + +function isIsoDateString(value: unknown): value is string { + return ( + typeof value === 'string' && + /^\d{4}-\d{2}-\d{2}(?:T[\d:.+-]+Z?)?$/.test(value.trim()) + ); +} + +function isDefined(value: T | null | undefined): value is T { + return value !== null && value !== undefined; +} From f663821a69a9a3d4669a37ac735414c05a868960 Mon Sep 17 00:00:00 2001 From: RelayFile Adapters Bot Date: Sun, 26 Apr 2026 23:26:37 +0200 Subject: [PATCH 2/2] chore(adapter-notion): drop unrelated lockfile churn --- package-lock.json | 158 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 135 insertions(+), 23 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d6742d..804ffec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -687,6 +687,16 @@ "resolved": "packages/teams", "link": true }, + "node_modules/@relayfile/core": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/core/-/core-0.3.2.tgz", + "integrity": "sha512-3qv+m1G7acS3sdydI1OxzxdGMdPYlYAiycbUtPbtf42o9rce/nixCTXzfgdlCKlCZEhPyFzAWXiucXh0TvHieQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@relayfile/sdk": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.1.7.tgz", @@ -2927,7 +2937,7 @@ }, "packages/core": { "name": "@relayfile/adapter-core", - "version": "0.1.4", + "version": "0.1.7", "license": "MIT", "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", @@ -2940,7 +2950,7 @@ }, "devDependencies": { "@agent-relay/sdk": "^3.2.22", - "@relayfile/sdk": "^0.1.7", + "@relayfile/sdk": "^0.3.1", "@types/node": "^24.5.2", "typescript": "^5.9.2", "vitest": "^3.0.0" @@ -2949,18 +2959,31 @@ "node": ">=18" }, "peerDependencies": { - "@relayfile/sdk": "^0.1.7" + "@relayfile/sdk": ">=0.1.7 <1" + } + }, + "packages/core/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@relayfile/core": "0.3.2" + }, + "engines": { + "node": ">=18" } }, "packages/github": { "name": "@relayfile/adapter-github", - "version": "0.1.4", + "version": "0.1.7", "license": "MIT", "dependencies": { "@relayfile/adapter-core": "^0.1.1" }, "devDependencies": { - "@relayfile/sdk": "^0.1.7", + "@relayfile/sdk": "^0.3.1", "@types/node": "^24.6.0", "tsx": "^4.21.0", "typescript": "^5.9.3" @@ -2969,86 +2992,175 @@ "node": ">=18" }, "peerDependencies": { - "@relayfile/sdk": "^0.1.7" + "@relayfile/sdk": ">=0.1.7 <1" } }, - "packages/gitlab": { - "name": "@relayfile/adapter-gitlab", - "version": "0.1.4", + "packages/github/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, "license": "MIT", "dependencies": { - "@relayfile/sdk": "^0.1.7" + "@relayfile/core": "0.3.2" }, + "engines": { + "node": ">=18" + } + }, + "packages/gitlab": { + "name": "@relayfile/adapter-gitlab", + "version": "0.1.7", + "license": "MIT", "devDependencies": { "@agent-relay/sdk": "^3.2.22", + "@relayfile/sdk": "^0.3.1", "@types/node": "^24.6.0", "typescript": "^5.9.3" }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@relayfile/sdk": ">=0.1.7 <1" + } + }, + "packages/gitlab/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@relayfile/core": "0.3.2" + }, "engines": { "node": ">=18" } }, "packages/linear": { "name": "@relayfile/adapter-linear", - "version": "0.1.5", + "version": "0.1.8", "license": "MIT", "dependencies": { - "@agent-relay/sdk": "^3.2.22", - "@relayfile/sdk": "^0.1.7" + "@agent-relay/sdk": "^3.2.22" }, "devDependencies": { + "@relayfile/sdk": "^0.3.1", "@types/node": "^24.6.0", "tsx": "^4.20.6", "typescript": "^5.9.3" }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@relayfile/sdk": ">=0.1.7 <1" + } + }, + "packages/linear/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@relayfile/core": "0.3.2" + }, "engines": { "node": ">=18" } }, "packages/notion": { "name": "@relayfile/adapter-notion", - "version": "0.1.4", + "version": "0.1.7", "license": "MIT", "dependencies": { - "@agent-relay/sdk": "^3.2.22", - "@relayfile/sdk": "^0.1.7" + "@agent-relay/sdk": "^3.2.22" }, "devDependencies": { + "@relayfile/sdk": "^0.3.1", "typescript": "^5.4.0" }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@relayfile/sdk": ">=0.1.7 <1" + } + }, + "packages/notion/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@relayfile/core": "0.3.2" + }, "engines": { "node": ">=18" } }, "packages/slack": { "name": "@relayfile/adapter-slack", - "version": "0.1.5", + "version": "0.1.8", "license": "MIT", "dependencies": { - "@agent-relay/sdk": "^3.2.22", - "@relayfile/sdk": "^0.1.7" + "@agent-relay/sdk": "^3.2.22" }, "devDependencies": { + "@relayfile/sdk": "^0.3.1", "@types/node": "^24.6.0", "tsx": "^4.20.6", "typescript": "^5.9.3" }, "engines": { "node": ">=20" + }, + "peerDependencies": { + "@relayfile/sdk": ">=0.1.7 <1" } }, - "packages/teams": { - "name": "@relayfile/adapter-teams", - "version": "0.1.4", + "packages/slack/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, "license": "MIT", "dependencies": { - "@relayfile/sdk": "^0.1.7" + "@relayfile/core": "0.3.2" }, + "engines": { + "node": ">=18" + } + }, + "packages/teams": { + "name": "@relayfile/adapter-teams", + "version": "0.1.7", + "license": "MIT", "devDependencies": { "@agent-relay/sdk": "^3.2.22", + "@relayfile/sdk": "^0.3.1", "@types/node": "^25.5.0", "typescript": "^5.4.0" }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@relayfile/sdk": ">=0.1.7 <1" + } + }, + "packages/teams/node_modules/@relayfile/sdk": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.3.2.tgz", + "integrity": "sha512-tOaXT3fJUIVXRt41o9pxKbUIllqPXiJ0r6syrM8wREZErvE4gxABdqn6DDAZSo4fLMgiWrdyC12qQlS0kVEhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@relayfile/core": "0.3.2" + }, "engines": { "node": ">=18" }