Skip to content

Commit 77f758c

Browse files
authored
Merge pull request #211 from ardriveapp/dev
Release CORE v1.17.0
2 parents 16f59ea + 475cb52 commit 77f758c

File tree

5 files changed

+114
-20
lines changed

5 files changed

+114
-20
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ardrive-core-js",
3-
"version": "1.16.0",
3+
"version": "1.17.0",
44
"description": "ArDrive Core contains the essential back end application features to support the ArDrive CLI and Desktop apps, such as file management, Permaweb upload/download, wallet management and other common functions.",
55
"main": "./lib/exports.js",
66
"types": "./lib/exports.d.ts",

src/arfs/arfs_meta_data_factory.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ export function getPrepFileParams({
7474
wrappedFile,
7575
dataPrototypeFactoryFn: async (fileData, fileId) =>
7676
new ArFSPrivateFileDataPrototype(
77-
await ArFSPrivateFileDataTransactionData.from(fileData, fileId, driveKey)
77+
await ArFSPrivateFileDataTransactionData.from(fileData, fileId, driveKey),
78+
wrappedFile.customMetaData?.dataGqlTags
7879
),
7980
metadataTxDataFactoryFn: async (fileId, dataTxId) => {
8081
return ArFSPrivateFileMetaDataPrototype.fromFile({
@@ -96,7 +97,8 @@ export function getPrepFileParams({
9697
Promise.resolve(
9798
new ArFSPublicFileDataPrototype(
9899
new ArFSPublicFileDataTransactionData(fileData),
99-
wrappedFile.contentType
100+
wrappedFile.contentType,
101+
wrappedFile.customMetaData?.dataGqlTags
100102
)
101103
),
102104
metadataTxDataFactoryFn: (fileId, dataTxId) =>

src/types/custom_metadata_types.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,16 @@ const invalidSchemaErrorMessage = `Invalid custom metadata schema. Please submit
77
const customMetaDataGqlTagShapeOne = '{ "TAG_NAME": "TAG_VALUE" }';
88
const customMetaDataGqlTagShapeTwo = '{ "TAG_NAME": ["VAL 1", "VAL 2" ] }';
99
const customMetaDataJsonShape = '{ "TAG_NAME": { "Any": [ "Valid", "JSON" ] } }';
10-
const customMetaDataShape = `{ metaDataJson?: ${customMetaDataGqlTagShapeOne}, metaDataGql?: ${customMetaDataGqlTagShapeTwo} }`;
10+
const customMetaDataShape = `{ metaDataJson?: ${customMetaDataGqlTagShapeOne}, metaDataGql?: ${customMetaDataGqlTagShapeTwo}, dataGqlTags?: ${customMetaDataGqlTagShapeTwo} }`;
1111

1212
export const invalidCustomMetaDataGqlTagErrorMessage = `${invalidSchemaErrorMessage}${customMetaDataGqlTagShapeOne} or ${customMetaDataGqlTagShapeTwo}`;
13+
export const invalidCustomDataGqlTagErrorMessage = `${invalidSchemaErrorMessage}${customMetaDataGqlTagShapeOne} or ${customMetaDataGqlTagShapeTwo}`;
1314
export const invalidCustomMetaDataJsonErrorMessage = `${invalidSchemaErrorMessage}${customMetaDataJsonShape}`;
1415
export const invalidCustomMetaDataErrorMessage = `${invalidSchemaErrorMessage}${customMetaDataShape}`;
1516

1617
export type CustomMetaDataGqlTags = Record<string, string | string[]>;
1718
export type CustomMetaDataJsonFields = EntityMetaDataTransactionData;
19+
export type CustomMetaDataTagInterface = CustomMetaDataGqlTags;
1820

1921
export interface CustomMetaData {
2022
/** Include custom metadata on MetaData Tx Data JSON */
@@ -23,9 +25,8 @@ export interface CustomMetaData {
2325
/** Include custom metadata on MetaData Tx GQL Tags */
2426
metaDataGqlTags?: CustomMetaDataGqlTags;
2527

26-
// TODO: Include dataTx GQL tags as an option (PE-1534)
2728
/** Include custom metadata on File Data Tx GQL Tags */
28-
// dataGqlTags?: CustomMetaDataTagInterface;
29+
dataGqlTags?: CustomMetaDataTagInterface;
2930
}
3031

3132
export function isCustomMetaDataJsonFields(customDataJson: unknown): customDataJson is CustomMetaDataJsonFields {
@@ -93,11 +94,20 @@ export function isCustomMetaData(tags: unknown): tags is CustomMetaData {
9394
}
9495

9596
for (const [key, metaData] of Object.entries(tags)) {
96-
if (key === 'metaDataJson' && !isCustomMetaDataJsonFields(metaData)) {
97-
return false;
98-
}
99-
if (key === 'metaDataGqlTags' && !isCustomMetaDataGqlTags(metaData)) {
100-
return false;
97+
switch (key) {
98+
case 'metaDataJson':
99+
if (!isCustomMetaDataJsonFields(metaData)) {
100+
return false;
101+
}
102+
break;
103+
case 'metaDataGqlTags':
104+
case 'dataGqlTags':
105+
if (!isCustomMetaDataGqlTags(metaData)) {
106+
return false;
107+
}
108+
break;
109+
default:
110+
break;
101111
}
102112
}
103113
return true;
@@ -119,6 +129,7 @@ export function assertCustomMetaDataJsonFields(tags: unknown): tags is CustomMet
119129

120130
export function assertCustomMetaData(tags: unknown): tags is CustomMetaData {
121131
if (!isCustomMetaData(tags)) {
132+
// TODO: throw the error for data ones as well.
122133
throw Error(invalidCustomMetaDataErrorMessage);
123134
}
124135
return true;

tests/helpers/arlocal_test_assertions.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,14 @@ import {
2626
EntityMetaDataTransactionData,
2727
GQLTagInterface,
2828
CustomMetaData,
29-
CustomMetaDataJsonFields
29+
CustomMetaDataJsonFields,
30+
PRIVATE_CONTENT_TYPE
3031
} from '../../src/types';
3132
import { getDecodedTags } from '../test_helpers';
3233

34+
const defaultPublicDataContentType = 'text/plain';
35+
const defaultPrivateDataContentType = PRIVATE_CONTENT_TYPE;
36+
3337
interface AssertEntityExpectationsParams<T = ArFSEntity> {
3438
entity: T;
3539
driveId: DriveID;
@@ -350,16 +354,34 @@ export function assertFolderMetaDataGqlTags(
350354
export function assertFileDataTxGqlTags(
351355
dataTx: Transaction,
352356
expectations: {
353-
contentType: DataContentType;
357+
contentType?: DataContentType;
358+
customMetaData?: CustomMetaDataGqlTags;
354359
}
355360
): void {
356-
const { contentType } = expectations;
361+
const { contentType, customMetaData } = expectations;
357362
const dataTxTags = getDecodedTags(dataTx.tags);
358363

359-
expect(dataTxTags).to.deep.equal([
360-
{ name: 'Content-Type', value: contentType },
361-
{ name: 'App-Name', value: 'ArLocal Integration Test' },
362-
{ name: 'App-Version', value: 'FAKE_VERSION' },
363-
{ name: 'Tip-Type', value: 'data upload' }
364-
]);
364+
const expectedCustomTags: GQLTagInterface[] = mapMetaDataTagInterfaceToGqlTagInterface(customMetaData);
365+
366+
const cipherIv = dataTxTags.find((tag) => tag.name === 'Cipher-IV')?.value;
367+
const isPublic = !cipherIv;
368+
if (isPublic) {
369+
expect(dataTxTags).to.deep.equal([
370+
...expectedCustomTags,
371+
{ name: 'Content-Type', value: contentType ?? defaultPublicDataContentType },
372+
{ name: 'App-Name', value: 'ArLocal Integration Test' },
373+
{ name: 'App-Version', value: 'FAKE_VERSION' },
374+
{ name: 'Tip-Type', value: 'data upload' }
375+
]);
376+
} else {
377+
expect(dataTxTags).to.deep.equal([
378+
...expectedCustomTags,
379+
{ name: 'Content-Type', value: contentType ?? defaultPrivateDataContentType },
380+
{ name: 'Cipher', value: 'AES256-GCM' },
381+
{ name: 'Cipher-IV', value: cipherIv },
382+
{ name: 'App-Name', value: 'ArLocal Integration Test' },
383+
{ name: 'App-Version', value: 'FAKE_VERSION' },
384+
{ name: 'Tip-Type', value: 'data upload' }
385+
]);
386+
}
365387
}

tests/integration/arlocal.int.test.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,35 @@ describe('ArLocal Integration Tests', function () {
486486
});
487487
});
488488

489+
it('we can upload a public file as a v2 transaction with custom data gql tags', async () => {
490+
const customMetaData: CustomMetaData = {
491+
dataGqlTags: {
492+
'My-Tag-1': 'My awesome value',
493+
'My-Tag-2': ['hello', 'world!']
494+
}
495+
};
496+
497+
const { created } = await v2ArDrive.uploadAllEntities({
498+
entitiesToUpload: [
499+
{
500+
destFolderId: rootFolderId,
501+
wrappedEntity: wrapFileOrFolder(
502+
'tests/stub_files/bulk_root_folder/file_in_root.txt',
503+
undefined,
504+
customMetaData
505+
)
506+
}
507+
]
508+
});
509+
await mineArLocalBlock(arweave);
510+
511+
// @ts-ignore
512+
const { dataTxId }: Required<ArFSEntityData> = created[0];
513+
514+
const dataTx = new Transaction(await fakeGatewayApi.getTransaction(dataTxId));
515+
assertFileDataTxGqlTags(dataTx, { customMetaData: customMetaData.dataGqlTags });
516+
});
517+
489518
it('we can upload a file as a v2 transaction with custom metadata to the Data JSON containing all valid JSON shapes', async () => {
490519
const fileName = 'json_shapes_unique_name';
491520
const customMetaDataJson: CustomMetaDataJsonFields = {
@@ -1220,6 +1249,36 @@ describe('ArLocal Integration Tests', function () {
12201249
});
12211250
});
12221251

1252+
it('we can upload a private file as a v2 transaction with custom data gql tags', async () => {
1253+
const customMetaData: CustomMetaData = {
1254+
dataGqlTags: {
1255+
'My-Tag-1': 'The best value ever for a tag',
1256+
'My-Tag-2': ['foo', 'var']
1257+
}
1258+
};
1259+
1260+
const { created } = await v2ArDrive.uploadAllEntities({
1261+
entitiesToUpload: [
1262+
{
1263+
destFolderId: rootFolderId,
1264+
wrappedEntity: wrapFileOrFolder(
1265+
'tests/stub_files/bulk_root_folder/parent_folder/file_in_parent.txt',
1266+
undefined,
1267+
customMetaData
1268+
),
1269+
driveKey
1270+
}
1271+
]
1272+
});
1273+
await mineArLocalBlock(arweave);
1274+
1275+
// @ts-ignore
1276+
const { dataTxId }: Required<ArFSEntityData> = created[0];
1277+
1278+
const dataTx = new Transaction(await fakeGatewayApi.getTransaction(dataTxId));
1279+
assertFileDataTxGqlTags(dataTx, { customMetaData: customMetaData.dataGqlTags });
1280+
});
1281+
12231282
it('we can upload a private folder as a v2 transaction with custom metadata', async () => {
12241283
const folderName = 'custom_content_unique_folder';
12251284

0 commit comments

Comments
 (0)