@dcl/content-validator 1.0.0-20220104134007.commit-80072ed

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.
Files changed (84) hide show
  1. package/README.md +29 -0
  2. package/dist/content-validator.api.json +1177 -0
  3. package/dist/index.d.ts +8 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +32 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/tsdoc-metadata.json +11 -0
  8. package/dist/types.d.ts +114 -0
  9. package/dist/types.d.ts.map +1 -0
  10. package/dist/types.js +36 -0
  11. package/dist/types.js.map +1 -0
  12. package/dist/validations/access-checker/access.d.ts +7 -0
  13. package/dist/validations/access-checker/access.d.ts.map +1 -0
  14. package/dist/validations/access-checker/access.js +28 -0
  15. package/dist/validations/access-checker/access.js.map +1 -0
  16. package/dist/validations/access-checker/profiles.d.ts +7 -0
  17. package/dist/validations/access-checker/profiles.d.ts.map +1 -0
  18. package/dist/validations/access-checker/profiles.js +30 -0
  19. package/dist/validations/access-checker/profiles.js.map +1 -0
  20. package/dist/validations/access-checker/scenes.d.ts +7 -0
  21. package/dist/validations/access-checker/scenes.d.ts.map +1 -0
  22. package/dist/validations/access-checker/scenes.js +246 -0
  23. package/dist/validations/access-checker/scenes.js.map +1 -0
  24. package/dist/validations/access-checker/wearables.d.ts +20 -0
  25. package/dist/validations/access-checker/wearables.d.ts.map +1 -0
  26. package/dist/validations/access-checker/wearables.js +247 -0
  27. package/dist/validations/access-checker/wearables.js.map +1 -0
  28. package/dist/validations/content.d.ts +7 -0
  29. package/dist/validations/content.d.ts.map +1 -0
  30. package/dist/validations/content.js +48 -0
  31. package/dist/validations/content.js.map +1 -0
  32. package/dist/validations/decentraland-address.d.ts +6 -0
  33. package/dist/validations/decentraland-address.d.ts.map +1 -0
  34. package/dist/validations/decentraland-address.js +19 -0
  35. package/dist/validations/decentraland-address.js.map +1 -0
  36. package/dist/validations/entity-structure.d.ts +7 -0
  37. package/dist/validations/entity-structure.d.ts.map +1 -0
  38. package/dist/validations/entity-structure.js +21 -0
  39. package/dist/validations/entity-structure.js.map +1 -0
  40. package/dist/validations/index.d.ts +22 -0
  41. package/dist/validations/index.d.ts.map +1 -0
  42. package/dist/validations/index.js +76 -0
  43. package/dist/validations/index.js.map +1 -0
  44. package/dist/validations/ipfs-hashing.d.ts +7 -0
  45. package/dist/validations/ipfs-hashing.d.ts.map +1 -0
  46. package/dist/validations/ipfs-hashing.js +25 -0
  47. package/dist/validations/ipfs-hashing.js.map +1 -0
  48. package/dist/validations/metadata-schema.d.ts +6 -0
  49. package/dist/validations/metadata-schema.d.ts.map +1 -0
  50. package/dist/validations/metadata-schema.js +26 -0
  51. package/dist/validations/metadata-schema.js.map +1 -0
  52. package/dist/validations/must-have-failed-before.d.ts +6 -0
  53. package/dist/validations/must-have-failed-before.d.ts.map +1 -0
  54. package/dist/validations/must-have-failed-before.js +13 -0
  55. package/dist/validations/must-have-failed-before.js.map +1 -0
  56. package/dist/validations/no-newer.d.ts +6 -0
  57. package/dist/validations/no-newer.d.ts.map +1 -0
  58. package/dist/validations/no-newer.js +14 -0
  59. package/dist/validations/no-newer.js.map +1 -0
  60. package/dist/validations/no-redeploy.d.ts +6 -0
  61. package/dist/validations/no-redeploy.d.ts.map +1 -0
  62. package/dist/validations/no-redeploy.js +13 -0
  63. package/dist/validations/no-redeploy.js.map +1 -0
  64. package/dist/validations/rate-limit.d.ts +6 -0
  65. package/dist/validations/rate-limit.d.ts.map +1 -0
  66. package/dist/validations/rate-limit.js +13 -0
  67. package/dist/validations/rate-limit.js.map +1 -0
  68. package/dist/validations/recent.d.ts +7 -0
  69. package/dist/validations/recent.d.ts.map +1 -0
  70. package/dist/validations/recent.js +27 -0
  71. package/dist/validations/recent.js.map +1 -0
  72. package/dist/validations/signature.d.ts +7 -0
  73. package/dist/validations/signature.d.ts.map +1 -0
  74. package/dist/validations/signature.js +17 -0
  75. package/dist/validations/signature.js.map +1 -0
  76. package/dist/validations/size.d.ts +8 -0
  77. package/dist/validations/size.d.ts.map +1 -0
  78. package/dist/validations/size.js +39 -0
  79. package/dist/validations/size.js.map +1 -0
  80. package/dist/validations/wearable.d.ts +10 -0
  81. package/dist/validations/wearable.d.ts.map +1 -0
  82. package/dist/validations/wearable.js +76 -0
  83. package/dist/validations/wearable.js.map +1 -0
  84. package/package.json +47 -0
