@things-factory/attachment-base 10.1.40 → 10.1.44

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.
@@ -238,6 +238,21 @@ async function createAttachments(_, { attachments }, context) {
238
238
  }
239
239
  return resolve;
240
240
  }
241
+ /**
242
+ * Removes a file from storage - after the commit, when there is one to wait for.
243
+ *
244
+ * Inside @transaction the row is deleted now and the file waits on context.state.afterCommit: a commit
245
+ * that fails brings the row back, and the file must still be there (ADR-0091 decision 8). Outside a
246
+ * transaction there is nothing to roll back, so the file goes at once, as before. A transaction opened
247
+ * by hand, without runTransaction, has no list either - the file goes at once there too, and a failed
248
+ * commit still loses it.
249
+ */
250
+ async function deleteFileWhenCommitted(path, context) {
251
+ const deferred = (0, shell_1.whenCommitted)(context?.state?.afterCommit, `delete attachment file ${path}`, () => attachment_const_1.STORAGE.deleteFile(path));
252
+ if (!deferred) {
253
+ await attachment_const_1.STORAGE.deleteFile(path);
254
+ }
255
+ }
241
256
  async function deleteAttachment(_, { id }, context) {
242
257
  const { domain, tx } = context.state;
243
258
  const repository = tx ? tx.getRepository(attachment_1.Attachment) : (0, shell_1.getRepository)(attachment_1.Attachment);
@@ -246,7 +261,7 @@ async function deleteAttachment(_, { id }, context) {
246
261
  });
247
262
  if (attachment) {
248
263
  await repository.delete({ id: attachment.id });
249
- await attachment_const_1.STORAGE.deleteFile(attachment.path);
264
+ await deleteFileWhenCommitted(attachment.path, context);
250
265
  return true;
251
266
  }
