From 479212208632c9ad57a2ceabe1bd8d63ad60b2f2 Mon Sep 17 00:00:00 2001 From: Tyler Hall Date: Thu, 31 Oct 2024 19:57:40 +0000 Subject: [PATCH] fix(connect): properly add protocol tags on message and spawn #1059 --- connect/package-lock.json | 12 +++++++ connect/package.json | 1 + connect/src/lib/message/upload-message.js | 31 +++++++++------- .../src/lib/message/upload-message.test.js | 6 ++-- connect/src/lib/spawn/upload-process.js | 35 +++++++++++-------- connect/src/lib/spawn/upload-process.test.js | 16 ++++----- connect/src/lib/utils.js | 25 ++----------- connect/src/lib/utils.test.js | 35 +------------------ 8 files changed, 67 insertions(+), 94 deletions(-) diff --git a/connect/package-lock.json b/connect/package-lock.json index 620172953..89f3b5356 100644 --- a/connect/package-lock.json +++ b/connect/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.59", "dependencies": { "@permaweb/ao-scheduler-utils": "~0.0.23", + "@permaweb/protocol-tag-utils": "~0.0.1", "buffer": "^6.0.3", "debug": "^4.3.6", "hyper-async": "^1.1.2", @@ -455,6 +456,12 @@ "node": ">=18" } }, + "node_modules/@permaweb/protocol-tag-utils": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@permaweb/protocol-tag-utils/-/protocol-tag-utils-0.0.1.tgz", + "integrity": "sha512-31dmD/bBuAwu9JmxlgEJNYTpdchiaX+WGmEiPLoWrGq/BhnpEKS+STIackqckAxXNoEL0ksCMMnfUBg9ZAGMAw==", + "license": "MIT" + }, "node_modules/arconnect": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/arconnect/-/arconnect-0.4.2.tgz", @@ -924,6 +931,11 @@ "zod": "^3.23.5" } }, + "@permaweb/protocol-tag-utils": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@permaweb/protocol-tag-utils/-/protocol-tag-utils-0.0.1.tgz", + "integrity": "sha512-31dmD/bBuAwu9JmxlgEJNYTpdchiaX+WGmEiPLoWrGq/BhnpEKS+STIackqckAxXNoEL0ksCMMnfUBg9ZAGMAw==" + }, "arconnect": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/arconnect/-/arconnect-0.4.2.tgz", diff --git a/connect/package.json b/connect/package.json index 7c499e6b4..0495ba7b6 100644 --- a/connect/package.json +++ b/connect/package.json @@ -46,6 +46,7 @@ }, "dependencies": { "@permaweb/ao-scheduler-utils": "~0.0.23", + "@permaweb/protocol-tag-utils": "~0.0.1", "buffer": "^6.0.3", "debug": "^4.3.6", "hyper-async": "^1.1.2", diff --git a/connect/src/lib/message/upload-message.js b/connect/src/lib/message/upload-message.js index 16cbc1117..be22d7818 100644 --- a/connect/src/lib/message/upload-message.js +++ b/connect/src/lib/message/upload-message.js @@ -1,9 +1,14 @@ import { Resolved, fromPromise, of } from 'hyper-async' import { z } from 'zod' -import { __, always, append, assoc, concat, defaultTo, ifElse, pipe, prop } from 'ramda' +import { __, always, assoc, curry, defaultTo, ifElse, pipe, prop } from 'ramda' +import { proto } from '@permaweb/protocol-tag-utils' import { deployMessageSchema, signerSchema } from '../../dal.js' -import { removeTagsByNameMaybeValue } from '../utils.js' + +const aoProto = proto('ao') +const removeAoProtoByName = curry(aoProto.removeAllByName) +const concatAoProto = curry(aoProto.concat) +const concatUnassoc = curry(aoProto.concatUnassoc) const tagSchema = z.array(z.object({ name: z.string(), @@ -36,15 +41,11 @@ function buildTagsWith () { return (ctx) => { return of(ctx.tags) .map(defaultTo([])) - .map(removeTagsByNameMaybeValue('Data-Protocol', 'ao')) - .map(removeTagsByNameMaybeValue('Variant')) - .map(removeTagsByNameMaybeValue('Type')) - .map(removeTagsByNameMaybeValue('SDK')) - .map(concat(__, [ - { name: 'Data-Protocol', value: 'ao' }, + .map(removeAoProtoByName('Variant')) + .map(removeAoProtoByName('Type')) + .map(concatAoProto([ { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Message' }, - { name: 'SDK', value: 'aoconnect' } + { name: 'Type', value: 'Message' } ])) .map(tagSchema.parse) .map(assoc('tags', __, ctx)) @@ -79,13 +80,19 @@ function buildDataWith ({ logger }) { .map( (ctx) => pipe( prop('tags'), - removeTagsByNameMaybeValue('Content-Type'), - append({ name: 'Content-Type', value: 'text/plain' }), + concatUnassoc([{ name: 'Content-Type', value: 'text/plain' }]), assoc('tags', __, ctx) )(ctx) ) .map(logger.tap('added pseudo-random string as message "data"')) )) + .map( + (ctx) => pipe( + prop('tags'), + concatUnassoc([{ name: 'SDK', value: 'aoconnect' }]), + assoc('tags', __, ctx) + )(ctx) + ) } } diff --git a/connect/src/lib/message/upload-message.test.js b/connect/src/lib/message/upload-message.test.js index c50bc7a87..b1fd04866 100644 --- a/connect/src/lib/message/upload-message.test.js +++ b/connect/src/lib/message/upload-message.test.js @@ -14,11 +14,11 @@ describe('upload-message', () => { assert.equal(processId, 'process-asdf') assert.deepStrictEqual(tags, [ { name: 'foo', value: 'bar' }, + { name: 'Content-Type', value: 'text/plain' }, + { name: 'SDK', value: 'aoconnect' }, { name: 'Data-Protocol', value: 'ao' }, { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Message' }, - { name: 'SDK', value: 'aoconnect' }, - { name: 'Content-Type', value: 'text/plain' } + { name: 'Type', value: 'Message' } ]) assert.equal(anchor, 'idempotent-123') assert.ok(signer) diff --git a/connect/src/lib/spawn/upload-process.js b/connect/src/lib/spawn/upload-process.js index 090b6656a..3bd396348 100644 --- a/connect/src/lib/spawn/upload-process.js +++ b/connect/src/lib/spawn/upload-process.js @@ -1,9 +1,14 @@ import { fromPromise, of, Resolved } from 'hyper-async' import { z } from 'zod' -import { __, always, append, assoc, concat, defaultTo, ifElse, pipe, prop } from 'ramda' +import { __, always, assoc, curry, defaultTo, ifElse, pipe, prop } from 'ramda' +import { proto } from '@permaweb/protocol-tag-utils' import { deployProcessSchema, signerSchema } from '../../dal.js' -import { removeTagsByNameMaybeValue } from '../utils.js' + +const aoProto = proto('ao') +const removeAoProtoByName = curry(aoProto.removeAllByName) +const concatAoProto = curry(aoProto.concat) +const concatUnassoc = curry(aoProto.concatUnassoc) const tagSchema = z.array(z.object({ name: z.string(), @@ -30,19 +35,15 @@ function buildTagsWith () { return of(ctx) .map(prop('tags')) .map(defaultTo([])) - .map(removeTagsByNameMaybeValue('Data-Protocol', 'ao')) - .map(removeTagsByNameMaybeValue('Variant')) - .map(removeTagsByNameMaybeValue('Type')) - .map(removeTagsByNameMaybeValue('Module')) - .map(removeTagsByNameMaybeValue('Scheduler')) - .map(removeTagsByNameMaybeValue('SDK')) - .map(concat(__, [ - { name: 'Data-Protocol', value: 'ao' }, + .map(removeAoProtoByName('Variant')) + .map(removeAoProtoByName('Type')) + .map(removeAoProtoByName('Module')) + .map(removeAoProtoByName('Scheduler')) + .map(concatAoProto([ { name: 'Variant', value: 'ao.TN.1' }, { name: 'Type', value: 'Process' }, { name: 'Module', value: ctx.module }, - { name: 'Scheduler', value: ctx.scheduler }, - { name: 'SDK', value: 'aoconnect' } + { name: 'Scheduler', value: ctx.scheduler } ])) .map(tagSchema.parse) .map(assoc('tags', __, ctx)) @@ -70,13 +71,19 @@ function buildDataWith ({ logger }) { .map( (ctx) => pipe( prop('tags'), - removeTagsByNameMaybeValue('Content-Type'), - append({ name: 'Content-Type', value: 'text/plain' }), + concatUnassoc([{ name: 'Content-Type', value: 'text/plain' }]), assoc('tags', __, ctx) )(ctx) ) .map(logger.tap('added pseudo-random string as process "data"')) )) + .map( + (ctx) => pipe( + prop('tags'), + concatUnassoc([{ name: 'SDK', value: 'aoconnect' }]), + assoc('tags', __, ctx) + )(ctx) + ) } } diff --git a/connect/src/lib/spawn/upload-process.test.js b/connect/src/lib/spawn/upload-process.test.js index 04aad7d11..5c86283ee 100644 --- a/connect/src/lib/spawn/upload-process.test.js +++ b/connect/src/lib/spawn/upload-process.test.js @@ -13,13 +13,13 @@ describe('upload-process', () => { assert.ok(data) assert.deepStrictEqual(tags, [ { name: 'foo', value: 'bar' }, + { name: 'Content-Type', value: 'text/plain' }, + { name: 'SDK', value: 'aoconnect' }, { name: 'Data-Protocol', value: 'ao' }, { name: 'Variant', value: 'ao.TN.1' }, { name: 'Type', value: 'Process' }, { name: 'Module', value: 'module-id-123' }, - { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' }, - { name: 'SDK', value: 'aoconnect' }, - { name: 'Content-Type', value: 'text/plain' } + { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' } ]) assert.ok(signer) @@ -53,13 +53,13 @@ describe('upload-process', () => { const uploadProcess = uploadProcessWith({ deployProcess: async ({ tags }) => { assert.deepStrictEqual(tags, [ + { name: 'Content-Type', value: 'text/plain' }, + { name: 'SDK', value: 'aoconnect' }, { name: 'Data-Protocol', value: 'ao' }, { name: 'Variant', value: 'ao.TN.1' }, { name: 'Type', value: 'Process' }, { name: 'Module', value: 'module-id-123' }, - { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' }, - { name: 'SDK', value: 'aoconnect' }, - { name: 'Content-Type', value: 'text/plain' } + { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' } ]) return { res: 'foobar', processId: 'process-id-123' } @@ -84,12 +84,12 @@ describe('upload-process', () => { */ assert.deepStrictEqual(tags, [ { name: 'foo', value: 'bar' }, + { name: 'SDK', value: 'aoconnect' }, { name: 'Data-Protocol', value: 'ao' }, { name: 'Variant', value: 'ao.TN.1' }, { name: 'Type', value: 'Process' }, { name: 'Module', value: 'module-id-123' }, - { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' }, - { name: 'SDK', value: 'aoconnect' } + { name: 'Scheduler', value: 'zVkjFCALjk4xxuCilddKS8ShZ-9HdeqeuYQOgMgWucro' } ]) return { res: 'foobar', diff --git a/connect/src/lib/utils.js b/connect/src/lib/utils.js index 0007aca29..5d13faf9f 100644 --- a/connect/src/lib/utils.js +++ b/connect/src/lib/utils.js @@ -1,6 +1,6 @@ import { - F, T, __, allPass, always, append, assoc, chain, concat, cond, defaultTo, - equals, has, ifElse, includes, is, join, map, pipe, propEq, propOr, reduce, reject + F, T, __, append, assoc, chain, concat, cond, defaultTo, + equals, has, includes, is, join, map, pipe, propOr, reduce } from 'ramda' import { ZodError, ZodIssueCode } from 'zod' @@ -46,27 +46,6 @@ export function parseTags (rawTags) { )(rawTags) } -/** - * Remove tags from the array by name. If value is provided, - * then only remove tags whose both name and value matches. - * - * @param {string} name - the name of the tags to be removed - * @param {string} [value] - the value of the tags to be removed - */ -export function removeTagsByNameMaybeValue (name, value) { - return (tags) => reject( - allPass([ - propEq(name, 'name'), - ifElse( - always(value), - propEq(value, 'value'), - T - ) - ]), - tags - ) -} - export function eqOrIncludes (val) { return cond([ [is(String), equals(val)], diff --git a/connect/src/lib/utils.test.js b/connect/src/lib/utils.test.js index ac382f67f..16d9fdef2 100644 --- a/connect/src/lib/utils.test.js +++ b/connect/src/lib/utils.test.js @@ -3,7 +3,7 @@ import * as assert from 'node:assert' import { z } from 'zod' -import { errFrom, joinUrl, removeTagsByNameMaybeValue } from './utils.js' +import { errFrom, joinUrl } from './utils.js' describe('utils', () => { describe('joinUrl', () => { @@ -71,37 +71,4 @@ describe('utils', () => { assert.equal(err.message, 'An error occurred') }) }) - - describe('removeTagsByNameMaybeValue', () => { - const tags = [ - { name: 'Data-Protocol', value: 'ao' }, - { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Message' }, - { name: 'Type', value: 'Foo' }, - { name: 'SDK', value: 'aoconnect' } - ] - - test('should remove the tags by name', () => { - assert.deepStrictEqual( - removeTagsByNameMaybeValue('Type')(tags), - [ - { name: 'Data-Protocol', value: 'ao' }, - { name: 'Variant', value: 'ao.TN.1' }, - { name: 'SDK', value: 'aoconnect' } - ] - ) - }) - - test('should remove the tags by name and value', () => { - assert.deepStrictEqual( - removeTagsByNameMaybeValue('Type', 'Foo')(tags), - [ - { name: 'Data-Protocol', value: 'ao' }, - { name: 'Variant', value: 'ao.TN.1' }, - { name: 'Type', value: 'Message' }, - { name: 'SDK', value: 'aoconnect' } - ] - ) - }) - }) })