From fec89f29d8bd33f7a57d8da1284c2786d1b2b9e4 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Sun, 19 Apr 2026 16:32:07 +0100 Subject: [PATCH 01/11] append collections id --- packages/ws-worker/src/util/convert-lightning-plan.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ws-worker/src/util/convert-lightning-plan.ts b/packages/ws-worker/src/util/convert-lightning-plan.ts index 7723e2a0b..81463d21b 100644 --- a/packages/ws-worker/src/util/convert-lightning-plan.ts +++ b/packages/ws-worker/src/util/convert-lightning-plan.ts @@ -234,6 +234,7 @@ export default ( plan.workflow.credentials = { collections_token: true, collections_endpoint: true, + project_id: run.project_id, }; } } From 3ff6e59cae72d7adfc60cdc92ced472db6526512 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 13:28:32 +0100 Subject: [PATCH 02/11] types --- packages/cli/src/collections/command.ts | 1 + packages/lexicon/lightning.d.ts | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/collections/command.ts b/packages/cli/src/collections/command.ts index 4dd518ad0..56e6ee395 100644 --- a/packages/cli/src/collections/command.ts +++ b/packages/cli/src/collections/command.ts @@ -89,6 +89,7 @@ const key = { }; const endpoint = { + // TODO in docs, prefer endpoint to lightning name: 'endpoint', yargs: { alias: ['e', 'lightning'], diff --git a/packages/lexicon/lightning.d.ts b/packages/lexicon/lightning.d.ts index 870696462..81d9ac5d3 100644 --- a/packages/lexicon/lightning.d.ts +++ b/packages/lexicon/lightning.d.ts @@ -30,6 +30,9 @@ export type LightningPlan = { /** The human readable name of the workflow. Not currently sent by Lightning. */ name?: string; + /** The id of the project which owns this plan */ + project_id?: string; + dataclip_id: string; starting_node_id: string; @@ -129,7 +132,11 @@ export type CHANNEL_LEAVE = 'socket:channel-leave'; export type CLAIM = 'claim'; // This is the payload in the message sent to lightning -export type ClaimPayload = { demand?: number; worker_name: string | null; queues?: string[] }; +export type ClaimPayload = { + demand?: number; + worker_name: string | null; + queues?: string[]; +}; // This is the response from lightning export type ClaimReply = { runs: Array }; From 30aaf97c5632592723181767f5fca686cc1eefc0 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 16:09:12 +0100 Subject: [PATCH 03/11] update tests --- packages/cli/src/collections/command.ts | 13 +++++++ packages/cli/src/collections/handler.ts | 11 ++++-- packages/cli/src/collections/request.ts | 5 +++ .../cli/test/collections/collections.test.ts | 39 ++++++++++--------- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/cli/src/collections/command.ts b/packages/cli/src/collections/command.ts index 56e6ee395..fc800dcf1 100644 --- a/packages/cli/src/collections/command.ts +++ b/packages/cli/src/collections/command.ts @@ -15,6 +15,7 @@ export type CollectionsOptions = Pick & { token?: string; key: string; collectionName: string; + projectId?: string; }; export type GetOptions = CollectionsOptions & @@ -106,6 +107,17 @@ const pageSize = { }, }; +const projectId = { + name: 'project-id', + yargs: { + alias: ['p'], + // TODO maybe CLI should be smart and support a local alias here + // Or if inside a workspace, use that + description: 'The UUID of the project which owns this collection', + type: 'string', + }, +}; + // TODO not working yet const limit = { name: 'limit', @@ -158,6 +170,7 @@ const getOptions = [ pageSize, limit, pretty, + projectId, createdBefore, createdAfter, diff --git a/packages/cli/src/collections/handler.ts b/packages/cli/src/collections/handler.ts index 43eafd011..33494b757 100644 --- a/packages/cli/src/collections/handler.ts +++ b/packages/cli/src/collections/handler.ts @@ -15,18 +15,18 @@ import { QueryOptions } from '@openfn/language-collections/types/collections'; const ensureToken = (opts: CollectionsOptions, logger: Logger) => { if (!('token' in opts)) { - if (process.env.OPENFN_PAT) { - const token = process.env.OPENFN_PAT; + const token = process.env.OPENFN_API_KEY ?? process.env.OPENFN_PAT; + if (token) { logger.info( `Using access token ending in ${token?.substring( token.length - 10 - )} from env (OPENFN_PAT)` + )} from env` ); opts.token = token; } else { logger.error('No access token detected!'); logger.error( - 'Ensure you pass a Personal Access Token (PAT) with --token $MY_TOKEN or set the OPENFN_PAT env var' + 'Ensure you pass a Personal Access Token (PAT) with --token $MY_TOKEN or set the OPENFN_API_KEY env var' ); logger.error( 'You can get a PAT from OpenFn, see https://docs.openfn.org/documentation/api-tokens' @@ -76,6 +76,7 @@ export const get = async (options: GetOptions, logger: Logger) => { key: options.key, collectionName: options.collectionName, query: buildQuery(options), + projectId: options.projectId, }, logger ); @@ -152,6 +153,7 @@ export const set = async (options: SetOptions, logger: Logger) => { key: options.key, collectionName: options.collectionName, data: { items }, + projectId: options.projectId, }, logger ); @@ -179,6 +181,7 @@ export const remove = async (options: RemoveOptions, logger: Logger) => { token: options.token!, key: options.key, collectionName: options.collectionName, + projectId: options.projectId, }, logger ); diff --git a/packages/cli/src/collections/request.ts b/packages/cli/src/collections/request.ts index cb4b2f8bb..5cd4616d3 100644 --- a/packages/cli/src/collections/request.ts +++ b/packages/cli/src/collections/request.ts @@ -3,6 +3,7 @@ import { request } from 'undici'; import type { Dispatcher } from 'undici'; import { Logger } from '../util'; import { throwAbortableError } from '../util/abort'; +import { projectId } from '../options'; // helper function to call out to the collections API @@ -11,6 +12,7 @@ type Options = { collectionName: string; token: string; lightning?: string; + projectId?: string; includeMeta?: boolean; // TODO ignored right now pageSize?: number; @@ -48,6 +50,9 @@ export default async ( }, options.query ); + if (options.projectId) { + query.project_id = options.projectId; + } const args: Partial = { headers, diff --git a/packages/cli/test/collections/collections.test.ts b/packages/cli/test/collections/collections.test.ts index c2063e5b1..8e4ee836d 100644 --- a/packages/cli/test/collections/collections.test.ts +++ b/packages/cli/test/collections/collections.test.ts @@ -13,6 +13,7 @@ import { readFile } from 'fs/promises'; // Log as json to make testing easier const logger = createMockLogger('default', { level: 'debug', json: true }); +const PROJECT = 'project-1'; const COLLECTION = 'test-collection-a'; const ENDPOINT = 'https://mock.openfn.org'; @@ -42,7 +43,7 @@ test.before(() => { test.beforeEach(() => { logger._reset(); api.reset(); - api.createCollection(COLLECTION); + api.createCollection(PROJECT, COLLECTION); loadData({ x: {}, y: {}, @@ -130,7 +131,7 @@ test.serial('get one key from a collection and write to disk', async (t) => { // So we'll test on the logs - it's good enough for today test.serial('get 200 items over 4 pages', async (t) => { api.reset(); - api.createCollection(COLLECTION); + api.createCollection(PROJECT, COLLECTION); new Array(300).fill(0).forEach((_v, idx) => { api.upsert( @@ -142,7 +143,7 @@ test.serial('get 200 items over 4 pages', async (t) => { }) ); }); - t.is(api.count(COLLECTION), 300); + t.is(api.count(PROJECT, COLLECTION), 300); const options = createOptions({ key: '*', @@ -168,10 +169,11 @@ test.serial('get 200 items over 4 pages', async (t) => { // This test uses an irregular page size test.serial('get 180 items over 4 pages', async (t) => { api.reset(); - api.createCollection(COLLECTION); + api.createCollection(PROJECT, COLLECTION); new Array(300).fill(0).forEach((_v, idx) => { api.upsert( + PROJECT, COLLECTION, idx, JSON.stringify({ @@ -180,7 +182,7 @@ test.serial('get 180 items over 4 pages', async (t) => { }) ); }); - t.is(api.count(COLLECTION), 300); + t.is(api.count(PROJECT, COLLECTION), 300); const options = createOptions({ key: '*', @@ -220,8 +222,9 @@ test.serial('set a single value', async (t) => { await set(options, logger); - t.is(api.count(COLLECTION), 3); - const item = api.asJSON(COLLECTION, 'z'); + t.is(api.count(PROJECT, COLLECTION), 3); + + const item = api.collectionsByProject[PROJECT][COLLECTION].z; t.deepEqual(item, { id: 'z' }); }); @@ -239,12 +242,12 @@ test.serial('set multiple values', async (t) => { await set(options, logger); - t.is(api.count(COLLECTION), 4); - const a = api.asJSON(COLLECTION, 'a'); - t.deepEqual(a, { id: 'a' }); + t.is(api.count(PROJECT, COLLECTION), 4); + + const col = api.collectionsByProject[PROJECT][COLLECTION]; + t.deepEqual(col.a, { id: 'a' }); - const b = api.asJSON(COLLECTION, 'b'); - t.deepEqual(b, { id: 'b' }); + t.deepEqual(col.b, { id: 'b' }); }); test.serial('set should throw if key and items are both set', async (t) => { @@ -270,12 +273,12 @@ test.serial('remove one key', async (t) => { await remove(options, logger); - const itemAfter = api.byKey(COLLECTION, 'x'); - t.falsy(itemAfter); + const col = api.collectionsByProject[PROJECT][COLLECTION]; + t.falsy(col.x); }); test.serial('remove multiple keys', async (t) => { - t.is(api.count(COLLECTION), 2); + t.is(api.count(PROJECT, COLLECTION), 2); const options = createOptions({ key: '*', @@ -283,11 +286,11 @@ test.serial('remove multiple keys', async (t) => { await remove(options, logger); - t.is(api.count(COLLECTION), 0); + t.is(api.count(PROJECT, COLLECTION), 0); }); test.serial('remove with dry run', async (t) => { - t.is(api.count(COLLECTION), 2); + t.is(api.count(PROJECT, COLLECTION), 2); const options = createOptions({ key: '*', @@ -296,7 +299,7 @@ test.serial('remove with dry run', async (t) => { await remove(options, logger); - t.is(api.count(COLLECTION), 2); + t.is(api.count(PROJECT, COLLECTION), 2); // Find the outputted keys const [, output] = logger._history.find( From 789c64be373ce7a8d8b502249ca8241c85414156 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 16:24:13 +0100 Subject: [PATCH 04/11] update tests and adaptor --- packages/cli/package.json | 4 +-- .../cli/test/collections/collections.test.ts | 13 ++++---- pnpm-lock.yaml | 33 +++++++++++++++++-- pnpm-workspace.yaml | 2 ++ 4 files changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 7f9b29d32..199fa1b33 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -33,10 +33,10 @@ "author": "Open Function Group ", "license": "ISC", "devDependencies": { - "@openfn/language-collections": "^0.8.3", + "@openfn/language-collections": "^0.9.0", "@openfn/language-common": "3.2.3", - "@types/lodash-es": "~4.17.12", "@types/json-diff": "^1.0.3", + "@types/lodash-es": "~4.17.12", "@types/mock-fs": "^4.13.4", "@types/node": "^18.19.130", "@types/rimraf": "^3.0.2", diff --git a/packages/cli/test/collections/collections.test.ts b/packages/cli/test/collections/collections.test.ts index 8e4ee836d..0da32ee85 100644 --- a/packages/cli/test/collections/collections.test.ts +++ b/packages/cli/test/collections/collections.test.ts @@ -24,6 +24,7 @@ let api: any; const loadData = (items: Record) => { for (const key in items) { api.upsert( + PROJECT, COLLECTION, key, JSON.stringify({ @@ -135,6 +136,7 @@ test.serial('get 200 items over 4 pages', async (t) => { new Array(300).fill(0).forEach((_v, idx) => { api.upsert( + PROJECT, COLLECTION, idx, JSON.stringify({ @@ -225,7 +227,7 @@ test.serial('set a single value', async (t) => { t.is(api.count(PROJECT, COLLECTION), 3); const item = api.collectionsByProject[PROJECT][COLLECTION].z; - t.deepEqual(item, { id: 'z' }); + t.deepEqual(JSON.parse(item), { id: 'z' }); }); test.serial('set multiple values', async (t) => { @@ -245,9 +247,9 @@ test.serial('set multiple values', async (t) => { t.is(api.count(PROJECT, COLLECTION), 4); const col = api.collectionsByProject[PROJECT][COLLECTION]; - t.deepEqual(col.a, { id: 'a' }); + t.deepEqual(JSON.parse(col.a), { id: 'a' }); - t.deepEqual(col.b, { id: 'b' }); + t.deepEqual(JSON.parse(col.b), { id: 'b' }); }); test.serial('set should throw if key and items are both set', async (t) => { @@ -264,8 +266,8 @@ test.serial('set should throw if key and items are both set', async (t) => { }); test.serial('remove one key', async (t) => { - const itemBefore = api.byKey(COLLECTION, 'x'); - t.truthy(itemBefore); + const col = api.collectionsByProject[PROJECT][COLLECTION]; + t.truthy(col.x); const options = createOptions({ key: 'x', @@ -273,7 +275,6 @@ test.serial('remove one key', async (t) => { await remove(options, logger); - const col = api.collectionsByProject[PROJECT][COLLECTION]; t.falsy(col.x); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 675581c6e..fa9301662 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -220,8 +220,8 @@ importers: version: 17.7.2 devDependencies: '@openfn/language-collections': - specifier: ^0.8.3 - version: 0.8.3 + specifier: ^0.9.0 + version: 0.9.0 '@openfn/language-common': specifier: 3.2.3 version: 3.2.3 @@ -1342,12 +1342,18 @@ packages: '@openfn/language-collections@0.8.3': resolution: {integrity: sha512-jymBp77rQKUBojTKERGZQ/RhF2YRojUKt1Vg6J28vSH+m9gwz9Sdh/5zBXSHv4qV6SURmW6+4R6e3sOAVWUpUw==} + '@openfn/language-collections@0.9.0': + resolution: {integrity: sha512-7crUlbIEW4qXbcZMDV6FxepMWu9AZlU/4BwBy7p5lo15Pr4XOQR6t9EOlBwo+lg4jRWx6I2hEUeRw5RQP61oOw==} + '@openfn/language-common@2.0.1': resolution: {integrity: sha512-eiBcgjEzRrZL/sr/ULK/GUQSzktvThbAoorWDM3nXHq22d4OAJkePfFPY4mb7xveCKDNBADTWY39j7CgPiI9Jw==} '@openfn/language-common@3.2.3': resolution: {integrity: sha512-XvDGPwGCaaGPNaAHjAS44uH1q8XIsE5tjcr2SyqmMEJgqHJWRdpN6d5B+UrZVmbUaNisigBp5fwsYHsC/F4uPg==} + '@openfn/language-common@3.3.1': + resolution: {integrity: sha512-WBdDjA1gf8zmOZ6J7Y47o1reQa/np15oKFQ9EEJSMbJg8kTTbJmHU0V3ibL40M8dPVJBvr5b5UFzKytqNvSCCw==} + '@openfn/language-http@6.4.3': resolution: {integrity: sha512-8ihgIYId+ewMuNU9hbe5JWEWvaJInDrIEiy4EyO7tbzu5t/f1kO18JIzQWm6r7dcHiMfcG2QaXe6O3br1xOrDA==} @@ -4229,6 +4235,10 @@ packages: resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} engines: {node: '>=20.18.1'} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} + universalify@0.1.2: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} @@ -4896,6 +4906,12 @@ snapshots: stream-json: 1.9.1 undici: 7.24.4 + '@openfn/language-collections@0.9.0': + dependencies: + '@openfn/language-common': 3.3.1 + stream-json: 1.9.1 + undici: 7.25.0 + '@openfn/language-common@2.0.1': dependencies: ajv: 8.18.0 @@ -4918,6 +4934,17 @@ snapshots: lodash: 4.17.23 undici: 7.24.4 + '@openfn/language-common@3.3.1': + dependencies: + ajv: 8.18.0 + csv-parse: 5.6.0 + csvtojson: 2.0.14 + date-fns: 2.30.0 + http-status-codes: 2.3.0 + jsonpath-plus: 10.4.0 + lodash: 4.18.1 + undici: 7.25.0 + '@openfn/language-http@6.4.3': dependencies: '@openfn/language-common': 2.0.1 @@ -7876,6 +7903,8 @@ snapshots: undici@7.24.4: {} + undici@7.25.0: {} + universalify@0.1.2: {} unpipe@1.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 38271f34d..71629c205 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -10,6 +10,8 @@ packages: - '!**/test/**' minimumReleaseAge: 1440 +minimumReleaseAgeExclude: + - '@openfn/*' onlyBuiltDependencies: - '@swc/core' From 69bdeff6d7e00473ff2a878e2956dd2c203c9cf2 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 16:35:02 +0100 Subject: [PATCH 05/11] add extra tests --- packages/cli/src/collections/request.ts | 4 +++ .../cli/test/collections/collections.test.ts | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/packages/cli/src/collections/request.ts b/packages/cli/src/collections/request.ts index 5cd4616d3..01ebb35f5 100644 --- a/packages/cli/src/collections/request.ts +++ b/packages/cli/src/collections/request.ts @@ -135,6 +135,10 @@ async function handleError(logger: Logger, response: Dispatcher.ResponseData) { let fix; switch (response.statusCode) { + case 409: + message = `409: multiple collection names matched`; + fix = `Pass --project-id to disambiguate the request`; + break; case 404: message = `404: collection not found`; fix = `Ensure the Collection has been created on the admin page`; diff --git a/packages/cli/test/collections/collections.test.ts b/packages/cli/test/collections/collections.test.ts index 0da32ee85..d761bdd6f 100644 --- a/packages/cli/test/collections/collections.test.ts +++ b/packages/cli/test/collections/collections.test.ts @@ -337,6 +337,39 @@ test.serial("should throw if a collection doesn't exist", async (t) => { } }); +test.serial('should throw if a collection is ambiguous', async (t) => { + api.createCollection('project-2', COLLECTION); + + const options = createOptions({ + key: '*', + collectionName: COLLECTION, + }); + try { + await get(options, logger); + } catch (e: any) { + t.regex(e.reason, /409: multiple collection names matched/i); + } +}); + +test.serial('do not throw if project_id is passed', async (t) => { + api.createCollection('project-2', COLLECTION); + + api.upsert('project-2', COLLECTION, 'x', JSON.stringify({ id: 'x' })); + + const options = createOptions({ + key: 'x', + collectionName: COLLECTION, + projectId: 'project-2', + }); + + await get(options, logger); + + const [_level, log] = logger._history.at(-1); + t.deepEqual(log.message[0], { + id: 'x', + }); +}); + test.serial('use OPENFN_ENDPOINT if endpoint option is not set', async (t) => { const options = createOptions({ key: 'x', From 9455d3ea12da21816a96ac90bd56ff65cf657d48 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 16:47:54 +0100 Subject: [PATCH 06/11] types --- packages/cli/src/collections/request.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/cli/src/collections/request.ts b/packages/cli/src/collections/request.ts index 01ebb35f5..82be2ff12 100644 --- a/packages/cli/src/collections/request.ts +++ b/packages/cli/src/collections/request.ts @@ -3,7 +3,6 @@ import { request } from 'undici'; import type { Dispatcher } from 'undici'; import { Logger } from '../util'; import { throwAbortableError } from '../util/abort'; -import { projectId } from '../options'; // helper function to call out to the collections API From ea05c4b1b334c7c9087a7f971f80964e1bb4ab75 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Mon, 20 Apr 2026 17:43:42 +0100 Subject: [PATCH 07/11] fix tests --- packages/ws-worker/src/util/convert-lightning-plan.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ws-worker/src/util/convert-lightning-plan.ts b/packages/ws-worker/src/util/convert-lightning-plan.ts index 81463d21b..2d24190da 100644 --- a/packages/ws-worker/src/util/convert-lightning-plan.ts +++ b/packages/ws-worker/src/util/convert-lightning-plan.ts @@ -234,8 +234,10 @@ export default ( plan.workflow.credentials = { collections_token: true, collections_endpoint: true, - project_id: run.project_id, }; + if (run.project_id) { + plan.workflow.credentials.project_id = run.project_id; + } } } From 6a619f2ce9c6d2a8501e163fd1eabcbf8a076303 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 21 Apr 2026 11:24:46 +0100 Subject: [PATCH 08/11] load project id from env --- packages/cli/src/collections/command.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/collections/command.ts b/packages/cli/src/collections/command.ts index fc800dcf1..0a25d5f55 100644 --- a/packages/cli/src/collections/command.ts +++ b/packages/cli/src/collections/command.ts @@ -113,9 +113,15 @@ const projectId = { alias: ['p'], // TODO maybe CLI should be smart and support a local alias here // Or if inside a workspace, use that - description: 'The UUID of the project which owns this collection', + description: + 'The UUID of the project which owns this collection. Set via env var OPENFN_PROJECT_ID', type: 'string', }, + ensure: (opts: any) => { + if (!opts.projectId) { + opts.projectId = process.env.OPENFN_PROJECT_ID; + } + }, }; // TODO not working yet @@ -164,13 +170,13 @@ const updatedAfter = { const getOptions = [ collectionName, + projectId, key, o.apiKey, endpoint, pageSize, limit, pretty, - projectId, createdBefore, createdAfter, @@ -206,6 +212,7 @@ const dryRun = { const removeOptions = [ collectionName, + projectId, key, o.apiKey, endpoint, @@ -246,6 +253,7 @@ const items = { const setOptions = [ collectionName, + projectId, override(key as any, { demand: false, }), From 7ad26a210f45e42154d53585b9bd125680c1a2a8 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 21 Apr 2026 11:26:52 +0100 Subject: [PATCH 09/11] refine error handling --- packages/cli/src/collections/request.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/collections/request.ts b/packages/cli/src/collections/request.ts index 82be2ff12..2bd0c6816 100644 --- a/packages/cli/src/collections/request.ts +++ b/packages/cli/src/collections/request.ts @@ -132,15 +132,18 @@ async function handleError(logger: Logger, response: Dispatcher.ResponseData) { logger.error('Error from server', response.statusCode); let message; let fix; + let logBody = true; switch (response.statusCode) { case 409: message = `409: multiple collection names matched`; fix = `Pass --project-id to disambiguate the request`; + logBody = false; break; case 404: message = `404: collection not found`; fix = `Ensure the Collection has been created on the admin page`; + logBody = false; break; default: message = `Error from server: ${response.statusCode}`; @@ -148,16 +151,18 @@ async function handleError(logger: Logger, response: Dispatcher.ResponseData) { let contentType = (response.headers?.['content-type'] as string) ?? ''; - if (contentType.startsWith('application/json')) { - try { - const body = await response.body.json(); - logger.error(body); - } catch (e) {} - } else { - try { - const text = await response.body.text(); - logger.error(text); - } catch (e) {} + if (logBody) { + if (contentType.startsWith('application/json')) { + try { + const body = await response.body.json(); + logger.error(body); + } catch (e) {} + } else { + try { + const text = await response.body.text(); + logger.error(text); + } catch (e) {} + } } throwAbortableError(message, fix); From dbc5b01e7104f717e07742b655da51ede2dedbb8 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 21 Apr 2026 11:29:41 +0100 Subject: [PATCH 10/11] tweak message --- packages/cli/src/collections/request.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/collections/request.ts b/packages/cli/src/collections/request.ts index 2bd0c6816..ecda5472a 100644 --- a/packages/cli/src/collections/request.ts +++ b/packages/cli/src/collections/request.ts @@ -137,7 +137,7 @@ async function handleError(logger: Logger, response: Dispatcher.ResponseData) { switch (response.statusCode) { case 409: message = `409: multiple collection names matched`; - fix = `Pass --project-id to disambiguate the request`; + fix = `Pass --project-id or set OPENFN_PROJECT_ID to disambiguate the request`; logBody = false; break; case 404: From 711855888ae5eedff44f33e8a995b0a673c51117 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 21 Apr 2026 13:34:47 +0100 Subject: [PATCH 11/11] versions --- packages/cli/CHANGELOG.md | 12 ++++++++++++ packages/cli/package.json | 2 +- packages/lexicon/CHANGELOG.md | 6 ++++++ packages/lexicon/package.json | 2 +- packages/ws-worker/CHANGELOG.md | 11 +++++++++++ packages/ws-worker/package.json | 2 +- 6 files changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 764f6fcba..9bcba0386 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,11 +1,23 @@ # @openfn/cli +## 1.35.0 + +### Minor Changes + +- collections: add support for --project-id + +### Patch Changes + +- Updated dependencies + - @openfn/lexicon@1.5.0 + ## 1.34.2 ### Patch Changes - 3918358: Override config.endpoint with one from openfn.yaml + ## 1.34.1 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index 199fa1b33..9ad265111 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@openfn/cli", - "version": "1.34.2", + "version": "1.35.0", "description": "CLI devtools for the OpenFn toolchain", "engines": { "node": ">=18", diff --git a/packages/lexicon/CHANGELOG.md b/packages/lexicon/CHANGELOG.md index 9cbbbe796..043e8b469 100644 --- a/packages/lexicon/CHANGELOG.md +++ b/packages/lexicon/CHANGELOG.md @@ -1,5 +1,11 @@ # lexicon +## 1.5.0 + +### Minor Changes + +- Accept project id on workflow (for use with collections) + ## 1.4.2 ### Patch Changes diff --git a/packages/lexicon/package.json b/packages/lexicon/package.json index 24c5c711f..80df4b8b0 100644 --- a/packages/lexicon/package.json +++ b/packages/lexicon/package.json @@ -1,6 +1,6 @@ { "name": "@openfn/lexicon", - "version": "1.4.2", + "version": "1.5.0", "description": "Central repo of names and type definitions", "author": "Open Function Group ", "license": "ISC", diff --git a/packages/ws-worker/CHANGELOG.md b/packages/ws-worker/CHANGELOG.md index c7cb548b0..8fef29b2e 100644 --- a/packages/ws-worker/CHANGELOG.md +++ b/packages/ws-worker/CHANGELOG.md @@ -1,5 +1,16 @@ # ws-worker +## 1.24.0 + +### Minor Changes + +- Accept project id on workflow (for use with collections) + +### Patch Changes + +- Updated dependencies + - @openfn/lexicon@1.5.0 + ## 1.23.8 ### Patch Changes diff --git a/packages/ws-worker/package.json b/packages/ws-worker/package.json index a18d16007..a70221a16 100644 --- a/packages/ws-worker/package.json +++ b/packages/ws-worker/package.json @@ -1,6 +1,6 @@ { "name": "@openfn/ws-worker", - "version": "1.23.8", + "version": "1.24.0", "description": "A Websocket Worker to connect Lightning to a Runtime Engine", "main": "dist/index.js", "type": "module",