252
267
  else {
@@ -270,9 +285,7 @@ async function deleteAttachmentsByRef(_, { refBys, refType = null }, context) {
270
285
  await repository.delete(deleteWhereClause);
271
286
  //remove files from attachments folder
272
287
  if (attachments.length) {
273
- await Promise.all(attachments.map(async (attachment) => {
274
- await attachment_const_1.STORAGE.deleteFile(attachment.path);
275
- }));
288
+ await Promise.all(attachments.map(attachment => deleteFileWhenCommitted(attachment.path, context)));
276
289
  return true;
277
290
  }
278
291
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"attachment-mutation.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-mutation.ts"],"names":[],"mappings":";;;;AAsIA,4CA4DC;AAED,8CAYC;AAED,4CAeC;AAMD,wDAmCC;AAED,8CAMC;AAED,oCAEC;AAED,wCAEC;AAkDD,8CAwDC;;AApYD,sEAA4D;AAC5D,+FAA2D;AAC3D,wEAAsC;AAEtC,+CAA2E;AAC3E,qCAA4B;AAE5B,6CAAoD;AACpD,iDAAqD;AAErD,6DAAgD;AAChD,6CAAyC;AACzC,yDAA8E;AAC9E,yCAAoE;AACpE,2CAA+C;AAC/C,6DAA4F;AAE5F,MAAM,gBAAgB,GAAG,YAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAA;AAGxD,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAIvB,AAAN,KAAK,CAAC,gBAAgB,CACsB,UAAyB,EAC5D,OAAwB;QAE/B,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CACwB,WAA4B,EAClE,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CACT,EAAU,EACkB,KAAsB,EACtD,OAAwB;QAE/B,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAC,OAAO,CAAC;YACzD,KAAK,EAAE;gBACL,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE;gBACvC,EAAE;aACH;SACF,CAAC,CAAA;QAEF,OAAO,MAAM,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAC,IAAI,CAAC;YAC1C,GAAG,UAAU;YACb,GAAG,KAAK;YACR,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;SAC5B,CAAC,CAAA;IACJ,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CAAY,EAAU,EAAS,OAAwB;QAC3E,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAKK,AAAN,KAAK,CAAC,sBAAsB,CACO,MAAgB,EACG,OAAe,EAC5D,OAAwB;QAE/B,OAAO,MAAM,sBAAsB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,CAAA;IACzE,CAAC;IAKK,AAAN,KAAK,CAAC,YAAY,CACoB,IAAgB,EAC7C,OAAwB;QAE/B,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;IAKK,AAAN,KAAK,CAAC,cAAc,CACqB,KAAmB,EACnD,OAAwB;QAE/B,OAAO,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAIK,AAAN,KAAK,CAAC,iBAAiB,CACQ,IAAY,EAClC,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACzD,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CACa,IAAgB,EAC3C,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAC/C,CAAC;IAQK,AAAN,KAAK,CAAC,4BAA4B,CACiC,KAAa,EACvE,OAAwB;QAE/B,OAAO,MAAM,IAAA,iDAA4B,EAAC,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;IAC/D,CAAC;CACF,CAAA;AAhHY,gDAAkB;AAIvB;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,gCAAa,CAAC,CAAA;IACxC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CADgD,gCAAa;;0DAIpE;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,mBAAA,IAAA,kBAAG,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,gCAAa,CAAC,CAAC,CAAA;IAC3C,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IACT,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kCAAe,CAAC,CAAA;IACrC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;qDADwC,kCAAe;;0DAe9D;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IACL,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;0DAEnD;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IAE1B,mBAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/B,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;gEAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,0BAAa,CAAC,CAAA;IAClC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;iEADoC,6BAAU,oBAAV,6BAAU;;sDAIrD;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,0BAAa,CAAC,CAAC,CAAA;IACrC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;wDAGP;AAIK;IAFL,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,4BAAS,CAAC;IAC9B,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAE9F,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;IAC3B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,EAAE,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAE9E,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,GAAG,EAAE,CAAC,0BAAa,CAAC,CAAA;IAChC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;iEADkC,6BAAU,oBAAV,6BAAU;;2DAInD;AAQK;IANL,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,4CAAuB,EAAE;QAC5C,WAAW,EACT,0CAA0C;YAC1C,mDAAmD;KACtD,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA;IAC/D,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sEAGP;6BA/GU,kBAAkB;IAD9B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;GACR,kBAAkB,CAgH9B;AAEM,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,UAAU,EAAE,EAAE,OAAwB;IACrF,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,CAAA;IACvE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,CAAC,MAAM,IAAI,CAAe,CAAA;IAE/D,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAAO,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IACpG,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAE1C,mDAAmD;IACnD,kEAAkE;IAClE,8CAA8C;IAC9C,oDAAoD;IACpD,MAAM,QAAQ,GAAG,IAAA,4BAAiB,EAAC,cAAc,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAEtE,qDAAqD;IACrD,sDAAsD;IACtD,8DAA8D;IAC9D,qDAAqD;IACrD,iCAAiC;IACjC,wDAAwD;IACxD,IAAI,gBAAgB,YAAY,KAAK,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1G,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;YAC/B,IAAI,CAAC,IAAI;gBAAE,OAAO,KAAK,CAAA;YACvB,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAClC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC3C,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC3C,OAAO,CACL,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,CAAC,CAC7G,CAAA;YACH,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA;QAED,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC;gBAAC,MAAM,0BAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAAC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,YAAM,CAAC,IAAI,CAAC,sDAAuD,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;YAC3F,CAAC;YACD,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAA;QAChG,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,IAAA,6BAAiB,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAE7D,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAEhF,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC;QAC3B,MAAM;QACN,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,EAAE;QACF,WAAW;QACX,IAAI,EAAE,QAAQ;QACd,QAAQ;QACR,QAAQ;QACR,OAAO;QACP,KAAK;QACL,QAAQ,EAAE,QAAQ,IAAI,IAAA,+BAAoB,EAAC,QAAQ,CAAC;QACpD,IAAI,EAAE,IAAW;QACjB,IAAI;QACJ,QAAQ;QACR,SAAS;KACV,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,CAAM,EAAE,EAAE,WAAW,EAAE,EAAE,OAAwB;IACvF,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,sBAAW,CAAC,GAAG,CAC/C,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC,CAC5E,CAAA;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,YAAM,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAA;QAE1E,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAEM,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAwB;IAC7E,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEpC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAChF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;KACzC,CAAC,CAAA;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAA;QAC9C,MAAM,0BAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QACzC,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAMM,KAAK,UAAU,sBAAsB,CAC1C,CAAM,EACN,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAA2B,EACnD,OAAwB;IAExB,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IACpC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAChF,MAAM,iBAAiB,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE,CAAA;IAC/E,MAAM,iBAAiB,GAAQ,EAAE,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE,CAAA;IAEpD,4BAA4B;IAC5B,IAAI,OAAO,EAAE,CAAC;QACZ,iBAAiB,CAAC,OAAO,GAAG,OAAO,CAAA;QACnC,iBAAiB,CAAC,OAAO,GAAG,OAAO,CAAA;IACrC,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;QACxC,KAAK,EAAE,iBAAiB;KACzB,CAAC,CAAA;IAEF,6BAA6B;IAC7B,MAAM,UAAU,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAA;IAE1C,sCAAsC;IACtC,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,GAAG,CACf,WAAW,CAAC,GAAG,CAAC,KAAK,EAAC,UAAU,EAAC,EAAE;YACjC,MAAM,0BAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;QAC3C,CAAC,CAAC,CACH,CAAA;QAED,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACrC,CAAM,EACN,EAAE,IAAI,EAAE,EACR,OAAwB;IAExB,OAAO,MAAM,0BAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;AAC9C,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,CAAM,EAAE,EAAE,IAAI,EAAE,EAAE,OAAwB;IAC3E,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACxE,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,CAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAwB;IAC9E,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AAC3E,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,YAAwB;IACnD,IAAI,EAAE,gBAAgB,EAAE,GAAG,MAAM,YAAY,CAAA;IAE7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAiB,EAAE,CAAA;QAE/B,gBAAgB,EAAE;aACf,EAAE,CAAC,MAAM,EAAE,CAAC,KAAiB,EAAE,EAAE;YAChC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpB,CAAC,CAAC;aACD,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACd,IAAI,CAAC;gBACH,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;gBACzC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAA;YACf,CAAC;QACH,CAAC,CAAC;aACD,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe,EAAE,QAAgB,EAAE,QAAgB;IAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACzC,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAA;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAEhD,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,QAAQ;QAClB,gBAAgB,EAAE,GAAG,EAAE;YACrB,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;YAChC,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAA;YACtC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACrB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,OAAO,QAAQ,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,MAAkB,EAAE,OAAwB;IAClF,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAElD,MAAM,UAAU,GAAG,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAA;IAE/C,MAAM,WAAW,GAAG,EAAE,CAAA;IAEtB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAE1C,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;QAC9E,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,mCAAmC,CAAA;QAC3C,CAAC;QAED,IAAI,gBAAgB,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAEzD,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAI,gBAAgB,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,2BAA2B,EAAE,IAAI,IAAI,sCAAsC,CAAA;YACnF,CAAC;YAED,0BAA0B;YAC1B,SAAQ;QACV,CAAC;QAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;QAE1D,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAAO,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QAE9E,WAAW,CAAC,IAAI,CACd,MAAM,UAAU,CAAC,IAAI,CAAC;YACpB,MAAM;YACN,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;YACb,EAAE;YACF,WAAW;YACX,IAAI;YACJ,QAAQ;YACR,QAAQ;YACR,QAAQ,EAAE,QAAQ,IAAI,IAAA,+BAAoB,EAAC,QAAQ,CAAC;YACpD,IAAI,EAAE,IAAW;YACjB,IAAI;YACJ,QAAQ;SACT,CAAC,CACH,CAAA;IACH,CAAC;IAED,MAAM;QACJ,MAAM,CAAC;YACL,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG,WAAW,CAAC,MAAM,6BAA6B;YACzD,IAAI,EAAE,GAAG,WAAW,CAAC,MAAM,kCAAkC,IAAI,CAAC,IAAI,EAAE;SACzE,CAAC,CAAA;IAEJ,OAAO,WAAW,CAAA;AACpB,CAAC","sourcesContent":["import { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport promisesAll from 'promises-all'\n\nimport { Arg, Ctx, Directive, Int, Mutation, Resolver } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { config, logger } from '@things-factory/env'\nimport { getRepository } from '@things-factory/shell'\n\nimport { STORAGE } from '../../attachment-const'\nimport { Attachment } from './attachment'\nimport { AttachmentPatch, NewAttachment, UploadURL } from './attachment-types'\nimport { categoryFromMimetype, normalizeMimetype } from './mimetype'\nimport { generateThumbnail } from './thumbnail'\nimport { backfillAttachmentThumbnails, ThumbnailBackfillResult } from './thumbnail-backfill'\n\nconst allowedMimeTypes = config.get('fileUpload/mimeTypes', [])\n\n@Resolver(Attachment)\nexport class AttachmentMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async createAttachment(\n @Arg('attachment', type => NewAttachment) attachment: NewAttachment,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n return await createAttachment(null, { attachment }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment])\n async createAttachments(\n @Arg('attachments', type => [NewAttachment]) attachments: NewAttachment[],\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await createAttachments(null, { attachments }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async updateAttachment(\n @Arg('id') id: string,\n @Arg('patch', type => AttachmentPatch) patch: AttachmentPatch,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n const attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: context.state.domain.id },\n id\n }\n })\n\n return await getRepository(Attachment).save({\n ...attachment,\n ...patch,\n updater: context.state.user\n })\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean)\n async deleteAttachment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n return await deleteAttachment(null, { id }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean)\n async deleteAttachmentsByRef(\n @Arg('refBys', type => [String]) refBys: string[],\n @Arg('refType', type => String, { nullable: true }) refType: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n return await deleteAttachmentsByRef(null, { refBys, refType }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async singleUpload(\n @Arg('file', type => GraphQLUpload) file: FileUpload,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n return await singleUpload(null, { file }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment])\n async multipleUpload(\n @Arg('files', type => [GraphQLUpload]) files: FileUpload[],\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await multipleUpload(null, { files }, context)\n }\n\n @Mutation(returns => UploadURL)\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n async generateUploadURL(\n @Arg('type', type => String) type: string,\n @Ctx() context: ResolverContext\n ): Promise<{ url: string; fields: { [key: string]: string } }> {\n return await generateUploadURL(null, { type }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment], { description: 'To import some Attachments' })\n async importAttachments(\n @Arg('file', () => GraphQLUpload) file: FileUpload,\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await importAttachments(file, context)\n }\n\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ThumbnailBackfillResult, {\n description:\n '썸네일이 없는 기존 첨부파일들에 대해 서버에서 썸네일을 일괄 생성한다. ' +\n '한 호출당 limit 개까지만 처리하며, remaining > 0 이면 반복 호출 필요.'\n })\n async backfillAttachmentThumbnails(\n @Arg('limit', type => Int, { nullable: true, defaultValue: 20 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<ThumbnailBackfillResult> {\n return await backfillAttachmentThumbnails({ limit }, context)\n }\n}\n\nexport async function createAttachment(_: any, { attachment }, context: ResolverContext): Promise<Attachment> {\n const { file, category, refType = '', refBy, description } = attachment\n const { mimetype: clientMimetype } = (await file) as FileUpload\n\n const { id, path, size, filename, encoding, contents } = await STORAGE.uploadFile({ file, context })\n const { domain, user, tx } = context.state\n\n // 클라이언트가 보낸 mimetype 은 OS/브라우저 MIME DB 가 확장자를 인식하지\n // 못하면 'application/octet-stream' 으로 fallback 된다 (특히 .glb). 같은 파일이\n // 환경에 따라 다른 mime 으로 저장되면 썸네일/카테고리/검색 등 후속 로직이\n // 일관성을 잃으므로, 모호한 mime 만 magic byte → 확장자 순으로 재판정한다.\n const mimetype = normalizeMimetype(clientMimetype, filename, contents)\n\n // 허용 mime 검증 — 클라이언트 mime 또는 정규화된 mime 둘 중 하나라도 매칭되면\n // 통과. 클라이언트가 정확한 mime ('model/gltf+json' 등) 을 보낸 케이스와\n // 모호한 mime ('application/octet-stream') 으로 보낸 케이스 둘 다 동일 흐름으로\n // 처리되도록 — 이전엔 STORAGE 저장 전에 client mime 으로만 검증해서 정확한\n // mime 을 보낼수록 까다롭게 거절되는 역설이 있었다.\n // 검증을 STORAGE.uploadFile 후로 옮긴 대신, 거절 시 저장된 파일 cleanup.\n if (allowedMimeTypes instanceof Array && allowedMimeTypes.length > 0 && !allowedMimeTypes.includes('*/*')) {\n const matches = (mime: string) => {\n if (!mime) return false\n return allowedMimeTypes.some(type => {\n const [typeMain, typeSub] = type.split('/')\n const [mimeMain, mimeSub] = mime.split('/')\n return (\n (typeMain === mimeMain && (typeSub === '*' || typeSub === mimeSub)) || (typeMain === '*' && typeSub === '*')\n )\n })\n }\n\n if (!matches(clientMimetype) && !matches(mimetype)) {\n try { await STORAGE.deleteFile(path) } catch (e) {\n logger.warn(`[attachment] cleanup after rejected upload failed: ${(e as Error).message}`)\n }\n throw Error(context.t(`error.not allowed file type for upload`, { mimetype: clientMimetype }))\n }\n }\n\n const thumbnail = await generateThumbnail(contents, mimetype)\n\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n\n return await repository.save({\n domain,\n creator: user,\n updater: user,\n id,\n description,\n name: filename,\n mimetype,\n encoding,\n refType,\n refBy,\n category: category || categoryFromMimetype(mimetype),\n size: size as any,\n path,\n contents,\n thumbnail\n })\n}\n\nexport async function createAttachments(_: any, { attachments }, context: ResolverContext): Promise<Attachment[]> {\n const { resolve, reject } = await promisesAll.all(\n attachments.map(attachment => createAttachment(_, { attachment }, context))\n )\n\n if (reject.length) {\n reject.forEach(({ name, message }) => logger.error(`${name}: ${message}`))\n\n return reject\n }\n\n return resolve\n}\n\nexport async function deleteAttachment(_: any, { id }, context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n const attachment = await repository.findOne({\n where: { domain: { id: domain.id }, id }\n })\n\n if (attachment) {\n await repository.delete({ id: attachment.id })\n await STORAGE.deleteFile(attachment.path)\n return true\n } else {\n return false\n }\n}\n\ninterface DeleteAttachmentsObject {\n refBys: Array<string>\n refType?: string\n}\nexport async function deleteAttachmentsByRef(\n _: any,\n { refBys, refType = null }: DeleteAttachmentsObject,\n context: ResolverContext\n): Promise<boolean> {\n const { domain, tx } = context.state\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n const inquryWhereClause: any = { domain: { id: domain.id }, refBy: In(refBys) }\n const deleteWhereClause: any = { refBy: In(refBys) }\n\n // refType이 존재하면 where 절에 추가\n if (refType) {\n inquryWhereClause.refType = refType\n deleteWhereClause.refType = refType\n }\n\n const attachments = await repository.find({\n where: inquryWhereClause\n })\n\n //remove attachment from repo\n await repository.delete(deleteWhereClause)\n\n //remove files from attachments folder\n if (attachments.length) {\n await Promise.all(\n attachments.map(async attachment => {\n await STORAGE.deleteFile(attachment.path)\n })\n )\n\n return true\n } else {\n return false\n }\n}\n\nexport async function generateUploadURL(\n _: any,\n { type },\n context: ResolverContext\n): Promise<{ url: string; fields: { [key: string]: string } }> {\n return await STORAGE.generateUploadURL(type)\n}\n\nexport async function singleUpload(_: any, { file }, context: ResolverContext): Promise<Attachment> {\n return await createAttachment(null, { attachment: { file } }, context)\n}\n\nexport async function multipleUpload(_: any, { files }, context: ResolverContext): Promise<Attachment[]> {\n return await createAttachments(null, { attachments: { files } }, context)\n}\n\nasync function parseJSONFile(uploadedFile: FileUpload): Promise<any> {\n var { createReadStream } = await uploadedFile\n\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = []\n\n createReadStream()\n .on('data', (chunk: Uint8Array) => {\n chunks.push(chunk)\n })\n .on('end', () => {\n try {\n const fileContents = Buffer.concat(chunks).toString('utf-8')\n const jsonData = JSON.parse(fileContents)\n resolve(jsonData)\n } catch (error) {\n reject(error)\n }\n })\n .on('error', (error: Error) => {\n reject(error)\n })\n })\n}\n\nfunction dataURLToFileUpload(dataURL: string, filename: string, mimeType: string): FileUpload {\n const indexOfComma = dataURL.indexOf(',')\n if (indexOfComma === -1) {\n throw new Error('Invalid Data URL')\n }\n\n const base64Data = dataURL.slice(indexOfComma + 1)\n const buffer = Buffer.from(base64Data, 'base64')\n\n return {\n filename,\n mimetype: mimeType,\n encoding: 'base64',\n createReadStream: () => {\n const stream = require('stream')\n const readable = new stream.Readable()\n readable.push(buffer)\n readable.push(null)\n return readable\n }\n }\n}\n\nexport async function importAttachments(upload: FileUpload, context: ResolverContext): Promise<Attachment[]> {\n const { domain, user, notify, tx } = context.state\n\n const repository = tx.getRepository(Attachment)\n\n const attachments = []\n\n const parsed = await parseJSONFile(upload)\n\n for (const id in parsed) {\n var { name, description, category, mimetype, encoding, contents } = parsed[id]\n if (!name || !contents || !mimetype) {\n throw 'Malformed attachments import file'\n }\n\n var sameIdAttachment = await repository.findOneBy({ id })\n\n if (sameIdAttachment) {\n if (sameIdAttachment.domainId != domain.id) {\n throw `Attachment with id/name(${id}/${name}) is already taken in another domain`\n }\n\n // 동일 아이디 첨부파일이 있다면, 스킵한다.\n continue\n }\n\n const file = dataURLToFileUpload(contents, name, mimetype)\n\n var { path, size, contents } = await STORAGE.uploadFile({ id, file, context })\n\n attachments.push(\n await repository.save({\n domain,\n creator: user,\n updater: user,\n id,\n description,\n name,\n mimetype,\n encoding,\n category: category || categoryFromMimetype(mimetype),\n size: size as any,\n path,\n contents\n })\n )\n }\n\n notify &&\n notify({\n mode: 'in-app',\n title: `${attachments.length} Attachment(s) are imported`,\n body: `${attachments.length} Attachment(s) are imported by ${user.name}`\n })\n\n return attachments\n}\n"]}
1
+ {"version":3,"file":"attachment-mutation.js","sourceRoot":"","sources":["../../../server/service/attachment/attachment-mutation.ts"],"names":[],"mappings":";;;;AAsIA,4CA4DC;AAED,8CAYC;AAqBD,4CAeC;AAMD,wDA+BC;AAED,8CAMC;AAED,oCAEC;AAED,wCAEC;AAkDD,8CAwDC;;AAnZD,sEAA4D;AAC5D,+FAA2D;AAC3D,wEAAsC;AAEtC,+CAA2E;AAC3E,qCAA4B;AAE5B,6CAAoD;AACpD,iDAAoE;AAEpE,6DAAgD;AAChD,6CAAyC;AACzC,yDAA8E;AAC9E,yCAAoE;AACpE,2CAA+C;AAC/C,6DAA4F;AAE5F,MAAM,gBAAgB,GAAG,YAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAA;AAGxD,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAIvB,AAAN,KAAK,CAAC,gBAAgB,CACsB,UAAyB,EAC5D,OAAwB;QAE/B,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CACwB,WAA4B,EAClE,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,CAAA;IAChE,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CACT,EAAU,EACkB,KAAsB,EACtD,OAAwB;QAE/B,MAAM,UAAU,GAAG,MAAM,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAC,OAAO,CAAC;YACzD,KAAK,EAAE;gBACL,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE;gBACvC,EAAE;aACH;SACF,CAAC,CAAA;QAEF,OAAO,MAAM,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAC,IAAI,CAAC;YAC1C,GAAG,UAAU;YACb,GAAG,KAAK;YACR,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI;SAC5B,CAAC,CAAA;IACJ,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CAAY,EAAU,EAAS,OAAwB;QAC3E,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;IAKK,AAAN,KAAK,CAAC,sBAAsB,CACO,MAAgB,EACG,OAAe,EAC5D,OAAwB;QAE/B,OAAO,MAAM,sBAAsB,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,CAAA;IACzE,CAAC;IAKK,AAAN,KAAK,CAAC,YAAY,CACoB,IAAgB,EAC7C,OAAwB;QAE/B,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACpD,CAAC;IAKK,AAAN,KAAK,CAAC,cAAc,CACqB,KAAmB,EACnD,OAAwB;QAE/B,OAAO,MAAM,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;IACvD,CAAC;IAIK,AAAN,KAAK,CAAC,iBAAiB,CACQ,IAAY,EAClC,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,CAAC,CAAA;IACzD,CAAC;IAKK,AAAN,KAAK,CAAC,iBAAiB,CACa,IAAgB,EAC3C,OAAwB;QAE/B,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IAC/C,CAAC;IAQK,AAAN,KAAK,CAAC,4BAA4B,CACiC,KAAa,EACvE,OAAwB;QAE/B,OAAO,MAAM,IAAA,iDAA4B,EAAC,EAAE,KAAK,EAAE,EAAE,OAAO,CAAC,CAAA;IAC/D,CAAC;CACF,CAAA;AAhHY,gDAAkB;AAIvB;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,gCAAa,CAAC,CAAA;IACxC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;6CADgD,gCAAa;;0DAIpE;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,mBAAA,IAAA,kBAAG,EAAC,aAAa,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,gCAAa,CAAC,CAAC,CAAA;IAC3C,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IACT,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kCAAe,CAAC,CAAA;IACrC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;qDADwC,kCAAe;;0DAe9D;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IACL,mBAAA,IAAA,kBAAG,EAAC,IAAI,CAAC,CAAA;IAAc,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;0DAEnD;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC;IAE1B,mBAAA,IAAA,kBAAG,EAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAC/B,mBAAA,IAAA,kBAAG,EAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;gEAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,uBAAU,CAAC;IAE7B,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,0BAAa,CAAC,CAAA;IAClC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;iEADoC,6BAAU,oBAAV,6BAAU;;sDAIrD;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,CAAC;IAE/B,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC,0BAAa,CAAC,CAAC,CAAA;IACrC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;wDAGP;AAIK;IAFL,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,4BAAS,CAAC;IAC9B,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAE9F,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,CAAA;IAC3B,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;2DAGP;AAKK;IAHL,IAAA,wBAAS,EAAC,cAAc,CAAC;IACzB,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,uBAAU,CAAC,EAAE,EAAE,WAAW,EAAE,4BAA4B,EAAE,CAAC;IAE9E,mBAAA,IAAA,kBAAG,EAAC,MAAM,EAAE,GAAG,EAAE,CAAC,0BAAa,CAAC,CAAA;IAChC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;iEADkC,6BAAU,oBAAV,6BAAU;;2DAInD;AAQK;IANL,IAAA,wBAAS,EAAC,qFAAqF,CAAC;IAChG,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,4CAAuB,EAAE;QAC5C,WAAW,EACT,0CAA0C;YAC1C,mDAAmD;KACtD,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA;IAC/D,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;sEAGP;6BA/GU,kBAAkB;IAD9B,IAAA,uBAAQ,EAAC,uBAAU,CAAC;GACR,kBAAkB,CAgH9B;AAEM,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,UAAU,EAAE,EAAE,OAAwB;IACrF,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,UAAU,CAAA;IACvE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,CAAC,MAAM,IAAI,CAAe,CAAA;IAE/D,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAAO,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IACpG,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAE1C,mDAAmD;IACnD,kEAAkE;IAClE,8CAA8C;IAC9C,oDAAoD;IACpD,MAAM,QAAQ,GAAG,IAAA,4BAAiB,EAAC,cAAc,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAEtE,qDAAqD;IACrD,sDAAsD;IACtD,8DAA8D;IAC9D,qDAAqD;IACrD,iCAAiC;IACjC,wDAAwD;IACxD,IAAI,gBAAgB,YAAY,KAAK,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1G,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;YAC/B,IAAI,CAAC,IAAI;gBAAE,OAAO,KAAK,CAAA;YACvB,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;gBAClC,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC3C,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC3C,OAAO,CACL,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,OAAO,KAAK,GAAG,IAAI,OAAO,KAAK,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,OAAO,KAAK,GAAG,CAAC,CAC7G,CAAA;YACH,CAAC,CAAC,CAAA;QACJ,CAAC,CAAA;QAED,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACnD,IAAI,CAAC;gBAAC,MAAM,0BAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;YAAC,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBAChD,YAAM,CAAC,IAAI,CAAC,sDAAuD,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;YAC3F,CAAC;YACD,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wCAAwC,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAA;QAChG,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,MAAM,IAAA,6BAAiB,EAAC,QAAQ,EAAE,QAAQ,CAAC,CAAA;IAE7D,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAEhF,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC;QAC3B,MAAM;QACN,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,EAAE;QACF,WAAW;QACX,IAAI,EAAE,QAAQ;QACd,QAAQ;QACR,QAAQ;QACR,OAAO;QACP,KAAK;QACL,QAAQ,EAAE,QAAQ,IAAI,IAAA,+BAAoB,EAAC,QAAQ,CAAC;QACpD,IAAI,EAAE,IAAW;QACjB,IAAI;QACJ,QAAQ;QACR,SAAS;KACV,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,CAAM,EAAE,EAAE,WAAW,EAAE,EAAE,OAAwB;IACvF,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,MAAM,sBAAW,CAAC,GAAG,CAC/C,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,CAAC,CAC5E,CAAA;IAED,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,YAAM,CAAC,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC,CAAA;QAE1E,OAAO,MAAM,CAAA;IACf,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,uBAAuB,CAAC,IAAY,EAAE,OAAwB;IAC3E,MAAM,QAAQ,GAAG,IAAA,qBAAa,EAAE,OAAO,EAAE,KAAa,EAAE,WAAW,EAAE,0BAA0B,IAAI,EAAE,EAAE,GAAG,EAAE,CAC1G,0BAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CACzB,CAAA;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,0BAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,gBAAgB,CAAC,CAAM,EAAE,EAAE,EAAE,EAAE,EAAE,OAAwB;IAC7E,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAEpC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAChF,MAAM,UAAU,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAC1C,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE;KACzC,CAAC,CAAA;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAA;QAC9C,MAAM,uBAAuB,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;QACvD,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAMM,KAAK,UAAU,sBAAsB,CAC1C,CAAM,EACN,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,EAA2B,EACnD,OAAwB;IAExB,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IACpC,MAAM,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAC,CAAC,CAAC,IAAA,qBAAa,EAAC,uBAAU,CAAC,CAAA;IAChF,MAAM,iBAAiB,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE,CAAA;IAC/E,MAAM,iBAAiB,GAAQ,EAAE,KAAK,EAAE,IAAA,YAAE,EAAC,MAAM,CAAC,EAAE,CAAA;IAEpD,4BAA4B;IAC5B,IAAI,OAAO,EAAE,CAAC;QACZ,iBAAiB,CAAC,OAAO,GAAG,OAAO,CAAA;QACnC,iBAAiB,CAAC,OAAO,GAAG,OAAO,CAAA;IACrC,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC;QACxC,KAAK,EAAE,iBAAiB;KACzB,CAAC,CAAA;IAEF,6BAA6B;IAC7B,MAAM,UAAU,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAA;IAE1C,sCAAsC;IACtC,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,uBAAuB,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;QAEnG,OAAO,IAAI,CAAA;IACb,CAAC;SAAM,CAAC;QACN,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACrC,CAAM,EACN,EAAE,IAAI,EAAE,EACR,OAAwB;IAExB,OAAO,MAAM,0BAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;AAC9C,CAAC;AAEM,KAAK,UAAU,YAAY,CAAC,CAAM,EAAE,EAAE,IAAI,EAAE,EAAE,OAAwB;IAC3E,OAAO,MAAM,gBAAgB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AACxE,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,CAAM,EAAE,EAAE,KAAK,EAAE,EAAE,OAAwB;IAC9E,OAAO,MAAM,iBAAiB,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,CAAA;AAC3E,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,YAAwB;IACnD,IAAI,EAAE,gBAAgB,EAAE,GAAG,MAAM,YAAY,CAAA;IAE7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAiB,EAAE,CAAA;QAE/B,gBAAgB,EAAE;aACf,EAAE,CAAC,MAAM,EAAE,CAAC,KAAiB,EAAE,EAAE;YAChC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpB,CAAC,CAAC;aACD,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACd,IAAI,CAAC;gBACH,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBAC5D,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;gBACzC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACnB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,CAAC,KAAK,CAAC,CAAA;YACf,CAAC;QACH,CAAC,CAAC;aACD,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;YAC5B,MAAM,CAAC,KAAK,CAAC,CAAA;QACf,CAAC,CAAC,CAAA;IACN,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe,EAAE,QAAgB,EAAE,QAAgB;IAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACzC,IAAI,YAAY,KAAK,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAA;IAClD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAEhD,OAAO;QACL,QAAQ;QACR,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,QAAQ;QAClB,gBAAgB,EAAE,GAAG,EAAE;YACrB,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;YAChC,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAA;YACtC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACrB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,OAAO,QAAQ,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,MAAkB,EAAE,OAAwB;IAClF,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,KAAK,CAAA;IAElD,MAAM,UAAU,GAAG,EAAE,CAAC,aAAa,CAAC,uBAAU,CAAC,CAAA;IAE/C,MAAM,WAAW,GAAG,EAAE,CAAA;IAEtB,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAE1C,KAAK,MAAM,EAAE,IAAI,MAAM,EAAE,CAAC;QACxB,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAA;QAC9E,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,mCAAmC,CAAA;QAC3C,CAAC;QAED,IAAI,gBAAgB,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;QAEzD,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAI,gBAAgB,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,2BAA2B,EAAE,IAAI,IAAI,sCAAsC,CAAA;YACnF,CAAC;YAED,0BAA0B;YAC1B,SAAQ;QACV,CAAC;QAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;QAE1D,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,MAAM,0BAAO,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;QAE9E,WAAW,CAAC,IAAI,CACd,MAAM,UAAU,CAAC,IAAI,CAAC;YACpB,MAAM;YACN,OAAO,EAAE,IAAI;YACb,OAAO,EAAE,IAAI;YACb,EAAE;YACF,WAAW;YACX,IAAI;YACJ,QAAQ;YACR,QAAQ;YACR,QAAQ,EAAE,QAAQ,IAAI,IAAA,+BAAoB,EAAC,QAAQ,CAAC;YACpD,IAAI,EAAE,IAAW;YACjB,IAAI;YACJ,QAAQ;SACT,CAAC,CACH,CAAA;IACH,CAAC;IAED,MAAM;QACJ,MAAM,CAAC;YACL,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,GAAG,WAAW,CAAC,MAAM,6BAA6B;YACzD,IAAI,EAAE,GAAG,WAAW,CAAC,MAAM,kCAAkC,IAAI,CAAC,IAAI,EAAE;SACzE,CAAC,CAAA;IAEJ,OAAO,WAAW,CAAA;AACpB,CAAC","sourcesContent":["import { FileUpload } from 'graphql-upload/GraphQLUpload.js'\nimport GraphQLUpload from 'graphql-upload/GraphQLUpload.js'\nimport promisesAll from 'promises-all'\n\nimport { Arg, Ctx, Directive, Int, Mutation, Resolver } from 'type-graphql'\nimport { In } from 'typeorm'\n\nimport { config, logger } from '@things-factory/env'\nimport { getRepository, whenCommitted } from '@things-factory/shell'\n\nimport { STORAGE } from '../../attachment-const'\nimport { Attachment } from './attachment'\nimport { AttachmentPatch, NewAttachment, UploadURL } from './attachment-types'\nimport { categoryFromMimetype, normalizeMimetype } from './mimetype'\nimport { generateThumbnail } from './thumbnail'\nimport { backfillAttachmentThumbnails, ThumbnailBackfillResult } from './thumbnail-backfill'\n\nconst allowedMimeTypes = config.get('fileUpload/mimeTypes', [])\n\n@Resolver(Attachment)\nexport class AttachmentMutation {\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async createAttachment(\n @Arg('attachment', type => NewAttachment) attachment: NewAttachment,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n return await createAttachment(null, { attachment }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment])\n async createAttachments(\n @Arg('attachments', type => [NewAttachment]) attachments: NewAttachment[],\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await createAttachments(null, { attachments }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async updateAttachment(\n @Arg('id') id: string,\n @Arg('patch', type => AttachmentPatch) patch: AttachmentPatch,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n const attachment = await getRepository(Attachment).findOne({\n where: {\n domain: { id: context.state.domain.id },\n id\n }\n })\n\n return await getRepository(Attachment).save({\n ...attachment,\n ...patch,\n updater: context.state.user\n })\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean)\n async deleteAttachment(@Arg('id') id: string, @Ctx() context: ResolverContext): Promise<boolean> {\n return await deleteAttachment(null, { id }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Boolean)\n async deleteAttachmentsByRef(\n @Arg('refBys', type => [String]) refBys: string[],\n @Arg('refType', type => String, { nullable: true }) refType: string,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n return await deleteAttachmentsByRef(null, { refBys, refType }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => Attachment)\n async singleUpload(\n @Arg('file', type => GraphQLUpload) file: FileUpload,\n @Ctx() context: ResolverContext\n ): Promise<Attachment> {\n return await singleUpload(null, { file }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment])\n async multipleUpload(\n @Arg('files', type => [GraphQLUpload]) files: FileUpload[],\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await multipleUpload(null, { files }, context)\n }\n\n @Mutation(returns => UploadURL)\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n async generateUploadURL(\n @Arg('type', type => String) type: string,\n @Ctx() context: ResolverContext\n ): Promise<{ url: string; fields: { [key: string]: string } }> {\n return await generateUploadURL(null, { type }, context)\n }\n\n @Directive('@transaction')\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => [Attachment], { description: 'To import some Attachments' })\n async importAttachments(\n @Arg('file', () => GraphQLUpload) file: FileUpload,\n @Ctx() context: ResolverContext\n ): Promise<Attachment[]> {\n return await importAttachments(file, context)\n }\n\n @Directive('@privilege(category: \"attachment\", privilege: \"mutation\", domainOwnerGranted: true)')\n @Mutation(returns => ThumbnailBackfillResult, {\n description:\n '썸네일이 없는 기존 첨부파일들에 대해 서버에서 썸네일을 일괄 생성한다. ' +\n '한 호출당 limit 개까지만 처리하며, remaining > 0 이면 반복 호출 필요.'\n })\n async backfillAttachmentThumbnails(\n @Arg('limit', type => Int, { nullable: true, defaultValue: 20 }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<ThumbnailBackfillResult> {\n return await backfillAttachmentThumbnails({ limit }, context)\n }\n}\n\nexport async function createAttachment(_: any, { attachment }, context: ResolverContext): Promise<Attachment> {\n const { file, category, refType = '', refBy, description } = attachment\n const { mimetype: clientMimetype } = (await file) as FileUpload\n\n const { id, path, size, filename, encoding, contents } = await STORAGE.uploadFile({ file, context })\n const { domain, user, tx } = context.state\n\n // 클라이언트가 보낸 mimetype 은 OS/브라우저 MIME DB 가 확장자를 인식하지\n // 못하면 'application/octet-stream' 으로 fallback 된다 (특히 .glb). 같은 파일이\n // 환경에 따라 다른 mime 으로 저장되면 썸네일/카테고리/검색 등 후속 로직이\n // 일관성을 잃으므로, 모호한 mime 만 magic byte → 확장자 순으로 재판정한다.\n const mimetype = normalizeMimetype(clientMimetype, filename, contents)\n\n // 허용 mime 검증 — 클라이언트 mime 또는 정규화된 mime 둘 중 하나라도 매칭되면\n // 통과. 클라이언트가 정확한 mime ('model/gltf+json' 등) 을 보낸 케이스와\n // 모호한 mime ('application/octet-stream') 으로 보낸 케이스 둘 다 동일 흐름으로\n // 처리되도록 — 이전엔 STORAGE 저장 전에 client mime 으로만 검증해서 정확한\n // mime 을 보낼수록 까다롭게 거절되는 역설이 있었다.\n // 검증을 STORAGE.uploadFile 후로 옮긴 대신, 거절 시 저장된 파일 cleanup.\n if (allowedMimeTypes instanceof Array && allowedMimeTypes.length > 0 && !allowedMimeTypes.includes('*/*')) {\n const matches = (mime: string) => {\n if (!mime) return false\n return allowedMimeTypes.some(type => {\n const [typeMain, typeSub] = type.split('/')\n const [mimeMain, mimeSub] = mime.split('/')\n return (\n (typeMain === mimeMain && (typeSub === '*' || typeSub === mimeSub)) || (typeMain === '*' && typeSub === '*')\n )\n })\n }\n\n if (!matches(clientMimetype) && !matches(mimetype)) {\n try { await STORAGE.deleteFile(path) } catch (e) {\n logger.warn(`[attachment] cleanup after rejected upload failed: ${(e as Error).message}`)\n }\n throw Error(context.t(`error.not allowed file type for upload`, { mimetype: clientMimetype }))\n }\n }\n\n const thumbnail = await generateThumbnail(contents, mimetype)\n\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n\n return await repository.save({\n domain,\n creator: user,\n updater: user,\n id,\n description,\n name: filename,\n mimetype,\n encoding,\n refType,\n refBy,\n category: category || categoryFromMimetype(mimetype),\n size: size as any,\n path,\n contents,\n thumbnail\n })\n}\n\nexport async function createAttachments(_: any, { attachments }, context: ResolverContext): Promise<Attachment[]> {\n const { resolve, reject } = await promisesAll.all(\n attachments.map(attachment => createAttachment(_, { attachment }, context))\n )\n\n if (reject.length) {\n reject.forEach(({ name, message }) => logger.error(`${name}: ${message}`))\n\n return reject\n }\n\n return resolve\n}\n\n/**\n * Removes a file from storage - after the commit, when there is one to wait for.\n *\n * Inside @transaction the row is deleted now and the file waits on context.state.afterCommit: a commit\n * that fails brings the row back, and the file must still be there (ADR-0091 decision 8). Outside a\n * transaction there is nothing to roll back, so the file goes at once, as before. A transaction opened\n * by hand, without runTransaction, has no list either - the file goes at once there too, and a failed\n * commit still loses it.\n */\nasync function deleteFileWhenCommitted(path: string, context: ResolverContext): Promise<void> {\n const deferred = whenCommitted((context?.state as any)?.afterCommit, `delete attachment file ${path}`, () =>\n STORAGE.deleteFile(path)\n )\n\n if (!deferred) {\n await STORAGE.deleteFile(path)\n }\n}\n\nexport async function deleteAttachment(_: any, { id }, context: ResolverContext): Promise<boolean> {\n const { domain, tx } = context.state\n\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n const attachment = await repository.findOne({\n where: { domain: { id: domain.id }, id }\n })\n\n if (attachment) {\n await repository.delete({ id: attachment.id })\n await deleteFileWhenCommitted(attachment.path, context)\n return true\n } else {\n return false\n }\n}\n\ninterface DeleteAttachmentsObject {\n refBys: Array<string>\n refType?: string\n}\nexport async function deleteAttachmentsByRef(\n _: any,\n { refBys, refType = null }: DeleteAttachmentsObject,\n context: ResolverContext\n): Promise<boolean> {\n const { domain, tx } = context.state\n const repository = tx ? tx.getRepository(Attachment) : getRepository(Attachment)\n const inquryWhereClause: any = { domain: { id: domain.id }, refBy: In(refBys) }\n const deleteWhereClause: any = { refBy: In(refBys) }\n\n // refType이 존재하면 where 절에 추가\n if (refType) {\n inquryWhereClause.refType = refType\n deleteWhereClause.refType = refType\n }\n\n const attachments = await repository.find({\n where: inquryWhereClause\n })\n\n //remove attachment from repo\n await repository.delete(deleteWhereClause)\n\n //remove files from attachments folder\n if (attachments.length) {\n await Promise.all(attachments.map(attachment => deleteFileWhenCommitted(attachment.path, context)))\n\n return true\n } else {\n return false\n }\n}\n\nexport async function generateUploadURL(\n _: any,\n { type },\n context: ResolverContext\n): Promise<{ url: string; fields: { [key: string]: string } }> {\n return await STORAGE.generateUploadURL(type)\n}\n\nexport async function singleUpload(_: any, { file }, context: ResolverContext): Promise<Attachment> {\n return await createAttachment(null, { attachment: { file } }, context)\n}\n\nexport async function multipleUpload(_: any, { files }, context: ResolverContext): Promise<Attachment[]> {\n return await createAttachments(null, { attachments: { files } }, context)\n}\n\nasync function parseJSONFile(uploadedFile: FileUpload): Promise<any> {\n var { createReadStream } = await uploadedFile\n\n return new Promise((resolve, reject) => {\n const chunks: Uint8Array[] = []\n\n createReadStream()\n .on('data', (chunk: Uint8Array) => {\n chunks.push(chunk)\n })\n .on('end', () => {\n try {\n const fileContents = Buffer.concat(chunks).toString('utf-8')\n const jsonData = JSON.parse(fileContents)\n resolve(jsonData)\n } catch (error) {\n reject(error)\n }\n })\n .on('error', (error: Error) => {\n reject(error)\n })\n })\n}\n\nfunction dataURLToFileUpload(dataURL: string, filename: string, mimeType: string): FileUpload {\n const indexOfComma = dataURL.indexOf(',')\n if (indexOfComma === -1) {\n throw new Error('Invalid Data URL')\n }\n\n const base64Data = dataURL.slice(indexOfComma + 1)\n const buffer = Buffer.from(base64Data, 'base64')\n\n return {\n filename,\n mimetype: mimeType,\n encoding: 'base64',\n createReadStream: () => {\n const stream = require('stream')\n const readable = new stream.Readable()\n readable.push(buffer)\n readable.push(null)\n return readable\n }\n }\n}\n\nexport async function importAttachments(upload: FileUpload, context: ResolverContext): Promise<Attachment[]> {\n const { domain, user, notify, tx } = context.state\n\n const repository = tx.getRepository(Attachment)\n\n const attachments = []\n\n const parsed = await parseJSONFile(upload)\n\n for (const id in parsed) {\n var { name, description, category, mimetype, encoding, contents } = parsed[id]\n if (!name || !contents || !mimetype) {\n throw 'Malformed attachments import file'\n }\n\n var sameIdAttachment = await repository.findOneBy({ id })\n\n if (sameIdAttachment) {\n if (sameIdAttachment.domainId != domain.id) {\n throw `Attachment with id/name(${id}/${name}) is already taken in another domain`\n }\n\n // 동일 아이디 첨부파일이 있다면, 스킵한다.\n continue\n }\n\n const file = dataURLToFileUpload(contents, name, mimetype)\n\n var { path, size, contents } = await STORAGE.uploadFile({ id, file, context })\n\n attachments.push(\n await repository.save({\n domain,\n creator: user,\n updater: user,\n id,\n description,\n name,\n mimetype,\n encoding,\n category: category || categoryFromMimetype(mimetype),\n size: size as any,\n path,\n contents\n })\n )\n }\n\n notify &&\n notify({\n mode: 'in-app',\n title: `${attachments.length} Attachment(s) are imported`,\n body: `${attachments.length} Attachment(s) are imported by ${user.name}`\n })\n\n return attachments\n}\n"]}