diff --git a/packages/sdk/package-lock.json b/packages/sdk/package-lock.json index 9708d84f2..74248af17 100644 --- a/packages/sdk/package-lock.json +++ b/packages/sdk/package-lock.json @@ -10,8 +10,8 @@ "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", - "@relayfile/adapter-core": "0.8.5", - "@relayfile/relay-helpers": "0.6.1", + "@relayfile/adapter-core": "0.8.7", + "@relayfile/relay-helpers": "0.6.2", "@relayflows/surface": "2.0.66", "@types/js-yaml": "^4.0.9", "acorn": "^8.18.0", @@ -537,9 +537,9 @@ } }, "node_modules/@relayfile/adapter-core": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-core/-/adapter-core-0.8.5.tgz", - "integrity": "sha512-J10VAyHz1P7wQDKKmVCJD+2kORQs1icP7CtqG1u8r0wO73S76UStimPsCzlGl9UhVhzqdkCZ7wf+GKH9f4N6Aw==", + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-core/-/adapter-core-0.8.7.tgz", + "integrity": "sha512-+6Vl3YsestQN6QhfL42faP5CbdVP/Cpl44m1vdw9ENVi4eyz/GwyD+aJe/Ws7jD/w+ctrQbYVEXl8WOaSayULQ==", "license": "Apache-2.0", "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", @@ -558,12 +558,12 @@ } }, "node_modules/@relayfile/adapter-linear": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-linear/-/adapter-linear-0.6.1.tgz", - "integrity": "sha512-BeTSUcm0+vN4krpESFiAfvjJ/WesxKAKhpdQM6uuNYWyl3efNXMj5Qe5nDGCSO2QHMyhKAZYjCyzzgqB9YnqQw==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-linear/-/adapter-linear-0.6.2.tgz", + "integrity": "sha512-oaN0pJ9GBRMjGvR5y+Ozl94RerxPpTbX1E0ygR7hmeE4JMOEFFf3sKRKg1PaSHu6t7LIF1DxXxeXBgvGlc38Yw==", "license": "Apache-2.0", "dependencies": { - "@relayfile/adapter-core": "^0.8.5" + "@relayfile/adapter-core": "^0.8.7" }, "engines": { "node": ">=18" @@ -573,12 +573,12 @@ } }, "node_modules/@relayfile/adapter-reddit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-reddit/-/adapter-reddit-0.4.1.tgz", - "integrity": "sha512-Mz57v1vIE5sEy5F4Z7ix550Ga6l615lgQi0QDc8kgjWiUD9QqZW+Wm+iG+96S4vIQueM70pm60/fitrGGnIGAw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-reddit/-/adapter-reddit-0.4.2.tgz", + "integrity": "sha512-EkoNy+CqVGm5sivaPUzHALnoH20gWzJwIO8OvPNpD4wTPk/MB7AcZarrCQ+5cAJ1OxHOJj4h1ZNVJzhmtEYizQ==", "license": "Apache-2.0", "dependencies": { - "@relayfile/adapter-core": "^0.8.5" + "@relayfile/adapter-core": "^0.8.7" }, "engines": { "node": ">=18" @@ -738,14 +738,14 @@ "peer": true }, "node_modules/@relayfile/relay-helpers": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@relayfile/relay-helpers/-/relay-helpers-0.6.1.tgz", - "integrity": "sha512-C43jTVFwsqoiyGoS2RczvGgpSyeu9+v7q9nDKZj2NJp9WBqRHTZd6DlU2jH/OB1ovnY4cIGbH3o7TMdNLc50aQ==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@relayfile/relay-helpers/-/relay-helpers-0.6.2.tgz", + "integrity": "sha512-MWyj0g0ODoqeoZkZoLS2Ea7QCC6F7wJS8WRWPMDSK2JkekVDB+2gwSagvTfGygYquQCl0uU2wXwc2KQwFAvFKg==", "license": "Apache-2.0", "dependencies": { - "@relayfile/adapter-core": "^0.8.5", - "@relayfile/adapter-linear": "^0.6.1", - "@relayfile/adapter-reddit": "^0.4.1" + "@relayfile/adapter-core": "^0.8.7", + "@relayfile/adapter-linear": "^0.6.2", + "@relayfile/adapter-reddit": "^0.4.2" } }, "node_modules/@relayfile/sdk": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 1d7f14588..1189fbf58 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -48,8 +48,8 @@ "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.30.0", - "@relayfile/adapter-core": "0.8.5", - "@relayfile/relay-helpers": "0.6.1", + "@relayfile/adapter-core": "0.8.7", + "@relayfile/relay-helpers": "0.6.2", "@relayflows/surface": "2.0.66", "@types/js-yaml": "^4.0.9", "acorn": "^8.18.0", diff --git a/packages/sdk/tests/bin.test.ts b/packages/sdk/tests/bin.test.ts index 2ba7088e0..c9ea76dc3 100644 --- a/packages/sdk/tests/bin.test.ts +++ b/packages/sdk/tests/bin.test.ts @@ -1,13 +1,18 @@ import { mkdtempSync, + cpSync, + existsSync, + lstatSync, + mkdirSync, readFileSync, + realpathSync, rmSync, statSync, symlinkSync, writeFileSync, } from 'node:fs'; import { tmpdir } from 'node:os'; -import { dirname, join } from 'node:path'; +import { dirname, join, relative, isAbsolute, sep } from 'node:path'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { afterEach, describe, expect, it } from 'vitest'; @@ -32,6 +37,49 @@ function temporaryDirectory(): string { return directory; } +/** Stage owned package payloads so npm 10's prepare hook cannot rebuild shared dist. */ +function installSurfacePackage(directory: string): void { + const source = realpathSync(join(SDK, 'node_modules/@relayflows/surface')); + const location = relative(realpathSync(ROOT), source); + expect(isAbsolute(location) || location === '..' || location.startsWith(`..${sep}`), + 'Surface must come from this owned checkout, never a foreign worktree').toBe(false); + const manifest = JSON.parse(readFileSync(join(source, 'package.json'), 'utf8')); + expect(manifest.name).toBe('@relayflows/surface'); + const staging = join(directory, 'surface-package'); + mkdirSync(staging); + for (const file of manifest.files as string[]) { + expect(isAbsolute(file) || file.split(/[\\/]/).includes('..')).toBe(false); + const target = join(staging, file); + mkdirSync(dirname(target), { recursive: true }); + cpSync(join(source, file), target, { recursive: true, dereference: true, + filter: path => !relative(source, path).split(sep).includes('node_modules') }); + } + // Fixture-only lifecycle normalization follows scripts/publish.test.mjs. + // Runtime files, exports, versions and peer contracts still come from Surface. + const stagingManifest = structuredClone(manifest); + for (const hook of ['prepare', 'prepack', 'postpack']) delete stagingManifest.scripts?.[hook]; + writeFileSync(join(staging, 'package.json'), JSON.stringify(stagingManifest)); + const packed = spawnSync('npm', ['pack', '--ignore-scripts', '--json', '--pack-destination', directory], { + cwd: staging, encoding: 'utf8', timeout: 60_000, + }); + expect(packed.status, packed.stderr + packed.stdout).toBe(0); + const [{ filename }] = JSON.parse(packed.stdout) as Array<{ filename: string }>; + writeFileSync(join(directory, 'package.json'), '{"private":true,"type":"module"}'); + const installed = spawnSync('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', + '--omit=dev', '--registry=https://registry.npmjs.org', '--save-exact', join(directory, filename)], { + cwd: directory, encoding: 'utf8', timeout: 90_000, + }); + expect(installed.status, installed.stderr + installed.stdout).toBe(0); + const target = join(directory, 'node_modules/@relayflows/surface'); + expect(lstatSync(target).isSymbolicLink()).toBe(false); + expect(realpathSync(target)).toBe(join(realpathSync(directory), 'node_modules/@relayflows/surface')); + const installedManifest = JSON.parse(readFileSync(join(target, 'package.json'), 'utf8')); + expect(installedManifest).toEqual(stagingManifest); + expect({ ...installedManifest, scripts: manifest.scripts }).toEqual(manifest); + const helpers = JSON.parse(readFileSync(join(directory, 'node_modules/@relayfile/relay-helpers/package.json'), 'utf8')); + expect(helpers.version).toBe(manifest.peerDependencies['@relayfile/relay-helpers']); +} + function invoke(entry: string, flow: string, env: NodeJS.ProcessEnv = process.env) { return spawnSync(entry, ['check', flow], { cwd: ROOT, @@ -55,6 +103,37 @@ function expectMissingCliRefusal(result: ReturnType): void { } describe('built flows binary', () => { + it('loads authored bare package imports in the standalone without enabling dotenv or bunfig', () => { + const directory = temporaryDirectory(); + const standalone = join(directory, 'flows'); + const built = spawnSync(process.execPath, [STANDALONE_BUILDER, + process.platform === 'darwin' ? 'bun-darwin-arm64' : 'bun-linux-x64', standalone], { + cwd: ROOT, encoding: 'utf8', timeout: 120_000, + env: { ...process.env, FLOWS_BUILD_BUN: process.env['FLOWS_BUILD_BUN'] ?? 'bun' }, + }); + expect(built.status, built.stderr + built.stdout).toBe(0); + installSurfacePackage(directory); + writeFileSync(join(directory, '.env'), 'FLOWS_STANDALONE_DOTENV_PROBE=unexpected\n'); + writeFileSync(join(directory, 'bunfig.toml'), 'preload = ["./must-not-preload.mjs"]\n'); + writeFileSync(join(directory, 'must-not-preload.mjs'), "throw new Error('bunfig unexpectedly loaded');\n"); + const flow = join(directory, 'physical-surface.flow.ts'); + writeFileSync(flow, `import { flow } from '@relayflows/surface'; +import { writeFileSync } from 'node:fs'; +if (process.env.FLOWS_STANDALONE_DOTENV_PROBE !== undefined) throw new Error('dotenv unexpectedly loaded'); +export default flow('physical-surface', async f => { + writeFileSync(${JSON.stringify(join(directory, 'body-executed'))}, 'unexpected'); + f.done('success'); +});\n`); + const checked = spawnSync(standalone, ['check', '--json', '--no-daemon-check', flow], { + cwd: directory, encoding: 'utf8', timeout: 30_000, + // No NODE_PATH/NODE_OPTIONS or workspace package-resolution fallback. + env: { PATH: process.env.PATH, HOME: directory }, + }); + expect(checked.status, checked.stderr + checked.stdout).toBe(0); + expect(JSON.parse(checked.stdout)).toMatchObject({ ok: true, path: flow }); + expect(existsSync(join(directory, 'body-executed'))).toBe(false); + }, 150_000); + it('build produces an executable CLI artifact', () => { expect(statSync(BUILT_CLI).mode & 0o111).not.toBe(0); }); diff --git a/packages/sdk/tests/gitlab-helper-path.test.ts b/packages/sdk/tests/gitlab-helper-path.test.ts index 9a8683088..0545e588b 100644 --- a/packages/sdk/tests/gitlab-helper-path.test.ts +++ b/packages/sdk/tests/gitlab-helper-path.test.ts @@ -1,6 +1,62 @@ import { PreviewTransport, type gitlabClient } from '@relayfile/relay-helpers'; -import { helperClients } from '@relayflows/surface/runtime'; -import { expect, it } from 'vitest'; +import { helperClients, type HelperCall } from '@relayflows/surface/runtime'; +import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { afterEach, expect, it, vi } from 'vitest'; +import { helperTransport } from '../src/helper-writeback.js'; + +const directories: string[] = []; +afterEach(() => { + for (const directory of directories.splice(0)) rmSync(directory, { recursive: true, force: true }); + vi.unstubAllEnvs(); +}); + +const projectPath = 'acme/platform/web'; +const prefix = `/gitlab/projects/${projectPath}`; +const issues = Array.from({ length: 8 }, (_, index) => ({ iid: index + 1, title: `issue ${index + 1}`, state: index === 7 ? 'closed' : 'opened' })); +const requests = [{ iid: 9, title: 'merged request', state: 'merged' }]; + +function collectionFixtures(): Record { + return { + ...Object.fromEntries(issues.map(issue => [`${prefix}/issues/${issue.iid}__issue/meta.json`, issue])), + [`${prefix}/merge_requests/9__request/meta.json`]: requests[0], + [`${prefix}/issues/_index.json`]: issues.map(({ iid }) => ({ iid })), + [`${prefix}/merge_requests/_index.json`]: [{ iid: 9 }], + [`${prefix}/issues/1__issue/comments/1.json`]: { iid: 'child' }, + [`${prefix}/issues/1__issue/children/meta.json`]: { iid: 'grandchild' }, + [`${prefix}/issues/by-id/1.json`]: { iid: 'alias' }, + [`${prefix}/issues/by-id/1/meta.json`]: { iid: 'directory-alias' }, + '/gitlab/projects/acme/other/issues/1__foreign/meta.json': { iid: 'foreign' }, + }; +} + +for (const mode of ['filesystem', 'preview'] as const) { + for (const resource of ['issues', 'merge-requests'] as const) { + it(`${mode} lists exact ${resource} records through the shipped Surface factory`, async () => { + const fixtures = collectionFixtures(); + let transport; + if (mode === 'preview') { + transport = new PreviewTransport({ fixtures }); + } else { + const directory = mkdtempSync(join(tmpdir(), 'gitlab-helper-collections-')); + directories.push(directory); + for (const [path, value] of Object.entries(fixtures)) { + const target = join(directory, path); + mkdirSync(dirname(target), { recursive: true }); + writeFileSync(target, JSON.stringify(value)); + } + symlinkSync('1__issue', join(directory, prefix, 'issues', 'linked-record')); + vi.stubEnv('RELAYFILE_MOUNT_PATH', directory); + vi.stubEnv('RELAYFLOWS_GITLAB_MOCK', '0'); + const call: HelperCall = { type: 'effect', provider: 'gitlab', verb: `${resource}.list`, args: [{ projectPath }] }; + transport = helperTransport(call, directory, 'collection-proof', resource, new AbortController().signal).transport; + } + const client = helperClients.gitlab!({ transport }) as ReturnType; + expect(await client[resource].list({ projectPath })).toEqual(resource === 'issues' ? issues : requests); + }); + } +} it('reads and writes the mounted GitLab project through the shipped helper factory', async () => { const projectPath = 'acme/platform/web'; diff --git a/packages/surface/bun.lock b/packages/surface/bun.lock index e03edeb38..523d1350b 100644 --- a/packages/surface/bun.lock +++ b/packages/surface/bun.lock @@ -13,7 +13,7 @@ "vitest": "^2.1.0", }, "peerDependencies": { - "@relayfile/relay-helpers": "0.6.1", + "@relayfile/relay-helpers": "0.6.2", }, }, }, @@ -74,37 +74,37 @@ "@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="], - "@relayfile/adapter-core": ["@relayfile/adapter-core@0.8.5", "", { "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", "cheerio": "^1.2.0", "minimatch": "^10.0.3", "yaml": "^2.8.1" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" }, "bin": { "adapter-core": "dist/src/cli.js" } }, "sha512-J10VAyHz1P7wQDKKmVCJD+2kORQs1icP7CtqG1u8r0wO73S76UStimPsCzlGl9UhVhzqdkCZ7wf+GKH9f4N6Aw=="], + "@relayfile/adapter-core": ["@relayfile/adapter-core@0.8.7", "", { "dependencies": { "@scalar/postman-to-openapi": "^0.6.0", "cheerio": "^1.2.0", "minimatch": "^10.0.3", "yaml": "^2.8.1" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" }, "bin": { "adapter-core": "dist/src/cli.js" } }, "sha512-+6Vl3YsestQN6QhfL42faP5CbdVP/Cpl44m1vdw9ENVi4eyz/GwyD+aJe/Ws7jD/w+ctrQbYVEXl8WOaSayULQ=="], - "@relayfile/adapter-linear": ["@relayfile/adapter-linear@0.6.1", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.5" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" } }, "sha512-BeTSUcm0+vN4krpESFiAfvjJ/WesxKAKhpdQM6uuNYWyl3efNXMj5Qe5nDGCSO2QHMyhKAZYjCyzzgqB9YnqQw=="], + "@relayfile/adapter-linear": ["@relayfile/adapter-linear@0.6.2", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.7" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" } }, "sha512-oaN0pJ9GBRMjGvR5y+Ozl94RerxPpTbX1E0ygR7hmeE4JMOEFFf3sKRKg1PaSHu6t7LIF1DxXxeXBgvGlc38Yw=="], - "@relayfile/adapter-reddit": ["@relayfile/adapter-reddit@0.4.1", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.5" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" } }, "sha512-Mz57v1vIE5sEy5F4Z7ix550Ga6l615lgQi0QDc8kgjWiUD9QqZW+Wm+iG+96S4vIQueM70pm60/fitrGGnIGAw=="], + "@relayfile/adapter-reddit": ["@relayfile/adapter-reddit@0.4.2", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.7" }, "peerDependencies": { "@relayfile/sdk": ">=0.6.0 <1" } }, "sha512-EkoNy+CqVGm5sivaPUzHALnoH20gWzJwIO8OvPNpD4wTPk/MB7AcZarrCQ+5cAJ1OxHOJj4h1ZNVJzhmtEYizQ=="], - "@relayfile/cli-darwin-arm64": ["@relayfile/cli-darwin-arm64@0.10.76", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c+hoYqXm2V6poQNCgFM2Ls+rjh2/v5n/JRc9lWQPthKsiWCj+pN+2whltv5VmH4JZPeIxY5co9oOnZEGYxTrxQ=="], + "@relayfile/cli-darwin-arm64": ["@relayfile/cli-darwin-arm64@0.10.79", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Far6bxu5nhZfSlZ7eAZHSjULvKOrADxvYPUfFZofPAJR5Y132FnIc2SRi/HeQbmB3LpQtt7WYBXW/JlEJxq8EQ=="], - "@relayfile/cli-darwin-x64": ["@relayfile/cli-darwin-x64@0.10.76", "", { "os": "darwin", "cpu": "x64" }, "sha512-WZ0y+ky7HkNdXKPqVEvyaw/B8so8GxlQiJtbuv1o+k6WOvFtraVtfvtfD9MSoEI4JnF2LCMvhcu5+p2TtyE3Ow=="], + "@relayfile/cli-darwin-x64": ["@relayfile/cli-darwin-x64@0.10.79", "", { "os": "darwin", "cpu": "x64" }, "sha512-lk8Cia0Smn77ib4eit6ZicbBIHYJSSj7I725V5RG0JYaQ0GZ/OR6vk4kRP59kGT5v4JJqnOrj36LwYZFbOHKow=="], - "@relayfile/cli-linux-arm64": ["@relayfile/cli-linux-arm64@0.10.76", "", { "os": "linux", "cpu": "arm64" }, "sha512-/OnmA3omX5u3ECk4tZbGsdGCydnqJqZXvVC3JfursA6krj5Eo41XAQP6p4VmoocTSdYSkW5jke0QCNzObg1nAQ=="], + "@relayfile/cli-linux-arm64": ["@relayfile/cli-linux-arm64@0.10.79", "", { "os": "linux", "cpu": "arm64" }, "sha512-3D7zOi0EXef3wYVaaLo8+y4Me4plryyDpk+NMvWl/4vSVohq8FVjegdfJobvLy62jm51ep0skXT5QILCZ/lIkg=="], - "@relayfile/cli-linux-x64": ["@relayfile/cli-linux-x64@0.10.76", "", { "os": "linux", "cpu": "x64" }, "sha512-644dg1zSJW82emAudfDoO9hsE0ltZ228/IpmCEqiVHPRRS0+et7WfnUhFlmbkfY50UqJEbX/oFLrZdFcOXNfTw=="], + "@relayfile/cli-linux-x64": ["@relayfile/cli-linux-x64@0.10.79", "", { "os": "linux", "cpu": "x64" }, "sha512-dSNqIwOnCwl35jlG8IDBxXlYgenPtgAGNIZMnTZJmJZqeMLt5cHxwUDCFQVoEBrejc3z8zViGpD9OnszV3ZH4w=="], - "@relayfile/cli-win32-arm64": ["@relayfile/cli-win32-arm64@0.10.76", "", { "os": "win32", "cpu": "arm64" }, "sha512-7s2u/ZCC5Wr7OjqrhuepZaE2uvv67+cECcxpQsC1qNZeY4Vh0Qxml1x2w77tcvLHQotH3qU1w9LRECmhX7Mm5Q=="], + "@relayfile/cli-win32-arm64": ["@relayfile/cli-win32-arm64@0.10.79", "", { "os": "win32", "cpu": "arm64" }, "sha512-ZDtUrIn7aB8rfE25Eswa1ucqPm0cXq0k9vs0cz4ICihmxMc/o+vGA3nbiprmhggyrd+IE7GwSpP/y8n9BOUiNQ=="], - "@relayfile/cli-win32-x64": ["@relayfile/cli-win32-x64@0.10.76", "", { "os": "win32", "cpu": "x64" }, "sha512-e2cbYM+xPvGUQ2G+Hzh/s0y07pTdalGDBRgmpgfyxZok4/jUpF0oxgt5VVVQi5tTZMCvDciTp2ZBHHtjqQ8zuQ=="], + "@relayfile/cli-win32-x64": ["@relayfile/cli-win32-x64@0.10.79", "", { "os": "win32", "cpu": "x64" }, "sha512-rW/k8cEmZIwfFTW2KmYtXFaCJEcoapPCAgFnjfjc8SezkRhV2dC3o5T+htpJLPaUehfCjarKAcONZI7Hotl16Q=="], - "@relayfile/core": ["@relayfile/core@0.10.76", "", {}, "sha512-fwcGn8wqKjIaZPj7cpaIwqFCY/TZlHUWjrirunUNlUjEdYk8VtrjZYBzFLRF3fOQz7hPvsokZahxwCvyyeqEtg=="], + "@relayfile/core": ["@relayfile/core@0.10.79", "", {}, "sha512-fPWya8TqUN7ypx9cgh85+4SFgjbiyWdPxyRYTXbdFVqZkSGvBu7nGu6D8OqGZyewlmXr7g6WhdIm1B3bcLIDHA=="], - "@relayfile/mount-darwin-arm64": ["@relayfile/mount-darwin-arm64@0.10.76", "", { "os": "darwin", "cpu": "arm64" }, "sha512-WlYaBzCKIB/m7hxRgHhDFNSRsEDaHBwaIrj6WZ+YfVOeVciFwE9jLIwKX1Ku3Dm32uimwDQM9PT6LJD0EzKtxw=="], + "@relayfile/mount-darwin-arm64": ["@relayfile/mount-darwin-arm64@0.10.79", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5OQSQk5xJRs226u5yRWbI/tcybTV3dWGOuSwvouCNpaoU3MgargZgg+mieqNk4ketKgV1rufeKs7pMBp6ou6zQ=="], - "@relayfile/mount-darwin-x64": ["@relayfile/mount-darwin-x64@0.10.76", "", { "os": "darwin", "cpu": "x64" }, "sha512-41MorpFsVEzJPpLxnaIcgrDIhxj+hUzdMdh57M8/9GOXkLJY6b+6MWz1yPPlA0X3r6dkoxd/5reNqQmDBV8fQg=="], + "@relayfile/mount-darwin-x64": ["@relayfile/mount-darwin-x64@0.10.79", "", { "os": "darwin", "cpu": "x64" }, "sha512-r9PFhR0s8G+oU891SAw2qh8Ne7e/cVBtsV7qnhUUv6Mnt9+gnybB7vPmOj4vLvBvk7TkM6OSe+WaZWMTV/KVrg=="], - "@relayfile/mount-linux-arm64": ["@relayfile/mount-linux-arm64@0.10.76", "", { "os": "linux", "cpu": "arm64" }, "sha512-I/xkA/QED/DNDqapTEL7uTcc5UPJ/aAirSulCA3Y3yA7TnMv4I5QK+l2EDXzoxDTiF1LoadEtCZoTzRE0MeiLQ=="], + "@relayfile/mount-linux-arm64": ["@relayfile/mount-linux-arm64@0.10.79", "", { "os": "linux", "cpu": "arm64" }, "sha512-HnnjnIeQg8J1pIi6ufHRhDg/tn7raOX3Sm59tpwdQHikLxpPtQVSldg4k5NZrkUw+pCEhLGVJITX507LR4Bq7Q=="], - "@relayfile/mount-linux-x64": ["@relayfile/mount-linux-x64@0.10.76", "", { "os": "linux", "cpu": "x64" }, "sha512-PRVNoCyJrJZSHMB1YnxzfYosdi5eugAyKJvmze8qnnS/uIGMtsFdWHtdBs9LOp/Lx5QzGV6q7Rmaa35GkbpLQQ=="], + "@relayfile/mount-linux-x64": ["@relayfile/mount-linux-x64@0.10.79", "", { "os": "linux", "cpu": "x64" }, "sha512-R77dNUxQ7sFxtBZZxIz5mtawyAHenkhlJpIJ/xiiaWLlBuOnAUgeRC/eQGdPN/FGAp2qbTmVK/Y/wEAM652DnQ=="], - "@relayfile/relay-helpers": ["@relayfile/relay-helpers@0.6.1", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.5", "@relayfile/adapter-linear": "^0.6.1", "@relayfile/adapter-reddit": "^0.4.1" } }, "sha512-C43jTVFwsqoiyGoS2RczvGgpSyeu9+v7q9nDKZj2NJp9WBqRHTZd6DlU2jH/OB1ovnY4cIGbH3o7TMdNLc50aQ=="], + "@relayfile/relay-helpers": ["@relayfile/relay-helpers@0.6.2", "", { "dependencies": { "@relayfile/adapter-core": "^0.8.7", "@relayfile/adapter-linear": "^0.6.2", "@relayfile/adapter-reddit": "^0.4.2" } }, "sha512-MWyj0g0ODoqeoZkZoLS2Ea7QCC6F7wJS8WRWPMDSK2JkekVDB+2gwSagvTfGygYquQCl0uU2wXwc2KQwFAvFKg=="], - "@relayfile/sdk": ["@relayfile/sdk@0.10.76", "", { "dependencies": { "@relayfile/core": "0.10.76", "ignore": "^7.0.5", "tar": "^7.5.10" }, "optionalDependencies": { "@relayfile/cli-darwin-arm64": "0.10.76", "@relayfile/cli-darwin-x64": "0.10.76", "@relayfile/cli-linux-arm64": "0.10.76", "@relayfile/cli-linux-x64": "0.10.76", "@relayfile/cli-win32-arm64": "0.10.76", "@relayfile/cli-win32-x64": "0.10.76", "@relayfile/mount-darwin-arm64": "0.10.76", "@relayfile/mount-darwin-x64": "0.10.76", "@relayfile/mount-linux-arm64": "0.10.76", "@relayfile/mount-linux-x64": "0.10.76" } }, "sha512-/4PiO5FxsdF+IQ4MfZ6+eOe8ml1PU2CLdEzSpAbuPhO4nDT8npuZwOzXOs5KFv/tqPG9ldWnLTsUqPPpaUc63A=="], + "@relayfile/sdk": ["@relayfile/sdk@0.10.79", "", { "dependencies": { "@relayfile/core": "0.10.79", "ignore": "^7.0.5", "tar": "^7.5.10" }, "optionalDependencies": { "@relayfile/cli-darwin-arm64": "0.10.79", "@relayfile/cli-darwin-x64": "0.10.79", "@relayfile/cli-linux-arm64": "0.10.79", "@relayfile/cli-linux-x64": "0.10.79", "@relayfile/cli-win32-arm64": "0.10.79", "@relayfile/cli-win32-x64": "0.10.79", "@relayfile/mount-darwin-arm64": "0.10.79", "@relayfile/mount-darwin-x64": "0.10.79", "@relayfile/mount-linux-arm64": "0.10.79", "@relayfile/mount-linux-x64": "0.10.79" } }, "sha512-izrsq3F4b9g5GXslrsNVuCdbYHMSGi/XN/Ge5DPXWDaLLdTbTXkWDXdhvPhstE48zsoI5UtWv8kHcfarJRvw8g=="], "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.63.1", "", { "os": "android", "cpu": "arm" }, "sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ=="], @@ -454,7 +454,7 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "undici": ["undici@7.30.1", "", {}, "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg=="], + "undici": ["undici@7.30.2", "", {}, "sha512-mLyPQnHwUxaM/rideoK/+KL8DaAJLRl4aBCfmX444aCSLnIaomqPLtNRe2jdCYcsk5wZzXrDIQC8ZeYNRAYyIA=="], "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], diff --git a/packages/surface/package-lock.json b/packages/surface/package-lock.json index f8b86e276..cdad39cd3 100644 --- a/packages/surface/package-lock.json +++ b/packages/surface/package-lock.json @@ -20,7 +20,7 @@ "node": ">=20.19.0 || >=22.12.0" }, "peerDependencies": { - "@relayfile/relay-helpers": "0.6.1" + "@relayfile/relay-helpers": "0.6.2" } }, "node_modules/@esbuild/aix-ppc64": { @@ -504,9 +504,9 @@ } }, "node_modules/@relayfile/adapter-core": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-core/-/adapter-core-0.8.5.tgz", - "integrity": "sha512-J10VAyHz1P7wQDKKmVCJD+2kORQs1icP7CtqG1u8r0wO73S76UStimPsCzlGl9UhVhzqdkCZ7wf+GKH9f4N6Aw==", + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-core/-/adapter-core-0.8.7.tgz", + "integrity": "sha512-+6Vl3YsestQN6QhfL42faP5CbdVP/Cpl44m1vdw9ENVi4eyz/GwyD+aJe/Ws7jD/w+ctrQbYVEXl8WOaSayULQ==", "license": "Apache-2.0", "peer": true, "dependencies": { @@ -526,13 +526,13 @@ } }, "node_modules/@relayfile/adapter-linear": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-linear/-/adapter-linear-0.6.1.tgz", - "integrity": "sha512-BeTSUcm0+vN4krpESFiAfvjJ/WesxKAKhpdQM6uuNYWyl3efNXMj5Qe5nDGCSO2QHMyhKAZYjCyzzgqB9YnqQw==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-linear/-/adapter-linear-0.6.2.tgz", + "integrity": "sha512-oaN0pJ9GBRMjGvR5y+Ozl94RerxPpTbX1E0ygR7hmeE4JMOEFFf3sKRKg1PaSHu6t7LIF1DxXxeXBgvGlc38Yw==", "license": "Apache-2.0", "peer": true, "dependencies": { - "@relayfile/adapter-core": "^0.8.5" + "@relayfile/adapter-core": "^0.8.7" }, "engines": { "node": ">=18" @@ -542,13 +542,13 @@ } }, "node_modules/@relayfile/adapter-reddit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@relayfile/adapter-reddit/-/adapter-reddit-0.4.1.tgz", - "integrity": "sha512-Mz57v1vIE5sEy5F4Z7ix550Ga6l615lgQi0QDc8kgjWiUD9QqZW+Wm+iG+96S4vIQueM70pm60/fitrGGnIGAw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@relayfile/adapter-reddit/-/adapter-reddit-0.4.2.tgz", + "integrity": "sha512-EkoNy+CqVGm5sivaPUzHALnoH20gWzJwIO8OvPNpD4wTPk/MB7AcZarrCQ+5cAJ1OxHOJj4h1ZNVJzhmtEYizQ==", "license": "Apache-2.0", "peer": true, "dependencies": { - "@relayfile/adapter-core": "^0.8.5" + "@relayfile/adapter-core": "^0.8.7" }, "engines": { "node": ">=18" @@ -558,9 +558,9 @@ } }, "node_modules/@relayfile/cli-darwin-arm64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-darwin-arm64/-/cli-darwin-arm64-0.10.76.tgz", - "integrity": "sha512-c+hoYqXm2V6poQNCgFM2Ls+rjh2/v5n/JRc9lWQPthKsiWCj+pN+2whltv5VmH4JZPeIxY5co9oOnZEGYxTrxQ==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-darwin-arm64/-/cli-darwin-arm64-0.10.79.tgz", + "integrity": "sha512-Far6bxu5nhZfSlZ7eAZHSjULvKOrADxvYPUfFZofPAJR5Y132FnIc2SRi/HeQbmB3LpQtt7WYBXW/JlEJxq8EQ==", "cpu": [ "arm64" ], @@ -572,9 +572,9 @@ "peer": true }, "node_modules/@relayfile/cli-darwin-x64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-darwin-x64/-/cli-darwin-x64-0.10.76.tgz", - "integrity": "sha512-WZ0y+ky7HkNdXKPqVEvyaw/B8so8GxlQiJtbuv1o+k6WOvFtraVtfvtfD9MSoEI4JnF2LCMvhcu5+p2TtyE3Ow==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-darwin-x64/-/cli-darwin-x64-0.10.79.tgz", + "integrity": "sha512-lk8Cia0Smn77ib4eit6ZicbBIHYJSSj7I725V5RG0JYaQ0GZ/OR6vk4kRP59kGT5v4JJqnOrj36LwYZFbOHKow==", "cpu": [ "x64" ], @@ -586,9 +586,9 @@ "peer": true }, "node_modules/@relayfile/cli-linux-arm64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-linux-arm64/-/cli-linux-arm64-0.10.76.tgz", - "integrity": "sha512-/OnmA3omX5u3ECk4tZbGsdGCydnqJqZXvVC3JfursA6krj5Eo41XAQP6p4VmoocTSdYSkW5jke0QCNzObg1nAQ==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-linux-arm64/-/cli-linux-arm64-0.10.79.tgz", + "integrity": "sha512-3D7zOi0EXef3wYVaaLo8+y4Me4plryyDpk+NMvWl/4vSVohq8FVjegdfJobvLy62jm51ep0skXT5QILCZ/lIkg==", "cpu": [ "arm64" ], @@ -600,9 +600,9 @@ "peer": true }, "node_modules/@relayfile/cli-linux-x64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-linux-x64/-/cli-linux-x64-0.10.76.tgz", - "integrity": "sha512-644dg1zSJW82emAudfDoO9hsE0ltZ228/IpmCEqiVHPRRS0+et7WfnUhFlmbkfY50UqJEbX/oFLrZdFcOXNfTw==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-linux-x64/-/cli-linux-x64-0.10.79.tgz", + "integrity": "sha512-dSNqIwOnCwl35jlG8IDBxXlYgenPtgAGNIZMnTZJmJZqeMLt5cHxwUDCFQVoEBrejc3z8zViGpD9OnszV3ZH4w==", "cpu": [ "x64" ], @@ -614,9 +614,9 @@ "peer": true }, "node_modules/@relayfile/cli-win32-arm64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-win32-arm64/-/cli-win32-arm64-0.10.76.tgz", - "integrity": "sha512-7s2u/ZCC5Wr7OjqrhuepZaE2uvv67+cECcxpQsC1qNZeY4Vh0Qxml1x2w77tcvLHQotH3qU1w9LRECmhX7Mm5Q==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-win32-arm64/-/cli-win32-arm64-0.10.79.tgz", + "integrity": "sha512-ZDtUrIn7aB8rfE25Eswa1ucqPm0cXq0k9vs0cz4ICihmxMc/o+vGA3nbiprmhggyrd+IE7GwSpP/y8n9BOUiNQ==", "cpu": [ "arm64" ], @@ -628,9 +628,9 @@ "peer": true }, "node_modules/@relayfile/cli-win32-x64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/cli-win32-x64/-/cli-win32-x64-0.10.76.tgz", - "integrity": "sha512-e2cbYM+xPvGUQ2G+Hzh/s0y07pTdalGDBRgmpgfyxZok4/jUpF0oxgt5VVVQi5tTZMCvDciTp2ZBHHtjqQ8zuQ==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/cli-win32-x64/-/cli-win32-x64-0.10.79.tgz", + "integrity": "sha512-rW/k8cEmZIwfFTW2KmYtXFaCJEcoapPCAgFnjfjc8SezkRhV2dC3o5T+htpJLPaUehfCjarKAcONZI7Hotl16Q==", "cpu": [ "x64" ], @@ -642,9 +642,9 @@ "peer": true }, "node_modules/@relayfile/core": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/core/-/core-0.10.76.tgz", - "integrity": "sha512-fwcGn8wqKjIaZPj7cpaIwqFCY/TZlHUWjrirunUNlUjEdYk8VtrjZYBzFLRF3fOQz7hPvsokZahxwCvyyeqEtg==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/core/-/core-0.10.79.tgz", + "integrity": "sha512-fPWya8TqUN7ypx9cgh85+4SFgjbiyWdPxyRYTXbdFVqZkSGvBu7nGu6D8OqGZyewlmXr7g6WhdIm1B3bcLIDHA==", "license": "Apache-2.0", "peer": true, "engines": { @@ -652,9 +652,9 @@ } }, "node_modules/@relayfile/mount-darwin-arm64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/mount-darwin-arm64/-/mount-darwin-arm64-0.10.76.tgz", - "integrity": "sha512-WlYaBzCKIB/m7hxRgHhDFNSRsEDaHBwaIrj6WZ+YfVOeVciFwE9jLIwKX1Ku3Dm32uimwDQM9PT6LJD0EzKtxw==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/mount-darwin-arm64/-/mount-darwin-arm64-0.10.79.tgz", + "integrity": "sha512-5OQSQk5xJRs226u5yRWbI/tcybTV3dWGOuSwvouCNpaoU3MgargZgg+mieqNk4ketKgV1rufeKs7pMBp6ou6zQ==", "cpu": [ "arm64" ], @@ -666,9 +666,9 @@ "peer": true }, "node_modules/@relayfile/mount-darwin-x64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/mount-darwin-x64/-/mount-darwin-x64-0.10.76.tgz", - "integrity": "sha512-41MorpFsVEzJPpLxnaIcgrDIhxj+hUzdMdh57M8/9GOXkLJY6b+6MWz1yPPlA0X3r6dkoxd/5reNqQmDBV8fQg==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/mount-darwin-x64/-/mount-darwin-x64-0.10.79.tgz", + "integrity": "sha512-r9PFhR0s8G+oU891SAw2qh8Ne7e/cVBtsV7qnhUUv6Mnt9+gnybB7vPmOj4vLvBvk7TkM6OSe+WaZWMTV/KVrg==", "cpu": [ "x64" ], @@ -680,9 +680,9 @@ "peer": true }, "node_modules/@relayfile/mount-linux-arm64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/mount-linux-arm64/-/mount-linux-arm64-0.10.76.tgz", - "integrity": "sha512-I/xkA/QED/DNDqapTEL7uTcc5UPJ/aAirSulCA3Y3yA7TnMv4I5QK+l2EDXzoxDTiF1LoadEtCZoTzRE0MeiLQ==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/mount-linux-arm64/-/mount-linux-arm64-0.10.79.tgz", + "integrity": "sha512-HnnjnIeQg8J1pIi6ufHRhDg/tn7raOX3Sm59tpwdQHikLxpPtQVSldg4k5NZrkUw+pCEhLGVJITX507LR4Bq7Q==", "cpu": [ "arm64" ], @@ -694,9 +694,9 @@ "peer": true }, "node_modules/@relayfile/mount-linux-x64": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/mount-linux-x64/-/mount-linux-x64-0.10.76.tgz", - "integrity": "sha512-PRVNoCyJrJZSHMB1YnxzfYosdi5eugAyKJvmze8qnnS/uIGMtsFdWHtdBs9LOp/Lx5QzGV6q7Rmaa35GkbpLQQ==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/mount-linux-x64/-/mount-linux-x64-0.10.79.tgz", + "integrity": "sha512-R77dNUxQ7sFxtBZZxIz5mtawyAHenkhlJpIJ/xiiaWLlBuOnAUgeRC/eQGdPN/FGAp2qbTmVK/Y/wEAM652DnQ==", "cpu": [ "x64" ], @@ -708,25 +708,25 @@ "peer": true }, "node_modules/@relayfile/relay-helpers": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@relayfile/relay-helpers/-/relay-helpers-0.6.1.tgz", - "integrity": "sha512-C43jTVFwsqoiyGoS2RczvGgpSyeu9+v7q9nDKZj2NJp9WBqRHTZd6DlU2jH/OB1ovnY4cIGbH3o7TMdNLc50aQ==", + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@relayfile/relay-helpers/-/relay-helpers-0.6.2.tgz", + "integrity": "sha512-MWyj0g0ODoqeoZkZoLS2Ea7QCC6F7wJS8WRWPMDSK2JkekVDB+2gwSagvTfGygYquQCl0uU2wXwc2KQwFAvFKg==", "license": "Apache-2.0", "peer": true, "dependencies": { - "@relayfile/adapter-core": "^0.8.5", - "@relayfile/adapter-linear": "^0.6.1", - "@relayfile/adapter-reddit": "^0.4.1" + "@relayfile/adapter-core": "^0.8.7", + "@relayfile/adapter-linear": "^0.6.2", + "@relayfile/adapter-reddit": "^0.4.2" } }, "node_modules/@relayfile/sdk": { - "version": "0.10.76", - "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.10.76.tgz", - "integrity": "sha512-/4PiO5FxsdF+IQ4MfZ6+eOe8ml1PU2CLdEzSpAbuPhO4nDT8npuZwOzXOs5KFv/tqPG9ldWnLTsUqPPpaUc63A==", + "version": "0.10.79", + "resolved": "https://registry.npmjs.org/@relayfile/sdk/-/sdk-0.10.79.tgz", + "integrity": "sha512-izrsq3F4b9g5GXslrsNVuCdbYHMSGi/XN/Ge5DPXWDaLLdTbTXkWDXdhvPhstE48zsoI5UtWv8kHcfarJRvw8g==", "license": "Apache-2.0", "peer": true, "dependencies": { - "@relayfile/core": "0.10.76", + "@relayfile/core": "0.10.79", "ignore": "^7.0.5", "tar": "^7.5.10" }, @@ -734,16 +734,16 @@ "node": ">=18" }, "optionalDependencies": { - "@relayfile/cli-darwin-arm64": "0.10.76", - "@relayfile/cli-darwin-x64": "0.10.76", - "@relayfile/cli-linux-arm64": "0.10.76", - "@relayfile/cli-linux-x64": "0.10.76", - "@relayfile/cli-win32-arm64": "0.10.76", - "@relayfile/cli-win32-x64": "0.10.76", - "@relayfile/mount-darwin-arm64": "0.10.76", - "@relayfile/mount-darwin-x64": "0.10.76", - "@relayfile/mount-linux-arm64": "0.10.76", - "@relayfile/mount-linux-x64": "0.10.76" + "@relayfile/cli-darwin-arm64": "0.10.79", + "@relayfile/cli-darwin-x64": "0.10.79", + "@relayfile/cli-linux-arm64": "0.10.79", + "@relayfile/cli-linux-x64": "0.10.79", + "@relayfile/cli-win32-arm64": "0.10.79", + "@relayfile/cli-win32-x64": "0.10.79", + "@relayfile/mount-darwin-arm64": "0.10.79", + "@relayfile/mount-darwin-x64": "0.10.79", + "@relayfile/mount-linux-arm64": "0.10.79", + "@relayfile/mount-linux-x64": "0.10.79" } }, "node_modules/@rollup/rollup-android-arm-eabi": { @@ -3098,9 +3098,9 @@ } }, "node_modules/undici": { - "version": "7.30.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", - "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "version": "7.30.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.2.tgz", + "integrity": "sha512-mLyPQnHwUxaM/rideoK/+KL8DaAJLRl4aBCfmX444aCSLnIaomqPLtNRe2jdCYcsk5wZzXrDIQC8ZeYNRAYyIA==", "license": "MIT", "peer": true, "engines": { diff --git a/packages/surface/package.json b/packages/surface/package.json index 08468e842..c2e5d24ff 100644 --- a/packages/surface/package.json +++ b/packages/surface/package.json @@ -64,7 +64,7 @@ "directory": "packages/surface" }, "peerDependencies": { - "@relayfile/relay-helpers": "0.6.1" + "@relayfile/relay-helpers": "0.6.2" }, "dependencies": { "ai-hist": "0.4.1" diff --git a/scripts/build-standalone-cli.mjs b/scripts/build-standalone-cli.mjs index e50086bfb..f4fa6e615 100644 --- a/scripts/build-standalone-cli.mjs +++ b/scripts/build-standalone-cli.mjs @@ -31,5 +31,6 @@ process.exitCode = await runCli(process.argv.slice(2), undefined, { version: ${J detachedReceipt, selfCommand: [process.execPath] }); `); bun(['build', entry, '--compile', '--target='+target, '--outfile='+resolve(outfile), - '--env=disable', '--no-compile-autoload-dotenv', '--no-compile-autoload-bunfig']); + '--env=disable', '--no-compile-autoload-dotenv', '--no-compile-autoload-bunfig', + '--compile-autoload-package-json']); } finally { await rm(stage, { recursive: true, force: true }); } diff --git a/scripts/gitlab-collection-canary.mjs b/scripts/gitlab-collection-canary.mjs new file mode 100644 index 000000000..4349964e6 --- /dev/null +++ b/scripts/gitlab-collection-canary.mjs @@ -0,0 +1,132 @@ +#!/usr/bin/env node +// Exercise a supplied standalone CLI and daemon, including its embedded helper +// transport. Synthetic local mount only; this is not hosted/customer proof. +import assert from 'node:assert/strict'; +import { execFile, spawn } from 'node:child_process'; +import { createHash } from 'node:crypto'; +import { once } from 'node:events'; +import { access, mkdir, mkdtemp, readFile, realpath, rm, symlink, writeFile } from 'node:fs/promises'; +import { createRequire } from 'node:module'; +import { tmpdir } from 'node:os'; +import { dirname, join, resolve } from 'node:path'; +import { promisify } from 'node:util'; + +const options = process.argv.slice(2); +assert.equal(options.length, 6, 'usage: gitlab-collection-canary.mjs --flows --relayflowd <--surface-version exact-published-version|--surface-tarball candidate.tgz>'); +assert.equal(options[0], '--flows'); +assert.equal(options[2], '--relayflowd'); +assert.ok(['--surface-version', '--surface-tarball'].includes(options[4])); +const published = options[4] === '--surface-version'; +if (published) assert.match(options[5], /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/); +const surfaceInput = published ? `@relayflows/surface@${options[5]}` : resolve(options[5]); +const tarballSha256 = published ? undefined : createHash('sha256').update(await readFile(surfaceInput)).digest('hex'); +const flows = resolve(options[1]); +const relayflowd = resolve(options[3]); +await Promise.all([access(flows), access(relayflowd)]); +const directory = await realpath(await mkdtemp(join(tmpdir(), 'flows-gitlab-canary-'))); +const mount = join(directory, 'mount'); +const data = join(directory, 'journal'); +const projectPath = 'canary/subgroup/project'; +const prefix = `/gitlab/projects/${projectPath}`; +const issues = Array.from({ length: 8 }, (_, index) => ({ iid: index + 1, title: `issue ${index + 1}`, state: index === 7 ? 'closed' : 'opened' })); +const requests = [{ iid: 9, title: 'merged request', state: 'merged' }]; +const fixtures = { + ...Object.fromEntries(issues.map(issue => [`${prefix}/issues/${issue.iid}__issue/meta.json`, issue])), + [`${prefix}/merge_requests/9__request/meta.json`]: requests[0], + [`${prefix}/issues/_index.json`]: issues.map(({ iid }) => ({ iid })), + [`${prefix}/merge_requests/_index.json`]: [{ iid: 9 }], + [`${prefix}/issues/1__issue/comments/1.json`]: { iid: 'child' }, + [`${prefix}/issues/1__issue/children/meta.json`]: { iid: 'grandchild' }, + [`${prefix}/issues/by-id/1.json`]: { iid: 'alias' }, + [`${prefix}/issues/by-id/1/meta.json`]: { iid: 'directory-alias' }, + '/gitlab/projects/canary/foreign/issues/1__other/meta.json': { iid: 'foreign-project' }, +}; +const env = { + PATH: process.env.PATH ?? '', HOME: directory, TMPDIR: tmpdir(), + FLOWS_AUTHORED_NODE: process.execPath, + RELAYFILE_MOUNT_PATH: mount, + RELAYFLOWS_GITLAB_MOCK: '0', FLOWS_CLOUD_MIRROR: '0', +}; +let daemon; +let daemonError = ''; +try { + await writeFile(join(directory, 'package.json'), JSON.stringify({ private: true, type: 'module' })); + // Install the exact registry release or explicitly labelled candidate pack + // beside the authored source, with no workspace links or parent fallback. + await promisify(execFile)('npm', ['install', '--ignore-scripts', '--no-audit', '--no-fund', '--omit=dev', + '--registry=https://registry.npmjs.org', '--save-exact', surfaceInput], { cwd: directory, env, timeout: 120_000 }); + const surfaceRoot = join(directory, 'node_modules/@relayflows/surface'); + assert.equal(await realpath(surfaceRoot), surfaceRoot, 'Surface must be a physical registry installation'); + const manifestBytes = await readFile(join(surfaceRoot, 'package.json')); + const surface = JSON.parse(manifestBytes); + assert.equal(surface.name, '@relayflows/surface'); + if (published) assert.equal(surface.version, options[5]); + const require = createRequire(join(directory, 'package.json')); + assert.equal(await realpath(require.resolve('@relayflows/surface')), join(surfaceRoot, 'dist/index.js')); + const runtime = require.resolve('@relayflows/surface/runtime'); + assert.equal(await realpath(runtime), join(surfaceRoot, 'dist/runtime.js')); + assert.equal(await realpath(join(surfaceRoot, surface.exports['.'].types)), join(surfaceRoot, 'dist/index.d.ts')); + const helpersRoot = join(directory, 'node_modules/@relayfile/relay-helpers'); + assert.equal(await realpath(helpersRoot), helpersRoot); + const helpers = JSON.parse(await readFile(join(helpersRoot, 'package.json'), 'utf8')); + assert.equal(helpers.version, surface.peerDependencies['@relayfile/relay-helpers']); + const runtimeSha256 = createHash('sha256').update(await readFile(runtime)).digest('hex'); + const manifestSha256 = createHash('sha256').update(manifestBytes).digest('hex'); + const lock = JSON.parse(await readFile(join(directory, 'package-lock.json'), 'utf8')); + const packageIntegrity = lock.packages['node_modules/@relayflows/surface'].integrity; + assert.match(packageIntegrity, /^sha512-/); + for (const [path, value] of Object.entries(fixtures)) { + const target = join(mount, path); + await mkdir(dirname(target), { recursive: true }); + await writeFile(target, JSON.stringify(value)); + } + await symlink('1__issue', join(mount, prefix, 'issues', 'linked-record')); + const flow = join(directory, 'gitlab-collection-canary.flow.ts'); + await writeFile(flow, `import { flow } from '@relayflows/surface'; +import { deepStrictEqual } from 'node:assert/strict'; +export default flow('gitlab-collection-canary', { tools: { gitlab: true } }, async f => { + const issues = await f.gitlab.issues.list({ projectPath: ${JSON.stringify(projectPath)} }); + const requests = await f.gitlab['merge-requests'].list({ projectPath: ${JSON.stringify(projectPath)} }); + deepStrictEqual(issues, ${JSON.stringify(issues)}, 'GitLab issue collection mismatch'); + deepStrictEqual(requests, ${JSON.stringify(requests)}, 'GitLab MR collection mismatch'); + f.done('success'); +}); +`); + daemon = spawn(relayflowd, ['--data-dir', data, 'serve'], { env, stdio: ['ignore', 'ignore', 'pipe'] }); + daemon.stderr.on('data', chunk => { daemonError += chunk; }); + const daemonStarted = new Promise((_, reject) => daemon.once('error', reject)); + // The file is only a boot hint. The CLI must then perform its real handshake + // and run both journaled helper reads before this script reports success. + await Promise.race([daemonStarted, (async () => { + for (let attempt = 0; attempt < 250; attempt++) { + if (daemon.exitCode !== null) throw new Error(`canary daemon exited: ${daemonError}`); + try { await access(join(data, 'connection.json')); return; } catch {} + await new Promise(resolveWait => setTimeout(resolveWait, 20)); + } + throw new Error(`canary daemon did not start: ${daemonError}`); + })()]); + const args = ['run', '--json', '--no-spawn', '--no-observer-link', '--data-dir', data, flow, '--input', '{}']; + const { stdout, stderr } = await promisify(execFile)(flows, args, { env, cwd: directory, timeout: 90_000, maxBuffer: 4 * 1024 * 1024 }); + const report = JSON.parse(stdout); + assert.equal(report.ok, true, stdout + stderr); + assert.equal(report.path, flow, stdout + stderr); + assert.equal(report.completionReason, 'success', stdout + stderr); + assert.equal(typeof report.runId, 'string'); + const sha256 = createHash('sha256').update(await readFile(flows)).digest('hex'); + const daemonSha256 = createHash('sha256').update(await readFile(relayflowd)).digest('hex'); + console.log(JSON.stringify({ proof: 'standalone-cli-synthetic-gitlab-collections', sha256, + daemonSha256, artifactSource: published ? 'registry' : 'candidate-tarball', + surface: { tarballSha256, packageIntegrity, manifestSha256, + version: surface.version, runtimeSha256, helpersVersion: helpers.version }, issues: 8, mergeRequests: 1, report })); +} finally { + if (daemon?.pid && daemon.exitCode === null && daemon.signalCode === null) { + const exited = once(daemon, 'exit'); + daemon.kill('SIGTERM'); + let timer; + try { + const stopped = await Promise.race([exited.then(() => true), new Promise(resolveWait => { timer = setTimeout(() => resolveWait(false), 2_000); })]); + if (!stopped) { daemon.kill('SIGKILL'); await exited; } + } finally { clearTimeout(timer); } + } + await rm(directory, { recursive: true, force: true }); +}