@undefineds.co/xpod 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,6 +10,8 @@ export declare class MinioDataAccessor implements DataAccessor {
10
10
  private readonly client;
11
11
  private readonly bucketName;
12
12
  constructor(resourceMapper: FileIdentifierMapper, accessKey: string, secretKey: string, endpoint: string, bucketName: string);
13
+ private objectName;
14
+ private containerObjectName;
13
15
  /**
14
16
  * Should throw a NotImplementedHttpError if the DataAccessor does not support storing the given Representation.
15
17
  *
@@ -33,6 +33,12 @@ class MinioDataAccessor {
33
33
  this.bucketName = bucketName;
34
34
  this.logger.info(`MinioDataAccessor initialized with endpoint: ${endPoint}:${port} (SSL: ${useSSL})`);
35
35
  }
36
+ objectName(url) {
37
+ return url.pathname.replace(/^\/+/u, '');
38
+ }
39
+ containerObjectName(url) {
40
+ return `${this.objectName(url).replace(/\/+$/u, '')}/.container`;
41
+ }
36
42
  /**
37
43
  * Should throw a NotImplementedHttpError if the DataAccessor does not support storing the given Representation.
38
44
  *
@@ -55,7 +61,7 @@ class MinioDataAccessor {
55
61
  async getData(identifier) {
56
62
  const started = Date.now();
57
63
  const url = new URL(identifier.path);
58
- const stream = await this.client.getObject(this.bucketName, url.pathname);
64
+ const stream = await this.client.getObject(this.bucketName, this.objectName(url));
59
65
  this.logDuration('getData', identifier.path, started);
60
66
  return (0, community_server_1.guardStream)(stream);
61
67
  }
@@ -66,7 +72,7 @@ class MinioDataAccessor {
66
72
  */
67
73
  async getPresignedUrl(identifier, expires = 3600) {
68
74
  const url = new URL(identifier.path);
69
- const objectKey = url.pathname.replace(/^\//, '');
75
+ const objectKey = this.objectName(url);
70
76
  return this.client.presignedGetObject(this.bucketName, objectKey, expires);
71
77
  }
72
78
  /**
@@ -81,7 +87,7 @@ class MinioDataAccessor {
81
87
  const url = new URL(identifier.path);
82
88
  const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);
83
89
  const isDirectory = identifier.path.endsWith('/');
84
- const objectName = isDirectory ? `${url.pathname}/.container` : url.pathname;
90
+ const objectName = isDirectory ? this.containerObjectName(url) : this.objectName(url);
85
91
  let stats;
86
92
  try {
87
93
  stats = await this.client.statObject(this.bucketName, objectName);
@@ -115,7 +121,7 @@ class MinioDataAccessor {
115
121
  */
116
122
  async *getChildren(identifier) {
117
123
  const url = new URL(identifier.path);
118
- const objects = this.client.listObjectsV2(this.bucketName, url.pathname);
124
+ const objects = this.client.listObjectsV2(this.bucketName, this.objectName(url));
119
125
  for await (const object of objects) {
120
126
  const metadata = await this.getMetadata(object);
121
127
  yield metadata;
@@ -135,7 +141,7 @@ class MinioDataAccessor {
135
141
  const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);
136
142
  const itemMetadata = this.encodeMetadata(link, metadata);
137
143
  try {
138
- await this.client.putObject(this.bucketName, url.pathname, data, metadata.contentLength, itemMetadata || undefined);
144
+ await this.client.putObject(this.bucketName, this.objectName(url), data, metadata.contentLength, itemMetadata || undefined);
139
145
  this.logDuration('writeDocument', identifier.path, started);
140
146
  }
141
147
  catch (error) {
@@ -155,7 +161,7 @@ class MinioDataAccessor {
155
161
  const started = Date.now();
156
162
  const url = new URL(identifier.path);
157
163
  const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);
158
- await this.client.putObject(this.bucketName, `${url.pathname}/.container`, Buffer.from(''), metadata.contentLength, this.encodeMetadata(link, metadata) || undefined);
164
+ await this.client.putObject(this.bucketName, this.containerObjectName(url), Buffer.from(''), metadata.contentLength, this.encodeMetadata(link, metadata) || undefined);
159
165
  this.logDuration('writeContainer', identifier.path, started);
160
166
  }
161
167
  /**
@@ -179,7 +185,7 @@ class MinioDataAccessor {
179
185
  */
180
186
  async deleteResource(identifier) {
181
187
  const link = new URL(identifier.path);
182
- await this.client.removeObject(this.bucketName, link.pathname);
188
+ await this.client.removeObject(this.bucketName, this.objectName(link));
183
189
  }
184
190
  /**
185
191
  * Reads and generates all metadata relevant for the given file,
@@ -1 +1 @@
1
- {"version":3,"file":"MinioDataAccessor.js","sourceRoot":"","sources":["../../../src/storage/accessors/MinioDataAccessor.ts"],"names":[],"mappings":";;;AAAA,iCAA+C;AAC/C,iEAAqD;AAIrD,8DAuBiC;AASjC,MAAa,iBAAiB;IAM5B,YACE,cAAoC,EACpC,SAAiB,EACjB,SAAiB,EACjB,QAAgB,EAChB,UAAkB;QAVD,WAAM,GAAG,IAAA,oCAAY,EAAC,IAAI,CAAC,CAAC;QAY7C,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;QAErC,6FAA6F;QAC7F,IAAI,QAAgB,CAAC;QACrB,IAAI,IAAwB,CAAC;QAC7B,IAAI,MAAM,GAAG,KAAK,CAAC;QAEnB,IAAI,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YACtE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC9B,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;YACxB,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACrD,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACvD,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,cAAM,CAAC;YACvB,SAAS;YACT,SAAS;YACT,QAAQ;YACR,IAAI;YACJ,MAAM;SACP,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gDAAgD,QAAQ,IAAI,IAAI,UAAU,MAAM,GAAG,CAAC,CAAA;IACvG,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,SAAS,CAAC,cAA8B;QACnD,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,gDAA6B,CAAC,gCAAgC,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,OAAO,CAAC,UAA8B;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1E,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,IAAA,8BAAW,EAAC,MAAM,CAAC,CAAC;IAC7B,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,eAAe,CAAC,UAA8B,EAAE,OAAO,GAAG,IAAI;QACzE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7E,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,WAAW,CAAC,UAA8B;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC3E,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC7E,IAAI,KAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,oCAAiB,EAAE,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,IAAA,wCAAqB,EAAC,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACvD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACzD,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1D,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,IAAI,IAAA,wCAAqB,EAAC,UAAU,CAAC,IAAI,WAAW,EAAE,CAAC;YACrD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,CAAC,WAAW,CAAC,aAAa,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAC1D,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,MAAM,IAAI,oCAAiB,EAAE,CAAC;IAChC,CAAC;IAED;;;;;;;;;;;OAWG;IACI,KAAK,CAAA,CAAE,WAAW,CAAC,UAA8B;QACtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzE,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;YAChD,MAAM,QAAQ,CAAC;QACjB,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,aAAa,CAAC,UAA8B,EAAE,IAAuB,EAAE,QAAgC;QAClH,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CACzB,IAAI,CAAC,UAAU,EACf,GAAG,CAAC,QAAQ,EACZ,IAAI,EACJ,QAAQ,CAAC,aAAa,EACtB,YAAY,IAAI,SAAS,CAC1B,CAAC;YACF,IAAI,CAAC,WAAW,CAAC,eAAe,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,2BAA2B,UAAU,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,CAAA;YACxE,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,cAAc,CAAC,UAA8B,EAAE,QAAgC;QAC1F,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACpC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QAC3E,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CACzB,IAAI,CAAC,UAAU,EACf,GAAG,GAAG,CAAC,QAAQ,aAAa,EAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EACf,QAAQ,CAAC,aAAa,EACtB,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,SAAS,CACjD,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,gBAAgB,EAAE,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,aAAa,CAAC,UAA8B,EAAE,QAAgC;QACzF,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC7E,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,cAAc,CAAC,UAA8B;QACxD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACrC,MAAM,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,eAAe,CAAC,IAAkB,EAAE,KAAqB;QACrE,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;QAC9D,kHAAkH;QAClH,8EAA8E;QAC9E,8DAA8D;QAChE,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YAChD,QAAQ,CAAC,GAAG,CAAC,oCAAiB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,oBAAoB,CAAC,IAAkB,EAAE,KAAqB;QAC1E,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,eAAe,CAAC,IAAkB,EAAE,KAAqB,EAAE,WAAoB;QAC3F,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3D,IAAA,sCAAmB,EAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC3C,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;QACpD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACK,gBAAgB,CAAC,QAAgC,EAAE,KAAqB,EAAE,WAAoB;QACpG,IAAA,qCAAkB,EAAC,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;QACjD,QAAQ,CAAC,GAAG,CACV,wBAAK,CAAC,KAAK,CAAC,KAAK,EACjB,IAAA,4BAAS,EAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,sBAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EAC7E,6BAAU,CAAC,KAAK,CAAC,gBAAgB,CAClC,CAAC;QACF,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,QAAQ,CAAC,GAAG,CACV,wBAAK,CAAC,KAAK,CAAC,IAAI,EAChB,IAAA,4BAAS,EAAC,KAAK,CAAC,IAAI,EAAE,sBAAG,CAAC,KAAK,CAAC,OAAO,CAAC,EACxC,6BAAU,CAAC,KAAK,CAAC,gBAAgB,CAClC,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACO,cAAc,CAAC,IAAkB,EAAE,QAAgC;QAC3E,8CAA8C;QAC9C,QAAQ,CAAC,MAAM,CAAC,sBAAG,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpD,QAAQ,CAAC,MAAM,CAAC,sBAAG,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACrD,QAAQ,CAAC,MAAM,CAAC,sBAAG,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAG,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC1D,QAAQ,CAAC,SAAS,CAAC,qBAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACtC,+GAA+G;QAC/G,gFAAgF;QAChF,yFAAyF;QACzF,IAAI,IAAA,kCAAe,EAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,OAAO,QAAQ,CAAC,WAAW,KAAK,WAAW,EAAE,CAAC;YAClF,QAAQ,CAAC,SAAS,CAAC,oCAAiB,CAAC,CAAC;QACxC,CAAC;QACD,MAAM,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAA;QACpD,IAAI,iBAAiB,KAAK,SAAS;eAC9B,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5D,OAAO,IAAI,CAAC;QACd,CAAC;QACD,sDAAsD;QACtD,OAAO,iBAAiB,CAAC,UAAU,CAAC;IACtC,CAAC;IAES,cAAc,CAAC,IAAkB,EAAE,QAAwB;QACnE,OAAO,IAAI,yCAAsB,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAEO,WAAW,CACjB,SAAiB,EACjB,cAAsB,EACtB,OAAe,EACf,eAAe,GAAG,GAAG,EACrB,eAAe,GAAG,IAAI;QAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QACvC,IAAI,SAAS,GAAG,eAAe,EAAE,CAAC;YAChC,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,8BAA8B,SAAS,SAAS,cAAc,SAAS,SAAS,IAAI,CAAC;QACrG,IAAI,SAAS,IAAI,eAAe,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;CACF;AAvUD,8CAuUC","sourcesContent":["import { Client, BucketItemStat } from 'minio';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { DataAccessor } from '@solid/community-server';\nimport type { Readable } from 'node:stream';\nimport { DataFactory } from 'n3';\nimport {\n RepresentationMetadata,\n \n NotFoundHttpError,\n guardStream,\n isContainerIdentifier,\n isContainerPath,\n joinFilePath,\n UnsupportedMediaTypeHttpError,\n CONTENT_TYPE_TERM,\n DC,\n IANA,\n LDP,\n POSIX,\n RDF,\n SOLID_META,\n XSD,\n parseQuads,\n serializeQuads,\n addResourceMetadata,\n updateModifiedDate,\n toLiteral,\n toNamedTerm,\n} from '@solid/community-server';\nimport type { Guarded } from '@solid/community-server';\nimport type { FileIdentifierMapper, ResourceLink } from '@solid/community-server';\nimport type { \n ResourceIdentifier,\n Representation,\n MetadataRecord\n} from '@solid/community-server';\n\nexport class MinioDataAccessor implements DataAccessor {\n protected readonly logger = getLoggerFor(this);\n protected readonly resourceMapper: FileIdentifierMapper;\n private readonly client: Client;\n private readonly bucketName: string;\n\n public constructor(\n resourceMapper: FileIdentifierMapper,\n accessKey: string,\n secretKey: string,\n endpoint: string,\n bucketName: string,\n ) {\n this.resourceMapper = resourceMapper;\n\n // Parse endpoint - supports both URL format (http://host:port) and simple format (host:port)\n let endPoint: string;\n let port: number | undefined;\n let useSSL = false;\n\n if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {\n const url = new URL(endpoint);\n endPoint = url.hostname;\n port = url.port ? parseInt(url.port, 10) : undefined;\n useSSL = url.protocol === 'https:';\n } else {\n const parts = endpoint.split(':');\n endPoint = parts[0];\n port = parts[1] ? parseInt(parts[1], 10) : undefined;\n }\n\n this.client = new Client({\n accessKey,\n secretKey,\n endPoint,\n port,\n useSSL,\n });\n this.bucketName = bucketName;\n this.logger.info(`MinioDataAccessor initialized with endpoint: ${endPoint}:${port} (SSL: ${useSSL})`)\n }\n\n /**\n * Should throw a NotImplementedHttpError if the DataAccessor does not support storing the given Representation.\n *\n * @param representation - Incoming Representation.\n *\n * @throws BadRequestHttpError\n * If it does not support the incoming data.\n */\n public async canHandle(representation: Representation): Promise<void> {\n if (!representation.binary) {\n throw new UnsupportedMediaTypeHttpError('Only binary data is supported.');\n }\n }\n\n /**\n * Returns a data stream stored for the given identifier.\n * It can be assumed that the incoming identifier will always correspond to a document.\n *\n * @param identifier - Identifier for which the data is requested.\n */\n public async getData(identifier: ResourceIdentifier): Promise<Guarded<Readable>> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const stream = await this.client.getObject(this.bucketName, url.pathname);\n this.logDuration('getData', identifier.path, started);\n return guardStream(stream);\n }\n\n /**\n * Generate a presigned GET URL for the given resource.\n * @param identifier - Resource identifier.\n * @param expires - URL expiry in seconds (default 3600).\n */\n public async getPresignedUrl(identifier: ResourceIdentifier, expires = 3600): Promise<string> {\n const url = new URL(identifier.path);\n const objectKey = url.pathname.replace(/^\\//, '');\n return this.client.presignedGetObject(this.bucketName, objectKey, expires);\n }\n\n /**\n * Returns the metadata corresponding to the identifier.\n * If possible, it is suggested to add a `posix:size` triple to the metadata indicating the binary size.\n * This is necessary for range requests.\n *\n * @param identifier - Identifier for which the metadata is requested.\n */\n public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n const isDirectory = identifier.path.endsWith('/');\n const objectName = isDirectory ? `${url.pathname}/.container` : url.pathname;\n let stats: BucketItemStat;\n try {\n stats = await this.client.statObject(this.bucketName, objectName);\n } catch (error) {\n throw new NotFoundHttpError();\n }\n if (!isContainerIdentifier(identifier) && !isDirectory) {\n const metadata = await this.getFileMetadata(link, stats);\n this.logDuration('getMetadata', identifier.path, started);\n return metadata;\n }\n if (isContainerIdentifier(identifier) && isDirectory) {\n const metadata = await this.getDirectoryMetadata(link, stats);\n this.logDuration('getMetadata', identifier.path, started);\n return metadata;\n }\n throw new NotFoundHttpError();\n }\n\n /**\n * Returns metadata for all resources in the requested container.\n * This should not be all metadata of those resources (but it can be),\n * but instead the main metadata you want to show in situations\n * where all these resources are presented simultaneously.\n * Generally this would be metadata that is present for all of these resources,\n * such as resource type or last modified date.\n *\n * It can be safely assumed that the incoming identifier will always correspond to a container.\n *\n * @param identifier - Identifier of the parent container.\n */\n public async* getChildren(identifier: ResourceIdentifier): AsyncIterableIterator<RepresentationMetadata> {\n const url = new URL(identifier.path)\n const objects = this.client.listObjectsV2(this.bucketName, url.pathname);\n for await (const object of objects) {\n const metadata = await this.getMetadata(object);\n yield metadata;\n }\n }\n\n /**\n * Writes data and metadata for a document.\n * If any data and/or metadata exist for the given identifier, it should be overwritten.\n *\n * @param identifier - Identifier of the resource.\n * @param data - Data to store.\n * @param metadata - Metadata to store.\n */\n public async writeDocument(identifier: ResourceIdentifier, data: Guarded<Readable>, metadata: RepresentationMetadata): Promise<void> {\n const started = Date.now();\n const url = new URL(identifier.path);\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n const itemMetadata = this.encodeMetadata(link, metadata);\n try {\n await this.client.putObject(\n this.bucketName,\n url.pathname,\n data,\n metadata.contentLength,\n itemMetadata || undefined,\n );\n this.logDuration('writeDocument', identifier.path, started);\n } catch (error) {\n this.logger.error(`Error writing document: ${identifier.path} ${error}`)\n throw error;\n }\n }\n\n /**\n * Writes metadata for a container.\n * If the container does not exist yet it should be created,\n * if it does its metadata should be overwritten, except for the containment triples.\n *\n * @param identifier - Identifier of the container.\n * @param metadata - Metadata to store.\n */\n public async writeContainer(identifier: ResourceIdentifier, metadata: RepresentationMetadata): Promise<void> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n await this.client.putObject(\n this.bucketName,\n `${url.pathname}/.container`,\n Buffer.from(''),\n metadata.contentLength,\n this.encodeMetadata(link, metadata) || undefined,\n );\n this.logDuration('writeContainer', identifier.path, started);\n }\n\n /**\n * Writes metadata for a resource.\n * It can safely be assumed that the subject resource already exists.\n *\n * @param identifier - Identifier of the subject resource.\n * @param metadata - Metadata to store.\n */\n public async writeMetadata(identifier: ResourceIdentifier, metadata: RepresentationMetadata): Promise<void> {\n throw new Error('Minio does not support writing metadata for a resource.');\n }\n\n /**\n * Deletes the resource and its corresponding metadata.\n *\n * Solid, §5.4: \"When a contained resource is deleted, the server MUST also remove the corresponding containment\n * triple, which has the effect of removing the deleted resource from the containing container.\"\n * https://solid.github.io/specification/protocol#deleting-resources\n *\n * @param identifier - Resource to delete.\n */\n public async deleteResource(identifier: ResourceIdentifier): Promise<void> {\n const link = new URL(identifier.path)\n await this.client.removeObject(this.bucketName, link.pathname);\n }\n\n /**\n * Reads and generates all metadata relevant for the given file,\n * ingesting it into a RepresentationMetadata object.\n *\n * @param link - Path related metadata.\n * @param stats - Stats object of the corresponding file.\n */\n private async getFileMetadata(link: ResourceLink, stats: BucketItemStat): Promise<RepresentationMetadata> {\n const metadata = await this.getBaseMetadata(link, stats, false);\n // If the resource is using an unsupported contentType, the original contentType was written to the metadata file.\n // As a result, we should only set the contentType derived from the file path,\n // when no previous metadata entry for contentType is present.\n if (typeof metadata.contentType === 'undefined') {\n metadata.set(CONTENT_TYPE_TERM, link.contentType);\n }\n return metadata;\n }\n\n /**\n * Reads and generates all metadata relevant for the given directory,\n * ingesting it into a RepresentationMetadata object.\n *\n * @param link - Path related metadata.\n * @param stats - Stats object of the corresponding directory.\n */\n private async getDirectoryMetadata(link: ResourceLink, stats: BucketItemStat): Promise<RepresentationMetadata> {\n return this.getBaseMetadata(link, stats, true);\n }\n \n /**\n * Generates metadata relevant for any resources stored by this accessor.\n *\n * @param link - Path related metadata.\n * @param stats - Stats objects of the corresponding directory.\n * @param isContainer - If the path points to a container (directory) or not.\n */\n private async getBaseMetadata(link: ResourceLink, stats: BucketItemStat, isContainer: boolean): Promise<RepresentationMetadata> {\n const metadata = this.decodeMetadata(link, stats.metaData);\n addResourceMetadata(metadata, isContainer);\n this.addPosixMetadata(metadata, stats, isContainer);\n return metadata;\n }\n \n /**\n * Helper function to add file system related metadata.\n *\n * @param metadata - metadata object to add to\n * @param stats - Stats of the file/directory corresponding to the resource.\n */\n private addPosixMetadata(metadata: RepresentationMetadata, stats: BucketItemStat, isDirectory: boolean): void {\n updateModifiedDate(metadata, stats.lastModified);\n metadata.add(\n POSIX.terms.mtime,\n toLiteral(Math.floor(stats.lastModified.getTime() / 1000), XSD.terms.integer),\n SOLID_META.terms.ResponseMetadata,\n );\n if (!isDirectory) {\n metadata.add(\n POSIX.terms.size,\n toLiteral(stats.size, XSD.terms.integer),\n SOLID_META.terms.ResponseMetadata,\n );\n }\n }\n\n /**\n * encode the metadata of the resource to string.\n *\n * @param link - Path related metadata of the resource.\n * @param metadata - Metadata to write.\n *\n * @returns string of metadata.\n */\n protected encodeMetadata(link: ResourceLink, metadata: RepresentationMetadata): object | null {\n // These are stored by file system conventions\n metadata.remove(RDF.terms.type, LDP.terms.Resource);\n metadata.remove(RDF.terms.type, LDP.terms.Container);\n metadata.remove(RDF.terms.type, LDP.terms.BasicContainer);\n metadata.removeAll(DC.terms.modified);\n // When writing metadata for a document, only remove the content-type when dealing with a supported media type.\n // A media type is supported if the FileIdentifierMapper can correctly store it.\n // This allows restoring the appropriate content-type on data read (see getFileMetadata).\n if (isContainerPath(link.filePath) || typeof metadata.contentType !== 'undefined') {\n metadata.removeAll(CONTENT_TYPE_TERM);\n }\n const contentTypeObject = metadata.contentTypeObject\n if (contentTypeObject === undefined\n || Object.keys(contentTypeObject.parameters).length === 0) {\n return null;\n }\n // Write metadata to file if there are quads remaining\n return contentTypeObject.parameters;\n }\n\n protected decodeMetadata(link: ResourceLink, metadata: MetadataRecord): RepresentationMetadata {\n return new RepresentationMetadata(link.identifier, metadata);\n }\n\n private logDuration(\n operation: string,\n identifierPath: string,\n started: number,\n slowThresholdMs = 100,\n warnThresholdMs = 1000,\n ): void {\n const elapsedMs = Date.now() - started;\n if (elapsedMs < slowThresholdMs) {\n return;\n }\n\n const message = `[timing] MinioDataAccessor.${operation} path=${identifierPath} took=${elapsedMs}ms`;\n if (elapsedMs >= warnThresholdMs) {\n this.logger.warn(message);\n return;\n }\n\n this.logger.info(message);\n }\n}\n"]}
1
+ {"version":3,"file":"MinioDataAccessor.js","sourceRoot":"","sources":["../../../src/storage/accessors/MinioDataAccessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { Client, BucketItemStat } from 'minio';\nimport { getLoggerFor } from 'global-logger-factory';\nimport type { DataAccessor } from '@solid/community-server';\nimport type { Readable } from 'node:stream';\nimport { DataFactory } from 'n3';\nimport {\n RepresentationMetadata,\n \n NotFoundHttpError,\n guardStream,\n isContainerIdentifier,\n isContainerPath,\n joinFilePath,\n UnsupportedMediaTypeHttpError,\n CONTENT_TYPE_TERM,\n DC,\n IANA,\n LDP,\n POSIX,\n RDF,\n SOLID_META,\n XSD,\n parseQuads,\n serializeQuads,\n addResourceMetadata,\n updateModifiedDate,\n toLiteral,\n toNamedTerm,\n} from '@solid/community-server';\nimport type { Guarded } from '@solid/community-server';\nimport type { FileIdentifierMapper, ResourceLink } from '@solid/community-server';\nimport type { \n ResourceIdentifier,\n Representation,\n MetadataRecord\n} from '@solid/community-server';\n\nexport class MinioDataAccessor implements DataAccessor {\n protected readonly logger = getLoggerFor(this);\n protected readonly resourceMapper: FileIdentifierMapper;\n private readonly client: Client;\n private readonly bucketName: string;\n\n public constructor(\n resourceMapper: FileIdentifierMapper,\n accessKey: string,\n secretKey: string,\n endpoint: string,\n bucketName: string,\n ) {\n this.resourceMapper = resourceMapper;\n\n // Parse endpoint - supports both URL format (http://host:port) and simple format (host:port)\n let endPoint: string;\n let port: number | undefined;\n let useSSL = false;\n\n if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) {\n const url = new URL(endpoint);\n endPoint = url.hostname;\n port = url.port ? parseInt(url.port, 10) : undefined;\n useSSL = url.protocol === 'https:';\n } else {\n const parts = endpoint.split(':');\n endPoint = parts[0];\n port = parts[1] ? parseInt(parts[1], 10) : undefined;\n }\n\n this.client = new Client({\n accessKey,\n secretKey,\n endPoint,\n port,\n useSSL,\n });\n this.bucketName = bucketName;\n this.logger.info(`MinioDataAccessor initialized with endpoint: ${endPoint}:${port} (SSL: ${useSSL})`)\n }\n\n private objectName(url: URL): string {\n return url.pathname.replace(/^\\/+/u, '');\n }\n\n private containerObjectName(url: URL): string {\n return `${this.objectName(url).replace(/\\/+$/u, '')}/.container`;\n }\n\n /**\n * Should throw a NotImplementedHttpError if the DataAccessor does not support storing the given Representation.\n *\n * @param representation - Incoming Representation.\n *\n * @throws BadRequestHttpError\n * If it does not support the incoming data.\n */\n public async canHandle(representation: Representation): Promise<void> {\n if (!representation.binary) {\n throw new UnsupportedMediaTypeHttpError('Only binary data is supported.');\n }\n }\n\n /**\n * Returns a data stream stored for the given identifier.\n * It can be assumed that the incoming identifier will always correspond to a document.\n *\n * @param identifier - Identifier for which the data is requested.\n */\n public async getData(identifier: ResourceIdentifier): Promise<Guarded<Readable>> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const stream = await this.client.getObject(this.bucketName, this.objectName(url));\n this.logDuration('getData', identifier.path, started);\n return guardStream(stream);\n }\n\n /**\n * Generate a presigned GET URL for the given resource.\n * @param identifier - Resource identifier.\n * @param expires - URL expiry in seconds (default 3600).\n */\n public async getPresignedUrl(identifier: ResourceIdentifier, expires = 3600): Promise<string> {\n const url = new URL(identifier.path);\n const objectKey = this.objectName(url);\n return this.client.presignedGetObject(this.bucketName, objectKey, expires);\n }\n\n /**\n * Returns the metadata corresponding to the identifier.\n * If possible, it is suggested to add a `posix:size` triple to the metadata indicating the binary size.\n * This is necessary for range requests.\n *\n * @param identifier - Identifier for which the metadata is requested.\n */\n public async getMetadata(identifier: ResourceIdentifier): Promise<RepresentationMetadata> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n const isDirectory = identifier.path.endsWith('/');\n const objectName = isDirectory ? this.containerObjectName(url) : this.objectName(url);\n let stats: BucketItemStat;\n try {\n stats = await this.client.statObject(this.bucketName, objectName);\n } catch (error) {\n throw new NotFoundHttpError();\n }\n if (!isContainerIdentifier(identifier) && !isDirectory) {\n const metadata = await this.getFileMetadata(link, stats);\n this.logDuration('getMetadata', identifier.path, started);\n return metadata;\n }\n if (isContainerIdentifier(identifier) && isDirectory) {\n const metadata = await this.getDirectoryMetadata(link, stats);\n this.logDuration('getMetadata', identifier.path, started);\n return metadata;\n }\n throw new NotFoundHttpError();\n }\n\n /**\n * Returns metadata for all resources in the requested container.\n * This should not be all metadata of those resources (but it can be),\n * but instead the main metadata you want to show in situations\n * where all these resources are presented simultaneously.\n * Generally this would be metadata that is present for all of these resources,\n * such as resource type or last modified date.\n *\n * It can be safely assumed that the incoming identifier will always correspond to a container.\n *\n * @param identifier - Identifier of the parent container.\n */\n public async* getChildren(identifier: ResourceIdentifier): AsyncIterableIterator<RepresentationMetadata> {\n const url = new URL(identifier.path)\n const objects = this.client.listObjectsV2(this.bucketName, this.objectName(url));\n for await (const object of objects) {\n const metadata = await this.getMetadata(object);\n yield metadata;\n }\n }\n\n /**\n * Writes data and metadata for a document.\n * If any data and/or metadata exist for the given identifier, it should be overwritten.\n *\n * @param identifier - Identifier of the resource.\n * @param data - Data to store.\n * @param metadata - Metadata to store.\n */\n public async writeDocument(identifier: ResourceIdentifier, data: Guarded<Readable>, metadata: RepresentationMetadata): Promise<void> {\n const started = Date.now();\n const url = new URL(identifier.path);\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n const itemMetadata = this.encodeMetadata(link, metadata);\n try {\n await this.client.putObject(\n this.bucketName,\n this.objectName(url),\n data,\n metadata.contentLength,\n itemMetadata || undefined,\n );\n this.logDuration('writeDocument', identifier.path, started);\n } catch (error) {\n this.logger.error(`Error writing document: ${identifier.path} ${error}`)\n throw error;\n }\n }\n\n /**\n * Writes metadata for a container.\n * If the container does not exist yet it should be created,\n * if it does its metadata should be overwritten, except for the containment triples.\n *\n * @param identifier - Identifier of the container.\n * @param metadata - Metadata to store.\n */\n public async writeContainer(identifier: ResourceIdentifier, metadata: RepresentationMetadata): Promise<void> {\n const started = Date.now();\n const url = new URL(identifier.path)\n const link = await this.resourceMapper.mapUrlToFilePath(identifier, false);\n await this.client.putObject(\n this.bucketName,\n this.containerObjectName(url),\n Buffer.from(''),\n metadata.contentLength,\n this.encodeMetadata(link, metadata) || undefined,\n );\n this.logDuration('writeContainer', identifier.path, started);\n }\n\n /**\n * Writes metadata for a resource.\n * It can safely be assumed that the subject resource already exists.\n *\n * @param identifier - Identifier of the subject resource.\n * @param metadata - Metadata to store.\n */\n public async writeMetadata(identifier: ResourceIdentifier, metadata: RepresentationMetadata): Promise<void> {\n throw new Error('Minio does not support writing metadata for a resource.');\n }\n\n /**\n * Deletes the resource and its corresponding metadata.\n *\n * Solid, §5.4: \"When a contained resource is deleted, the server MUST also remove the corresponding containment\n * triple, which has the effect of removing the deleted resource from the containing container.\"\n * https://solid.github.io/specification/protocol#deleting-resources\n *\n * @param identifier - Resource to delete.\n */\n public async deleteResource(identifier: ResourceIdentifier): Promise<void> {\n const link = new URL(identifier.path)\n await this.client.removeObject(this.bucketName, this.objectName(link));\n }\n\n /**\n * Reads and generates all metadata relevant for the given file,\n * ingesting it into a RepresentationMetadata object.\n *\n * @param link - Path related metadata.\n * @param stats - Stats object of the corresponding file.\n */\n private async getFileMetadata(link: ResourceLink, stats: BucketItemStat): Promise<RepresentationMetadata> {\n const metadata = await this.getBaseMetadata(link, stats, false);\n // If the resource is using an unsupported contentType, the original contentType was written to the metadata file.\n // As a result, we should only set the contentType derived from the file path,\n // when no previous metadata entry for contentType is present.\n if (typeof metadata.contentType === 'undefined') {\n metadata.set(CONTENT_TYPE_TERM, link.contentType);\n }\n return metadata;\n }\n\n /**\n * Reads and generates all metadata relevant for the given directory,\n * ingesting it into a RepresentationMetadata object.\n *\n * @param link - Path related metadata.\n * @param stats - Stats object of the corresponding directory.\n */\n private async getDirectoryMetadata(link: ResourceLink, stats: BucketItemStat): Promise<RepresentationMetadata> {\n return this.getBaseMetadata(link, stats, true);\n }\n \n /**\n * Generates metadata relevant for any resources stored by this accessor.\n *\n * @param link - Path related metadata.\n * @param stats - Stats objects of the corresponding directory.\n * @param isContainer - If the path points to a container (directory) or not.\n */\n private async getBaseMetadata(link: ResourceLink, stats: BucketItemStat, isContainer: boolean): Promise<RepresentationMetadata> {\n const metadata = this.decodeMetadata(link, stats.metaData);\n addResourceMetadata(metadata, isContainer);\n this.addPosixMetadata(metadata, stats, isContainer);\n return metadata;\n }\n \n /**\n * Helper function to add file system related metadata.\n *\n * @param metadata - metadata object to add to\n * @param stats - Stats of the file/directory corresponding to the resource.\n */\n private addPosixMetadata(metadata: RepresentationMetadata, stats: BucketItemStat, isDirectory: boolean): void {\n updateModifiedDate(metadata, stats.lastModified);\n metadata.add(\n POSIX.terms.mtime,\n toLiteral(Math.floor(stats.lastModified.getTime() / 1000), XSD.terms.integer),\n SOLID_META.terms.ResponseMetadata,\n );\n if (!isDirectory) {\n metadata.add(\n POSIX.terms.size,\n toLiteral(stats.size, XSD.terms.integer),\n SOLID_META.terms.ResponseMetadata,\n );\n }\n }\n\n /**\n * encode the metadata of the resource to string.\n *\n * @param link - Path related metadata of the resource.\n * @param metadata - Metadata to write.\n *\n * @returns string of metadata.\n */\n protected encodeMetadata(link: ResourceLink, metadata: RepresentationMetadata): object | null {\n // These are stored by file system conventions\n metadata.remove(RDF.terms.type, LDP.terms.Resource);\n metadata.remove(RDF.terms.type, LDP.terms.Container);\n metadata.remove(RDF.terms.type, LDP.terms.BasicContainer);\n metadata.removeAll(DC.terms.modified);\n // When writing metadata for a document, only remove the content-type when dealing with a supported media type.\n // A media type is supported if the FileIdentifierMapper can correctly store it.\n // This allows restoring the appropriate content-type on data read (see getFileMetadata).\n if (isContainerPath(link.filePath) || typeof metadata.contentType !== 'undefined') {\n metadata.removeAll(CONTENT_TYPE_TERM);\n }\n const contentTypeObject = metadata.contentTypeObject\n if (contentTypeObject === undefined\n || Object.keys(contentTypeObject.parameters).length === 0) {\n return null;\n }\n // Write metadata to file if there are quads remaining\n return contentTypeObject.parameters;\n }\n\n protected decodeMetadata(link: ResourceLink, metadata: MetadataRecord): RepresentationMetadata {\n return new RepresentationMetadata(link.identifier, metadata);\n }\n\n private logDuration(\n operation: string,\n identifierPath: string,\n started: number,\n slowThresholdMs = 100,\n warnThresholdMs = 1000,\n ): void {\n const elapsedMs = Date.now() - started;\n if (elapsedMs < slowThresholdMs) {\n return;\n }\n\n const message = `[timing] MinioDataAccessor.${operation} path=${identifierPath} took=${elapsedMs}ms`;\n if (elapsedMs >= warnThresholdMs) {\n this.logger.warn(message);\n return;\n }\n\n this.logger.info(message);\n }\n}\n"]}
@@ -59,6 +59,14 @@
59
59
  "@id": "undefineds:dist/storage/accessors/MinioDataAccessor.jsonld#MinioDataAccessor__member_constructor",
60
60
  "memberFieldName": "constructor"
61
61
  },
62
+ {
63
+ "@id": "undefineds:dist/storage/accessors/MinioDataAccessor.jsonld#MinioDataAccessor__member_objectName",
64
+ "memberFieldName": "objectName"
65
+ },
66
+ {
67
+ "@id": "undefineds:dist/storage/accessors/MinioDataAccessor.jsonld#MinioDataAccessor__member_containerObjectName",
68
+ "memberFieldName": "containerObjectName"
69
+ },
62
70
  {
63
71
  "@id": "undefineds:dist/storage/accessors/MinioDataAccessor.jsonld#MinioDataAccessor__member_canHandle",
64
72
  "memberFieldName": "canHandle"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@undefineds.co/xpod",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Xpod is an extended Community Solid Server, offering rich-feature, production-level Solid Pod and identity management.",
5
5
  "repository": "https://github.com/undefinedsco/xpod",
6
6
  "author": "developer@undefineds.co",