Skip to content

Commit 338ca6a

Browse files
authored
Merge pull request #1308 from permaweb/feat/return-assignment+id
feat: add optional message id flag to support return type { slot, id }
2 parents ac2c718 + 8ea61de commit 338ca6a

8 files changed

Lines changed: 173 additions & 10 deletions

File tree

connect/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ const messageId = await message({
123123

124124
> Optional: Pass `returnAssignmentSlot: true` to `message` to get the scheduled slot of this message
125125
126+
> Optional: Pass `returnMessageId: true` with `returnAssignmentSlot: true` to return both values as `{ slot, id }`
127+
126128
> You can pass a 32 byte `anchor` to `message` which will be set on the DataItem
127129
128130
#### `signMessage`

connect/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@permaweb/aoconnect",
3-
"version": "0.0.94",
3+
"version": "0.0.95",
44
"repository": {
55
"type": "git",
66
"url": "https://github.com/permaweb/ao.git",

connect/src/client/ao-core.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ const getTags = (args) =>
4444

4545
const getData = (args) => args.data ?? '1984'
4646

47+
const getMessageId = (response, parsedResponse) =>
48+
parsedResponse.id ??
49+
parsedResponse.messageId ??
50+
parsedResponse.message?.id ??
51+
response.headers?.get?.('id') ??
52+
response.headers?.get?.('message')
53+
54+
const getMessageResponse = ({ response, parsedResponse, returnAssignmentSlot, returnMessageId }) => {
55+
const slot = parsedResponse.slot
56+
57+
if (returnMessageId) {
58+
const id = getMessageId(response, parsedResponse)
59+
if (!id) throw new Error('Message id not found in response')
60+
if (returnAssignmentSlot) return { slot, id }
61+
return id
62+
}
63+
64+
return slot
65+
}
66+
4767
export function requestWith(deps) {
4868
return async (args) => {
4969
try {
@@ -126,7 +146,14 @@ export function messageWith(deps) {
126146
const parsedResponse = await response.json()
127147

128148
if (args.opts?.fullResponse) return normalizeOutput(parsedResponse)
129-
else return parsedResponse.slot
149+
else {
150+
return getMessageResponse({
151+
response,
152+
parsedResponse,
153+
returnAssignmentSlot: args.returnAssignmentSlot,
154+
returnMessageId: args.returnMessageId
155+
})
156+
}
130157
}
131158
else throw new Error('Error sending message')
132159
} catch (e) {
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { describe, test } from 'node:test'
2+
import * as assert from 'node:assert'
3+
4+
import { messageWith } from './ao-core.js'
5+
6+
function responseWith (body, headers = {}) {
7+
return {
8+
ok: true,
9+
headers: {
10+
get: (name) => headers[name] ?? headers[name.toLowerCase()] ?? null
11+
},
12+
json: async () => body
13+
}
14+
}
15+
16+
function createMessage (body, headers) {
17+
return messageWith({
18+
aoCore: {
19+
request: async () => responseWith(body, headers)
20+
}
21+
})
22+
}
23+
24+
describe('ao-core message', () => {
25+
test('returns the assignment slot by default', async () => {
26+
const message = createMessage({ slot: 42, id: 'message-123' })
27+
28+
const res = await message({ process: 'process-asdf' })
29+
30+
assert.equal(res, 42)
31+
})
32+
33+
test('returns the message id when returnMessageId is true', async () => {
34+
const message = createMessage({ slot: 42, id: 'message-123' })
35+
36+
const res = await message({
37+
process: 'process-asdf',
38+
returnMessageId: true
39+
})
40+
41+
assert.equal(res, 'message-123')
42+
})
43+
44+
test('returns slot and id when returnAssignmentSlot and returnMessageId are true', async () => {
45+
const message = createMessage({ slot: 42, id: 'message-123' })
46+
47+
const res = await message({
48+
process: 'process-asdf',
49+
returnAssignmentSlot: true,
50+
returnMessageId: true
51+
})
52+
53+
assert.deepStrictEqual(res, {
54+
slot: 42,
55+
id: 'message-123'
56+
})
57+
})
58+
})

connect/src/dal.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export const deployMessageSchema = z.function()
5454
tags: z.array(tagSchema),
5555
anchor: z.string().optional(),
5656
signer: z.any().nullish(),
57-
returnAssignmentSlot: z.boolean().optional()
57+
returnAssignmentSlot: z.boolean().optional(),
58+
returnMessageId: z.boolean().optional()
5859
}))
5960
.returns(z.promise(
6061
z.object({

connect/src/lib/message/index.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,33 @@ import { prepareMessageWith, sendSignedMessageWith, uploadMessageWith } from './
1515
* @property {{ name: string, value: string }[]} [tags]
1616
* @property {string} [anchor]
1717
* @property {Types['signer']} [signer]
18+
* @property {boolean} [returnAssignmentSlot]
19+
* @property {boolean} [returnMessageId]
1820
*
1921
* @callback SendMessage
2022
* @param {SendMessageArgs} args
21-
* @returns {Promise<string>} the id of the data item that represents this message
23+
* @returns {Promise<string | { slot: string, id: string }>} the id of the data item that represents this message, the assignment slot, or both
2224
*
2325
* @param {Env1} - the environment
2426
* @returns {SendMessage}
2527
*/
2628
export function messageWith (env) {
2729
const uploadMessage = uploadMessageWith(env)
2830

29-
return ({ process, data, tags, anchor, signer, returnAssignmentSlot }) => {
30-
return of({ id: process, data, tags, anchor, signer, returnAssignmentSlot })
31+
return ({ process, data, tags, anchor, signer, returnAssignmentSlot, returnMessageId }) => {
32+
return of({ id: process, data, tags, anchor, signer, returnAssignmentSlot, returnMessageId })
3133
.chain(uploadMessage)
32-
.map((ctx) => returnAssignmentSlot ? ctx.assignmentSlot.toString() : ctx.messageId)
34+
.map((ctx) => {
35+
const id = ctx.messageId
36+
37+
if (returnAssignmentSlot) {
38+
const slot = ctx.assignmentSlot.toString()
39+
if (returnMessageId) return { slot, id }
40+
return slot
41+
}
42+
43+
return id
44+
})
3345
.bimap(errFrom, identity)
3446
.toPromise()
3547
}
@@ -57,4 +69,4 @@ export function signedMessageWith (env) {
5769
.bimap(errFrom, identity)
5870
.toPromise()
5971
}
60-
}
72+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { describe, test } from 'node:test'
2+
import * as assert from 'node:assert'
3+
4+
import { createLogger } from '../../logger.js'
5+
import { messageWith } from './index.js'
6+
7+
const logger = createLogger('message')
8+
9+
function createMessage (deployMessage) {
10+
return messageWith({ deployMessage, logger })
11+
}
12+
13+
describe('message', () => {
14+
test('returns the message id by default', async () => {
15+
const message = createMessage(async ({ returnMessageId }) => {
16+
assert.equal(returnMessageId, undefined)
17+
return { messageId: 'data-item-123', assignmentSlot: '42' }
18+
})
19+
20+
const res = await message({
21+
process: 'process-asdf',
22+
signer: () => {}
23+
})
24+
25+
assert.equal(res, 'data-item-123')
26+
})
27+
28+
test('returns the assignment slot when returnAssignmentSlot is true', async () => {
29+
const message = createMessage(async ({ returnAssignmentSlot }) => {
30+
assert.equal(returnAssignmentSlot, true)
31+
return { messageId: 'data-item-123', assignmentSlot: '42' }
32+
})
33+
34+
const res = await message({
35+
process: 'process-asdf',
36+
signer: () => {},
37+
returnAssignmentSlot: true
38+
})
39+
40+
assert.equal(res, '42')
41+
})
42+
43+
test('returns slot and id when returnAssignmentSlot and returnMessageId are true', async () => {
44+
const message = createMessage(async ({ returnAssignmentSlot, returnMessageId }) => {
45+
assert.equal(returnAssignmentSlot, true)
46+
assert.equal(returnMessageId, true)
47+
return { messageId: 'data-item-123', assignmentSlot: '42' }
48+
})
49+
50+
const res = await message({
51+
process: 'process-asdf',
52+
signer: () => {},
53+
returnAssignmentSlot: true,
54+
returnMessageId: true
55+
})
56+
57+
assert.deepStrictEqual(res, {
58+
slot: '42',
59+
id: 'data-item-123'
60+
})
61+
})
62+
})

connect/src/lib/message/upload-message.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,15 @@ export function uploadMessageWith (env) {
115115
return of(ctx)
116116
.chain(buildTags)
117117
.chain(buildData)
118-
.chain(fromPromise(({ id, data, tags, anchor, signer, returnAssignmentSlot }) => {
118+
.chain(fromPromise(({ id, data, tags, anchor, signer, returnAssignmentSlot, returnMessageId }) => {
119119
return deployMessage({
120120
processId: id,
121121
data,
122122
tags,
123123
anchor,
124124
signer: signerSchema.implement(signer || env.signer),
125-
returnAssignmentSlot
125+
returnAssignmentSlot,
126+
returnMessageId
126127
})
127128
}))
128129
.map(res => ({

0 commit comments

Comments
 (0)