@@ -0,0 +1,247 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.wearables = void 0;
7
+ const urn_resolver_1 = require("@dcl/urn-resolver");
8
+ const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
9
+ const ms_1 = __importDefault(require("ms"));
10
+ const __1 = require("../..");
11
+ const types_1 = require("../../types");
12
+ const L1_NETWORKS = ['mainnet', 'ropsten', 'kovan', 'rinkeby', 'goerli'];
13
+ const L2_NETWORKS = ['matic', 'mumbai'];
14
+ // When we want to find a block for a specific timestamp, we define an access window. This means that
15
+ // we will place will try to find the closes block to the timestamp, but only if it's within the window
16
+ const ACCESS_WINDOW_IN_SECONDS = (0, ms_1.default)('15s') / 1000;
17
+ const alreadySeen = (resolvedPointers, parsed) => {
18
+ return resolvedPointers.some((alreadyResolved) => resolveSameUrn(alreadyResolved, parsed));
19
+ };
20
+ const resolveSameUrn = (alreadyParsed, parsed) => {
21
+ const alreadyParsedCopy = Object.assign({}, alreadyParsed);
22
+ const parsedCopy = Object.assign({}, parsed);
23
+ alreadyParsedCopy.uri = new URL('urn:same');
24
+ parsedCopy.uri = new URL('urn:same');
25
+ return JSON.stringify(alreadyParsedCopy) == JSON.stringify(parsedCopy);
26
+ };
27
+ const parseUrnNoFail = async (urn) => {
28
+ try {
29
+ const parsed = await (0, urn_resolver_1.parseUrn)(urn);
30
+ if (parsed?.type === 'blockchain-collection-v1-asset') {
31
+ return parsed;
32
+ }
33
+ if (parsed?.type === 'blockchain-collection-v2-asset') {
34
+ return parsed;
35
+ }
36
+ if (parsed?.type === 'off-chain') {
37
+ return parsed;
38
+ }
39
+ }
40
+ catch { }
41
+ return null;
42
+ };
43
+ const hasPermission = async (subgraphUrl, collection, itemId, block, entity, externalCalls) => {
44
+ try {
45
+ const { content, metadata } = entity;
46
+ const permissions = await getCollectionItems(subgraphUrl, collection, itemId, block, externalCalls);
47
+ const ethAddressLowercase = entity.ethAddress.toLowerCase();
48
+ if (!!permissions.contentHash) {
49
+ const deployedByCommittee = permissions.committee.includes(ethAddressLowercase);
50
+ const calculateHashes = () => {
51
+ // Compare both by key and hash
52
+ const compare = (a, b) => {
53
+ if (a.hash > b.hash)
54
+ return 1;
55
+ else if (a.hash < b.hash)
56
+ return -1;
57
+ else
58
+ return a.key > b.key ? 1 : -1;
59
+ };
60
+ const contentAsJson = (content ?? []).map(({ file, hash }) => ({ key: file, hash })).sort(compare);
61
+ const buffer = Buffer.from(JSON.stringify({ content: contentAsJson, metadata }));
62
+ return Promise.all([dcl_catalyst_commons_1.Hashing.calculateBufferHash(buffer), dcl_catalyst_commons_1.Hashing.calculateIPFSHash(buffer)]);
63
+ };
64
+ return deployedByCommittee && (await calculateHashes()).includes(permissions.contentHash);
65
+ }
66
+ else {
67
+ const addressHasAccess = (permissions.collectionCreator && permissions.collectionCreator === ethAddressLowercase) ||
68
+ (permissions.collectionManagers && permissions.collectionManagers.includes(ethAddressLowercase)) ||
69
+ (permissions.itemManagers && permissions.itemManagers.includes(ethAddressLowercase));
70
+ // Deployments to the content server are made after the collection is completed, so that the committee can then approve it.
71
+ // That's why isCompleted must be true, but isApproved must be false. After the committee approves the wearable, there can't be any more changes
72
+ const isCollectionValid = !permissions.isApproved && permissions.isCompleted;
73
+ return addressHasAccess && isCollectionValid;
74
+ }
75
+ }
76
+ catch (error) {
77
+ // this.LOGGER.error(`Error checking permission for (${collection}-${itemId}) at block ${block}`, error)
78
+ return false;
79
+ }
80
+ };
81
+ const getCollectionItems = async (subgraphUrl, collection, itemId, block, externalCalls) => {
82
+ const query = `
83
+ query getCollectionRoles($collection: String!, $itemId: String!, $block: Int!) {
84
+ collections(where:{ id: $collection }, block: { number: $block }) {
85
+ creator
86
+ managers
87
+ isApproved
88
+ isCompleted
89
+ items(where:{ id: $itemId }) {
90
+ managers
91
+ contentHash
92
+ }
93
+ }
94
+
95
+ accounts(where:{ isCommitteeMember: true }, block: { number: $block }) {
96
+ id
97
+ }
98
+ }`;
99
+ const result = await externalCalls.queryGraph(subgraphUrl, query, {
100
+ collection,
101
+ itemId: `${collection}-${itemId}`,
102
+ block,
103
+ });
104
+ const collectionResult = result.collections[0];
105
+ const itemResult = collectionResult?.items[0];
106
+ return {
107
+ collectionCreator: collectionResult?.creator,
108
+ collectionManagers: collectionResult?.managers,
109
+ isApproved: collectionResult?.isApproved,
110
+ isCompleted: collectionResult?.isCompleted,
111
+ itemManagers: itemResult?.managers,
112
+ contentHash: itemResult?.contentHash,
113
+ committee: result.accounts.map(({ id }) => id.toLowerCase()),
114
+ };
115
+ };
116
+ const getWindowFromTimestamp = (timestamp) => {
117
+ const windowMin = timestamp - Math.floor(ACCESS_WINDOW_IN_SECONDS / 2);
118
+ const windowMax = timestamp + Math.ceil(ACCESS_WINDOW_IN_SECONDS / 2);
119
+ return {
120
+ max: windowMax,
121
+ min: windowMin,
122
+ };
123
+ };
124
+ const findBlocksForTimestamp = async (blocksSubgraphUrl, timestamp, externalCalls) => {
125
+ const query = `
126
+ query getBlockForTimestamp($timestamp: Int!, $timestampMin: Int!, $timestampMax: Int!, $timestamp5Min: Int!, $timestamp5MinMax: Int!, $timestamp5MinMin: Int!) {
127
+ before: blocks(where: { timestamp_lte: $timestamp, timestamp_gte: $timestampMin }, first: 1, orderBy: timestamp, orderDirection: desc) {
128
+ number
129
+ }
130
+ after: blocks(where: { timestamp_gte: $timestamp, timestamp_lte: $timestampMax }, first: 1, orderBy: timestamp, orderDirection: asc) {
131
+ number
132
+ }
133
+ fiveMinBefore: blocks(where: { timestamp_lte: $timestamp5Min, timestamp_gte: $timestamp5MinMin, }, first: 1, orderBy: timestamp, orderDirection: desc) {
134
+ number
135
+ }
136
+ fiveMinAfter: blocks(where: { timestamp_gte: $timestamp5Min, timestamp_lte: $timestamp5MinMax }, first: 1, orderBy: timestamp, orderDirection: asc) {
137
+ number
138
+ }
139
+ }
140
+ `;
141
+ try {
142
+ const timestampSec = Math.ceil(timestamp / 1000);
143
+ const timestamp5MinAgo = timestampSec - 60 * 5;
144
+ const window = getWindowFromTimestamp(timestampSec);
145
+ const window5MinAgo = getWindowFromTimestamp(timestamp5MinAgo);
146
+ const result = await externalCalls.queryGraph(blocksSubgraphUrl, query, {
147
+ timestamp: timestampSec,
148
+ timestampMax: window.max,
149
+ timestampMin: window.min,
150
+ timestamp5Min: timestamp5MinAgo,
151
+ timestamp5MinMax: window5MinAgo.max,
152
+ timestamp5MinMin: window5MinAgo.min,
153
+ });
154
+ // To get the deployment's block number, we check the one immediately after the entity's timestamp. Since it could not exist, we default to the one immediately before.
155
+ const blockNumberAtDeployment = result.after[0]?.number ?? result.before[0]?.number;
156
+ const blockNumberFiveMinBeforeDeployment = result.fiveMinAfter[0]?.number ?? result.fiveMinBefore[0]?.number;
157
+ if (blockNumberAtDeployment === undefined && blockNumberFiveMinBeforeDeployment === undefined) {
158
+ throw new Error(`Failed to find blocks for the specific timestamp`);
159
+ }
160
+ return {
161
+ blockNumberAtDeployment: !!blockNumberAtDeployment ? parseInt(blockNumberAtDeployment) : undefined,
162
+ blockNumberFiveMinBeforeDeployment: !!blockNumberFiveMinBeforeDeployment
163
+ ? parseInt(blockNumberFiveMinBeforeDeployment)
164
+ : undefined,
165
+ };
166
+ }
167
+ catch (error) {
168
+ // this.LOGGER.error(`Error fetching the block number for timestamp`, { timestamp, error: error.message })
169
+ throw error;
170
+ }
171
+ };
172
+ const checkCollectionAccess = async (blocksSubgraphUrl, collectionsSubgraphUrl, collection, itemId, entity, externalCalls) => {
173
+ const { timestamp } = entity;
174
+ try {
175
+ const { blockNumberAtDeployment, blockNumberFiveMinBeforeDeployment } = await findBlocksForTimestamp(blocksSubgraphUrl, timestamp, externalCalls);
176
+ // It could happen that the subgraph hasn't synced yet, so someone who just lost access still managed to make a deployment. The problem would be that when other catalysts perform
177
+ // the same check, the subgraph might have synced and the deployment is no longer valid. So, in order to prevent inconsistencies between catalysts, we will allow all deployments that
178
+ // have access now, or had access 5 minutes ago.
179
+ const hasPermissionOnBlock = async (blockNumber) => !!blockNumber &&
180
+ (await hasPermission(collectionsSubgraphUrl, collection, itemId, blockNumber, entity, externalCalls));
181
+ return ((await hasPermissionOnBlock(blockNumberAtDeployment)) ||
182
+ (await hasPermissionOnBlock(blockNumberFiveMinBeforeDeployment)));
183
+ }
184
+ catch (error) {
185
+ // this.LOGGER.error(
186
+ // `Error checking wearable access (${collection}, ${itemId}, ${accessParams.ethAddress}, ${timestamp}, ${blocksSubgraphUrl}).`,
187
+ // error
188
+ // )
189
+ return false;
190
+ }
191
+ };
192
+ /**
193
+ * Given the pointers (URNs), determine which layer should be used to check the access.
194
+ * Checks if the ethereum address has access to the collection.
195
+ * @public
196
+ */
197
+ exports.wearables = {
198
+ validate: async ({ deployment, externalCalls }) => {
199
+ const { pointers } = deployment.entity;
200
+ const ethAddress = externalCalls.ownerAddress(deployment.auditInfo);
201
+ const resolvedPointers = [];
202
+ // deduplicate pointer resolution
203
+ for (const pointer of pointers) {
204
+ const parsed = await parseUrnNoFail(pointer);
205
+ if (!parsed)
206
+ return (0, __1.validationFailed)(`Wearable pointers should be a urn, for example (urn:decentraland:{protocol}:collections-v2:{contract(0x[a-fA-F0-9]+)}:{name}). Invalid pointer: (${pointer})`);
207
+ if (!alreadySeen(resolvedPointers, parsed))
208
+ resolvedPointers.push(parsed);
209
+ }
210
+ if (resolvedPointers.length > 1)
211
+ return (0, __1.validationFailed)(`Only one pointer is allowed when you create a Wearable. Received: ${pointers}`);
212
+ const parsed = resolvedPointers[0];
213
+ if (!['off-chain', 'blockchain-collection-v1-asset', 'blockchain-collection-v2-asset'].includes(parsed.type))
214
+ return (0, __1.validationFailed)(`Could not resolve the contractAddress of the urn ${parsed}`);
215
+ if (parsed.type === 'off-chain') {
216
+ // Validate Off Chain Asset
217
+ if (!externalCalls.isAddressOwnedByDecentraland(ethAddress))
218
+ return (0, __1.validationFailed)(`The provided Eth Address '${ethAddress}' does not have access to the following wearable: '${parsed.uri}'`);
219
+ }
220
+ else if (parsed?.type === 'blockchain-collection-v1-asset' || parsed?.type === 'blockchain-collection-v2-asset') {
221
+ // L1 or L2 so contractAddress is present
222
+ const collection = parsed.contractAddress;
223
+ const network = parsed.network;
224
+ const isL1 = L1_NETWORKS.includes(network);
225
+ const isL2 = L2_NETWORKS.includes(network);
226
+ if (!isL1 && !isL2)
227
+ return (0, __1.validationFailed)(`Found an unknown network on the urn '${network}'`);
228
+ const blocksSubgraphUrl = isL1 ? externalCalls.subgraphs.L1.blocks : externalCalls.subgraphs.L2.blocks;
229
+ const collectionsSubgraphUrl = isL1
230
+ ? externalCalls.subgraphs.L1.collections
231
+ : externalCalls.subgraphs.L2.collections;
232
+ const hasAccess = await checkCollectionAccess(blocksSubgraphUrl, collectionsSubgraphUrl, collection, parsed.id, { ...deployment.entity, ethAddress }, externalCalls);
233
+ if (!hasAccess) {
234
+ if (isL2)
235
+ return (0, __1.validationFailed)(`The provided Eth Address does not have access to the following wearable: (${parsed.contractAddress}, ${parsed.id})`);
236
+ // Some L1 collections are deployed by Decentraland Address
237
+ // Maybe this is not necessary as we already know that it's a 'blockchain-collection-v1-asset'
238
+ const isAllowlistedCollection = parsed.uri.toString().startsWith('urn:decentraland:ethereum:collections-v1');
239
+ if (!externalCalls.isAddressOwnedByDecentraland(ethAddress) || !isAllowlistedCollection) {
240
+ return (0, __1.validationFailed)(`The provided Eth Address '${ethAddress}' does not have access to the following wearable: '${parsed.uri}'`);
241
+ }
242
+ }
243
+ }
244
+ return types_1.OK;
245
+ },
246
+ };
247
+ //# sourceMappingURL=wearables.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wearables.js","sourceRoot":"","sources":["../../../src/validations/access-checker/wearables.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { Validation } from '../types';
2
+ /**
3
+ * Validate that uploaded and reported hashes are corrects and files corresponds to snapshots
4
+ * @public
5
+ */
6
+ export declare const content: Validation;
7
+ //# sourceMappingURL=content.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/validations/content.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAA;AAUjD;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,UAqCrB,CAAA"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.content = void 0;
4
+ const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
5
+ const _1 = require(".");
6
+ const types_1 = require("../types");
7
+ const correspondsToASnapshot = (fileName, hash, metadata) => {
8
+ const fileNameWithoutExtension = fileName.replace(/.[^/.]+$/, '');
9
+ return metadata.avatars.some((avatar) => Object.entries(avatar.avatar.snapshots).some((key) => key[0] === fileNameWithoutExtension && key[1] === hash));
10
+ };
11
+ /**
12
+ * Validate that uploaded and reported hashes are corrects and files corresponds to snapshots
13
+ * @public
14
+ */
15
+ exports.content = {
16
+ validate: async ({ deployment, externalCalls }) => {
17
+ const { entity, files } = deployment;
18
+ const errors = [];
19
+ if (entity.content) {
20
+ const alreadyStoredHashes = await externalCalls.isContentStoredAlready(Array.from(files.keys()));
21
+ for (const { hash } of entity.content) {
22
+ // Validate that all hashes in entity were uploaded, or were already stored on the service
23
+ if (!(files.has(hash) || alreadyStoredHashes.get(hash))) {
24
+ errors.push(`This hash is referenced in the entity but was not uploaded or previously available: ${hash}`);
25
+ }
26
+ }
27
+ }
28
+ // Validate that all hashes that belong to uploaded files are actually reported on the entity
29
+ const entityHashes = new Set(entity.content?.map(({ hash }) => hash) ?? []);
30
+ for (const [hash] of files) {
31
+ if (!entityHashes.has(hash) && hash !== entity.id) {
32
+ errors.push(`This hash was uploaded but is not referenced in the entity: ${hash}`);
33
+ }
34
+ }
35
+ if (entity.timestamp > _1.ADR_X_TIMESTAMP) {
36
+ for (const { file, hash } of entity.content ?? []) {
37
+ // Validate all content files correspond to at least one avatar snapshot
38
+ if (entity.type === dcl_catalyst_commons_1.EntityType.PROFILE) {
39
+ if (!correspondsToASnapshot(file, hash, entity.metadata)) {
40
+ errors.push(`This file is not expected: '${file}' or its hash is invalid: '${hash}'. Please, include only valid snapshot files.`);
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return (0, types_1.fromErrors)(...errors);
46
+ },
47
+ };
48
+ //# sourceMappingURL=content.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/validations/content.ts"],"names":[],"mappings":";;;AACA,+DAAiD;AACjD,wBAAmC;AACnC,oCAAiD;AAEjD,MAAM,sBAAsB,GAAG,CAAC,QAAgB,EAAE,IAAY,EAAE,QAAiB,EAAE,EAAE;IACnF,MAAM,wBAAwB,GAAG,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAEjE,OAAO,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAc,EAAE,EAAE,CAC9C,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,wBAAwB,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAC9G,CAAA;AACH,CAAC,CAAA;AAED;;;GAGG;AACU,QAAA,OAAO,GAAe;IACjC,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QAChD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,CAAA;QACpC,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,IAAI,MAAM,CAAC,OAAO,EAAE;YAClB,MAAM,mBAAmB,GAAG,MAAM,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YAEhG,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,EAAE;gBACrC,0FAA0F;gBAC1F,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE;oBACvD,MAAM,CAAC,IAAI,CAAC,uFAAuF,IAAI,EAAE,CAAC,CAAA;iBAC3G;aACF;SACF;QAED,6FAA6F;QAC7F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC3E,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,KAAK,EAAE;YAC1B,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,MAAM,CAAC,EAAE,EAAE;gBACjD,MAAM,CAAC,IAAI,CAAC,+DAA+D,IAAI,EAAE,CAAC,CAAA;aACnF;SACF;QAED,IAAI,MAAM,CAAC,SAAS,GAAG,kBAAe,EAAE;YACtC,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE;gBACjD,wEAAwE;gBACxE,IAAI,MAAM,CAAC,IAAI,KAAK,iCAAU,CAAC,OAAO,EAAE;oBACtC,IAAI,CAAC,sBAAsB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE;wBACxD,MAAM,CAAC,IAAI,CACT,+BAA+B,IAAI,8BAA8B,IAAI,+CAA+C,CACrH,CAAA;qBACF;iBACF;aACF;SACF;QACD,OAAO,IAAA,kBAAU,EAAC,GAAG,MAAM,CAAC,CAAA;IAC9B,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Validate that the address used was owned by Decentraland
3
+ * @public
4
+ */
5
+ export declare const decentralandAddress: import("../types").Validation;
6
+ //# sourceMappingURL=decentraland-address.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decentraland-address.d.ts","sourceRoot":"","sources":["../../src/validations/decentraland-address.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,mBAAmB,+BAS9B,CAAA"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.decentralandAddress = void 0;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Validate that the address used was owned by Decentraland
7
+ * @public
8
+ */
9
+ exports.decentralandAddress = (0, types_1.conditionalValidation)({
10
+ predicate: ({ deployment, externalCalls }) => {
11
+ const address = externalCalls.ownerAddress(deployment.auditInfo);
12
+ return externalCalls.isAddressOwnedByDecentraland(address);
13
+ },
14
+ message: ({ deployment, externalCalls }) => {
15
+ const address = externalCalls.ownerAddress(deployment.auditInfo);
16
+ return `Expected an address owned by decentraland. Instead, we found ${address}`;
17
+ },
18
+ });
19
+ //# sourceMappingURL=decentraland-address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decentraland-address.js","sourceRoot":"","sources":["../../src/validations/decentraland-address.ts"],"names":[],"mappings":";;;AAAA,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,mBAAmB,GAAG,IAAA,6BAAqB,EAAC;IACvD,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QAC3C,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAChE,OAAO,aAAa,CAAC,4BAA4B,CAAC,OAAO,CAAC,CAAA;IAC5D,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE;QACzC,MAAM,OAAO,GAAG,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,CAAC,CAAA;QAChE,OAAO,gEAAgE,OAAO,EAAE,CAAA;IAClF,CAAC;CACF,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { Validation } from '../types';
2
+ /**
3
+ * Validate that entity is actually ok
4
+ * @public
5
+ */
6
+ export declare const entityStructure: Validation;
7
+ //# sourceMappingURL=entity-structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-structure.d.ts","sourceRoot":"","sources":["../../src/validations/entity-structure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,UAAU,EAAoB,MAAM,UAAU,CAAA;AAE3D;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,UAU7B,CAAA"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.entityStructure = void 0;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Validate that entity is actually ok
7
+ * @public
8
+ */
9
+ exports.entityStructure = {
10
+ validate: async ({ deployment }) => {
11
+ const { entity } = deployment;
12
+ if (new Set(entity.pointers).size != entity.pointers.length) {
13
+ return (0, types_1.validationFailed)('There are repeated pointers in your request.');
14
+ }
15
+ else if (!entity.pointers || entity.pointers.length <= 0) {
16
+ return (0, types_1.validationFailed)('The entity needs to be pointed by one or more pointers.');
17
+ }
18
+ return types_1.OK;
19
+ },
20
+ };
21
+ //# sourceMappingURL=entity-structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-structure.js","sourceRoot":"","sources":["../../src/validations/entity-structure.ts"],"names":[],"mappings":";;;AAAA,oCAA2D;AAE3D;;;GAGG;AACU,QAAA,eAAe,GAAe;IACzC,QAAQ,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE;QACjC,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;QAC7B,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE;YAC3D,OAAO,IAAA,wBAAgB,EAAC,8CAA8C,CAAC,CAAA;SACxE;aAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,CAAC,EAAE;YAC1D,OAAO,IAAA,wBAAgB,EAAC,yDAAyD,CAAC,CAAA;SACnF;QACD,OAAO,UAAE,CAAA;IACX,CAAC;CACF,CAAA"}
@@ -0,0 +1,22 @@
1
+ import { DeploymentToValidate, ExternalCalls, Validation, ValidationArgs, ValidationResponse } from '../types';
2
+ /**
3
+ * @public
4
+ */
5
+ export declare const validateInRow: (validationArgs: ValidationArgs, ...validations: Validation[]) => Promise<ValidationResponse>;
6
+ /**
7
+ * @public
8
+ */
9
+ export declare const ADR_X_TIMESTAMP = 1648954800000;
10
+ /**
11
+ * @public
12
+ */
13
+ export declare const calculateDeploymentSize: (deployment: DeploymentToValidate, externalCalls: ExternalCalls) => Promise<number | string>;
14
+ /**
15
+ * @public
16
+ */
17
+ export declare const statefulValidations: Validation[];
18
+ /**
19
+ * @public
20
+ */
21
+ export declare const statelessValidations: Validation[];
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/validations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAM,UAAU,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAgBlH;;GAEG;AACH,eAAO,MAAM,aAAa,mBACR,cAAc,kBACd,UAAU,EAAE,KAC3B,QAAQ,kBAAkB,CAM5B,CAAA;AAGD;;GAEG;AACH,eAAO,MAAM,eAAe,gBAAgB,CAAA;AAE5C;;GAEG;AACH,eAAO,MAAM,uBAAuB,eACtB,oBAAoB,iBACjB,aAAa,KAC3B,QAAQ,MAAM,GAAG,MAAM,CAazB,CAAA;AAED;;GAEG;AACH,eAAO,MAAM,mBAAmB,cAY/B,CAAA;AACD;;GAEG;AACH,eAAO,MAAM,oBAAoB,cAA2C,CAAA"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.statelessValidations = exports.statefulValidations = exports.calculateDeploymentSize = exports.ADR_X_TIMESTAMP = exports.validateInRow = void 0;
4
+ const types_1 = require("../types");
5
+ const access_1 = require("./access-checker/access");
6
+ const content_1 = require("./content");
7
+ const decentraland_address_1 = require("./decentraland-address");
8
+ const entity_structure_1 = require("./entity-structure");
9
+ const ipfs_hashing_1 = require("./ipfs-hashing");
10
+ const metadata_schema_1 = require("./metadata-schema");
11
+ const must_have_failed_before_1 = require("./must-have-failed-before");
12
+ const no_newer_1 = require("./no-newer");
13
+ const no_redeploy_1 = require("./no-redeploy");
14
+ const rate_limit_1 = require("./rate-limit");
15
+ const recent_1 = require("./recent");
16
+ const signature_1 = require("./signature");
17
+ const size_1 = require("./size");
18
+ const wearable_1 = require("./wearable");
19
+ /**
20
+ * @public
21
+ */
22
+ const validateInRow = async (validationArgs, ...validations) => {
23
+ for (const validation of validations) {
24
+ const response = await validation.validate(validationArgs);
25
+ if (!response.ok)
26
+ return response;
27
+ }
28
+ return types_1.OK;
29
+ };
30
+ exports.validateInRow = validateInRow;
31
+ // todo: review/define date for entities v4 (for the time being, it is set for test purposes)
32
+ /**
33
+ * @public
34
+ */
35
+ exports.ADR_X_TIMESTAMP = 1648954800000;
36
+ /**
37
+ * @public
38
+ */
39
+ const calculateDeploymentSize = async (deployment, externalCalls) => {
40
+ let totalSize = 0;
41
+ for (const hash of new Set(deployment.entity.content?.map((item) => item.hash) ?? [])) {
42
+ const uploadedFile = deployment.files.get(hash);
43
+ if (uploadedFile) {
44
+ totalSize += uploadedFile.byteLength;
45
+ }
46
+ else {
47
+ const contentSize = await externalCalls.fetchContentFileSize(hash);
48
+ if (!contentSize)
49
+ return `Couldn't fetch content file with hash: ${hash}`;
50
+ totalSize += contentSize;
51
+ }
52
+ }
53
+ return totalSize;
54
+ };
55
+ exports.calculateDeploymentSize = calculateDeploymentSize;
56
+ /**
57
+ * @public
58
+ */
59
+ exports.statefulValidations = [
60
+ no_redeploy_1.noRedeploy,
61
+ signature_1.signature,
62
+ recent_1.recent,
63
+ no_newer_1.noNewer,
64
+ access_1.access,
65
+ size_1.size,
66
+ must_have_failed_before_1.mustHaveFailedBefore,
67
+ wearable_1.wearable,
68
+ content_1.content,
69
+ decentraland_address_1.decentralandAddress,
70
+ rate_limit_1.rateLimit,
71
+ ];
72
+ /**
73
+ * @public
74
+ */
75
+ exports.statelessValidations = [entity_structure_1.entityStructure, ipfs_hashing_1.ipfsHashing, metadata_schema_1.metadata];
76
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/validations/index.ts"],"names":[],"mappings":";;;AAAA,oCAAkH;AAClH,oDAAgD;AAChD,uCAAmC;AACnC,iEAA4D;AAC5D,yDAAoD;AACpD,iDAA4C;AAC5C,uDAA4C;AAC5C,uEAAgE;AAChE,yCAAoC;AACpC,+CAA0C;AAC1C,6CAAwC;AACxC,qCAAiC;AACjC,2CAAuC;AACvC,iCAA6B;AAC7B,yCAAqC;AAErC;;GAEG;AACI,MAAM,aAAa,GAAG,KAAK,EAChC,cAA8B,EAC9B,GAAG,WAAyB,EACC,EAAE;IAC/B,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE;QACpC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAA;QAC1D,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,QAAQ,CAAA;KAClC;IACD,OAAO,UAAE,CAAA;AACX,CAAC,CAAA;AATY,QAAA,aAAa,iBASzB;AAED,6FAA6F;AAC7F;;GAEG;AACU,QAAA,eAAe,GAAG,aAAa,CAAA;AAE5C;;GAEG;AACI,MAAM,uBAAuB,GAAG,KAAK,EAC1C,UAAgC,EAChC,aAA4B,EACF,EAAE;IAC5B,IAAI,SAAS,GAAG,CAAC,CAAA;IACjB,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE;QACrF,MAAM,YAAY,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC/C,IAAI,YAAY,EAAE;YAChB,SAAS,IAAI,YAAY,CAAC,UAAU,CAAA;SACrC;aAAM;YACL,MAAM,WAAW,GAAG,MAAM,aAAa,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAA;YAClE,IAAI,CAAC,WAAW;gBAAE,OAAO,0CAA0C,IAAI,EAAE,CAAA;YACzE,SAAS,IAAI,WAAW,CAAA;SACzB;KACF;IACD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAhBY,QAAA,uBAAuB,2BAgBnC;AAED;;GAEG;AACU,QAAA,mBAAmB,GAAG;IACjC,wBAAU;IACV,qBAAS;IACT,eAAM;IACN,kBAAO;IACP,eAAM;IACN,WAAI;IACJ,8CAAoB;IACpB,mBAAQ;IACR,iBAAO;IACP,0CAAmB;IACnB,sBAAS;CACV,CAAA;AACD;;GAEG;AACU,QAAA,oBAAoB,GAAG,CAAC,kCAAe,EAAE,0BAAW,EAAE,0BAAQ,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { Validation } from '../types';
2
+ /**
3
+ * Validate that all hashes used by the entity were actually IPFS hashes
4
+ * @public
5
+ */
6
+ export declare const ipfsHashing: Validation;
7
+ //# sourceMappingURL=ipfs-hashing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipfs-hashing.d.ts","sourceRoot":"","sources":["../../src/validations/ipfs-hashing.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,UAAU,EAAE,MAAM,UAAU,CAAA;AAEjD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,UAezB,CAAA"}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ipfsHashing = void 0;
4
+ const schemas_1 = require("@dcl/schemas");
5
+ const _1 = require(".");
6
+ const __1 = require("..");
7
+ const types_1 = require("../types");
8
+ /**
9
+ * Validate that all hashes used by the entity were actually IPFS hashes
10
+ * @public
11
+ */
12
+ exports.ipfsHashing = {
13
+ validate: ({ deployment }) => {
14
+ const { entity } = deployment;
15
+ if (entity.timestamp < _1.ADR_X_TIMESTAMP)
16
+ return __1.OK;
17
+ const hashesInContent = entity.content?.map(({ hash }) => hash) ?? [];
18
+ const allHashes = [entity.id, ...hashesInContent];
19
+ const errors = allHashes
20
+ .filter((hash) => !schemas_1.IPFSv2.validate(hash))
21
+ .map((hash) => `This hash '${hash}' is not valid. It should be IPFS v2 format.`);
22
+ return (0, types_1.fromErrors)(...errors);
23
+ },
24
+ };
25
+ //# sourceMappingURL=ipfs-hashing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipfs-hashing.js","sourceRoot":"","sources":["../../src/validations/ipfs-hashing.ts"],"names":[],"mappings":";;;AAAA,0CAAqC;AACrC,wBAAmC;AACnC,0BAAuB;AACvB,oCAAiD;AAEjD;;;GAGG;AACU,QAAA,WAAW,GAAe;IACrC,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QAC3B,MAAM,EAAE,MAAM,EAAE,GAAG,UAAU,CAAA;QAE7B,IAAI,MAAM,CAAC,SAAS,GAAG,kBAAe;YAAE,OAAO,MAAE,CAAA;QAEjD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;QACrE,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,eAAe,CAAC,CAAA;QAEjD,MAAM,MAAM,GAAG,SAAS;aACrB,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,gBAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;aACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,cAAc,IAAI,8CAA8C,CAAC,CAAA;QAElF,OAAO,IAAA,kBAAU,EAAC,GAAG,MAAM,CAAC,CAAA;IAC9B,CAAC;CACF,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Validate entities metadata against its corresponding schema
3
+ * @public
4
+ */
5
+ export declare const metadata: import("../types").Validation;
6
+ //# sourceMappingURL=metadata-schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata-schema.d.ts","sourceRoot":"","sources":["../../src/validations/metadata-schema.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,eAAO,MAAM,QAAQ,+BAYnB,CAAA"}
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.metadata = void 0;
4
+ const schemas_1 = require("@dcl/schemas");
5
+ const dcl_catalyst_commons_1 = require("dcl-catalyst-commons");
6
+ const _1 = require(".");
7
+ const types_1 = require("../types");
8
+ /**
9
+ * Validate entities metadata against its corresponding schema
10
+ * @public
11
+ */
12
+ exports.metadata = (0, types_1.conditionalValidation)({
13
+ predicate: ({ deployment }) => {
14
+ if (deployment.entity.timestamp <= _1.ADR_X_TIMESTAMP)
15
+ return true;
16
+ // todo: move this map to catalyst-commons
17
+ const validate = {
18
+ [dcl_catalyst_commons_1.EntityType.PROFILE]: schemas_1.Profile.validate,
19
+ [dcl_catalyst_commons_1.EntityType.SCENE]: schemas_1.Scene.validate,
20
+ [dcl_catalyst_commons_1.EntityType.WEARABLE]: schemas_1.Wearable.validate,
21
+ };
22
+ return validate[deployment.entity.type](deployment.entity.metadata);
23
+ },
24
+ message: ({ deployment }) => `The metadata for this entity type (${deployment.entity.type}) is not valid.`,
25
+ });
26
+ //# sourceMappingURL=metadata-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata-schema.js","sourceRoot":"","sources":["../../src/validations/metadata-schema.ts"],"names":[],"mappings":";;;AAAA,0CAAuD;AACvD,+DAAiD;AACjD,wBAAmC;AACnC,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,QAAQ,GAAG,IAAA,6BAAqB,EAAC;IAC5C,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;QAC5B,IAAI,UAAU,CAAC,MAAM,CAAC,SAAS,IAAI,kBAAe;YAAE,OAAO,IAAI,CAAA;QAC/D,0CAA0C;QAC1C,MAAM,QAAQ,GAAG;YACf,CAAC,iCAAU,CAAC,OAAO,CAAC,EAAE,iBAAO,CAAC,QAAQ;YACtC,CAAC,iCAAU,CAAC,KAAK,CAAC,EAAE,eAAK,CAAC,QAAQ;YAClC,CAAC,iCAAU,CAAC,QAAQ,CAAC,EAAE,kBAAQ,CAAC,QAAQ;SACzC,CAAA;QACD,OAAO,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,sCAAsC,UAAU,CAAC,MAAM,CAAC,IAAI,iBAAiB;CAC3G,CAAC,CAAA"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Make sure that the deployment actually failed, and that it can be re-deployed
3
+ * @public
4
+ */
5
+ export declare const mustHaveFailedBefore: import("../types").Validation;
6
+ //# sourceMappingURL=must-have-failed-before.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"must-have-failed-before.d.ts","sourceRoot":"","sources":["../../src/validations/must-have-failed-before.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,oBAAoB,+BAI/B,CAAA"}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mustHaveFailedBefore = void 0;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Make sure that the deployment actually failed, and that it can be re-deployed
7
+ * @public
8
+ */
9
+ exports.mustHaveFailedBefore = (0, types_1.conditionalValidation)({
10
+ predicate: async ({ deployment, externalCalls }) => await externalCalls.isFailedDeployment(deployment.entity.type, deployment.entity.id),
11
+ message: () => "This entity was already marked as failed. You can't fix it",
12
+ });
13
+ //# sourceMappingURL=must-have-failed-before.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"must-have-failed-before.js","sourceRoot":"","sources":["../../src/validations/must-have-failed-before.ts"],"names":[],"mappings":";;;AAAA,oCAAgD;AAEhD;;;GAGG;AACU,QAAA,oBAAoB,GAAG,IAAA,6BAAqB,EAAC;IACxD,SAAS,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,EAAE,EAAE,CACjD,MAAM,aAAa,CAAC,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;IACtF,OAAO,EAAE,GAAG,EAAE,CAAC,4DAA4D;CAC5E,CAAC,CAAA"}