@tinloof/medusa-sanity-sync 0.1.0
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.
- package/.medusa/server/src/admin/index.js +1521 -0
- package/.medusa/server/src/admin/index.mjs +1520 -0
- package/.medusa/server/src/api/admin/sanity/documents/[id]/route.d.ts +3 -0
- package/.medusa/server/src/api/admin/sanity/documents/[id]/route.d.ts.map +1 -0
- package/.medusa/server/src/api/admin/sanity/documents/[id]/route.js +12 -0
- package/.medusa/server/src/api/admin/sanity/entities/[entityType]/[id]/sync/route.d.ts +7 -0
- package/.medusa/server/src/api/admin/sanity/entities/[entityType]/[id]/sync/route.d.ts.map +1 -0
- package/.medusa/server/src/api/admin/sanity/entities/[entityType]/[id]/sync/route.js +23 -0
- package/.medusa/server/src/api/admin/sanity/syncs/route.d.ts +14 -0
- package/.medusa/server/src/api/admin/sanity/syncs/route.d.ts.map +1 -0
- package/.medusa/server/src/api/admin/sanity/syncs/route.js +60 -0
- package/.medusa/server/src/core/default-entities.d.ts +35 -0
- package/.medusa/server/src/core/default-entities.d.ts.map +1 -0
- package/.medusa/server/src/core/default-entities.js +67 -0
- package/.medusa/server/src/core/entity-registry.d.ts +15 -0
- package/.medusa/server/src/core/entity-registry.d.ts.map +1 -0
- package/.medusa/server/src/core/entity-registry.js +35 -0
- package/.medusa/server/src/core/index.d.ts +4 -0
- package/.medusa/server/src/core/index.d.ts.map +1 -0
- package/.medusa/server/src/core/index.js +17 -0
- package/.medusa/server/src/core/transformer.d.ts +49 -0
- package/.medusa/server/src/core/transformer.d.ts.map +1 -0
- package/.medusa/server/src/core/transformer.js +76 -0
- package/.medusa/server/src/event-batcher/event-batcher.d.ts +29 -0
- package/.medusa/server/src/event-batcher/event-batcher.d.ts.map +1 -0
- package/.medusa/server/src/event-batcher/event-batcher.js +93 -0
- package/.medusa/server/src/event-batcher/event-buffer.d.ts +35 -0
- package/.medusa/server/src/event-batcher/event-buffer.d.ts.map +1 -0
- package/.medusa/server/src/event-batcher/event-buffer.js +127 -0
- package/.medusa/server/src/event-batcher/index.d.ts +4 -0
- package/.medusa/server/src/event-batcher/index.d.ts.map +1 -0
- package/.medusa/server/src/event-batcher/index.js +8 -0
- package/.medusa/server/src/event-batcher/types.d.ts +50 -0
- package/.medusa/server/src/event-batcher/types.d.ts.map +1 -0
- package/.medusa/server/src/event-batcher/types.js +3 -0
- package/.medusa/server/src/index.d.ts +40 -0
- package/.medusa/server/src/index.d.ts.map +1 -0
- package/.medusa/server/src/index.js +62 -0
- package/.medusa/server/src/modules/sanity/index.d.ts +8 -0
- package/.medusa/server/src/modules/sanity/index.d.ts.map +1 -0
- package/.medusa/server/src/modules/sanity/index.js +15 -0
- package/.medusa/server/src/modules/sanity/service.d.ts +115 -0
- package/.medusa/server/src/modules/sanity/service.d.ts.map +1 -0
- package/.medusa/server/src/modules/sanity/service.js +301 -0
- package/.medusa/server/src/subscribers/factory.d.ts +43 -0
- package/.medusa/server/src/subscribers/factory.d.ts.map +1 -0
- package/.medusa/server/src/subscribers/factory.js +68 -0
- package/.medusa/server/src/subscribers/index.d.ts +9 -0
- package/.medusa/server/src/subscribers/index.d.ts.map +1 -0
- package/.medusa/server/src/subscribers/index.js +13 -0
- package/.medusa/server/src/subscribers/sanity-sync.d.ts +10 -0
- package/.medusa/server/src/subscribers/sanity-sync.d.ts.map +1 -0
- package/.medusa/server/src/subscribers/sanity-sync.js +81 -0
- package/.medusa/server/src/types/index.d.ts +189 -0
- package/.medusa/server/src/types/index.d.ts.map +1 -0
- package/.medusa/server/src/types/index.js +3 -0
- package/.medusa/server/src/workflows/index.d.ts +2 -0
- package/.medusa/server/src/workflows/index.d.ts.map +1 -0
- package/.medusa/server/src/workflows/index.js +6 -0
- package/.medusa/server/src/workflows/sanity-sync-products/index.d.ts +6 -0
- package/.medusa/server/src/workflows/sanity-sync-products/index.d.ts.map +1 -0
- package/.medusa/server/src/workflows/sanity-sync-products/index.js +16 -0
- package/.medusa/server/src/workflows/sanity-sync-products/steps/sync.d.ts +4 -0
- package/.medusa/server/src/workflows/sanity-sync-products/steps/sync.d.ts.map +1 -0
- package/.medusa/server/src/workflows/sanity-sync-products/steps/sync.js +90 -0
- package/README.md +459 -0
- package/package.json +120 -0
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const client_1 = require("@sanity/client");
|
|
4
|
+
const core_1 = require("../../core");
|
|
5
|
+
const event_batcher_1 = require("../../event-batcher");
|
|
6
|
+
class SanityModuleService {
|
|
7
|
+
constructor({ logger }, options) {
|
|
8
|
+
this.client = (0, client_1.createClient)({
|
|
9
|
+
projectId: options.project_id,
|
|
10
|
+
apiVersion: options.api_version,
|
|
11
|
+
dataset: options.dataset,
|
|
12
|
+
token: options.api_token,
|
|
13
|
+
});
|
|
14
|
+
this.logger = logger;
|
|
15
|
+
this.syncHandlers = options.syncHandlers;
|
|
16
|
+
// Initialize entity registry with configured entities or defaults
|
|
17
|
+
const entities = options.entities?.length
|
|
18
|
+
? options.entities
|
|
19
|
+
: core_1.defaultEntities;
|
|
20
|
+
this.entityRegistry = (0, core_1.createEntityRegistry)(entities);
|
|
21
|
+
// Initialize transformer with plugin-level transformer function
|
|
22
|
+
this.transformer = (0, core_1.createTransformer)({
|
|
23
|
+
logger,
|
|
24
|
+
transformer: options.transformer,
|
|
25
|
+
});
|
|
26
|
+
// Initialize batcher with flush handler
|
|
27
|
+
this.batcher = new event_batcher_1.EventBatcher(this.handleBatchFlush.bind(this), options.batching);
|
|
28
|
+
this.logger.info(`Sanity module initialized with ${this.entityRegistry.size} entity type(s), batching ${this.batcher.isEnabled ? "enabled" : "disabled"}`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the entity registry for external access.
|
|
32
|
+
*/
|
|
33
|
+
getEntityRegistry() {
|
|
34
|
+
return this.entityRegistry;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the transformer for external access.
|
|
38
|
+
*/
|
|
39
|
+
getTransformer() {
|
|
40
|
+
return this.transformer;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the batcher for external access (used by subscribers).
|
|
44
|
+
*/
|
|
45
|
+
getBatcher() {
|
|
46
|
+
return this.batcher;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create sync context for custom handlers.
|
|
50
|
+
*/
|
|
51
|
+
createSyncContext() {
|
|
52
|
+
return {
|
|
53
|
+
sanityClient: this.client,
|
|
54
|
+
logger: this.logger,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Handle batch flush - called by batcher when ready.
|
|
59
|
+
* Uses Sanity's transaction API for batch operations across all entity types.
|
|
60
|
+
*/
|
|
61
|
+
async handleBatchFlush(batches) {
|
|
62
|
+
const ctx = this.createSyncContext();
|
|
63
|
+
// If custom handlers are provided, fall back to individual calls
|
|
64
|
+
if (this.syncHandlers) {
|
|
65
|
+
await this.handleBatchFlushWithHandlers(batches, ctx);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Use single Sanity transaction for all entity types
|
|
69
|
+
const transaction = this.client.transaction();
|
|
70
|
+
let createCount = 0;
|
|
71
|
+
let updateCount = 0;
|
|
72
|
+
let deleteCount = 0;
|
|
73
|
+
for (const [entityType, batch] of batches.entries()) {
|
|
74
|
+
const entity = this.entityRegistry.get(entityType);
|
|
75
|
+
if (!entity) {
|
|
76
|
+
this.logger.warn(`Entity type "${entityType}" not registered, skipping`);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// Process creates - use createIfNotExists
|
|
80
|
+
for (const { id, data } of batch.creates) {
|
|
81
|
+
try {
|
|
82
|
+
const result = this.transformer.transformForCreate(entity, data, id);
|
|
83
|
+
transaction.createIfNotExists(result.data);
|
|
84
|
+
createCount += 1;
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
this.logger.error(`Failed to prepare create for ${entityType} ${id}: ${error}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Process updates - resolve draft IDs, then patch to preserve Sanity-managed fields
|
|
91
|
+
if (batch.updates.length > 0) {
|
|
92
|
+
const updateIds = batch.updates.map(({ id }) => id);
|
|
93
|
+
const targetIds = await this.getTargetIds(updateIds);
|
|
94
|
+
for (const { id, data } of batch.updates) {
|
|
95
|
+
try {
|
|
96
|
+
const result = this.transformer.transformForUpdate(entity, data);
|
|
97
|
+
const targetId = targetIds.get(id) ?? id;
|
|
98
|
+
transaction.createIfNotExists({
|
|
99
|
+
_id: targetId,
|
|
100
|
+
_type: entity.sanityType,
|
|
101
|
+
});
|
|
102
|
+
transaction.patch(targetId, { set: result.data });
|
|
103
|
+
updateCount += 1;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
this.logger.error(`Failed to prepare update for ${entityType} ${id}: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Process deletes - delete both published and draft
|
|
111
|
+
for (const { id } of batch.deletes) {
|
|
112
|
+
transaction.delete(id);
|
|
113
|
+
transaction.delete(`drafts.${id}`);
|
|
114
|
+
deleteCount += 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Commit transaction if there are any operations
|
|
118
|
+
const totalOps = createCount + updateCount + deleteCount;
|
|
119
|
+
if (totalOps > 0) {
|
|
120
|
+
try {
|
|
121
|
+
await transaction.commit();
|
|
122
|
+
this.logger.info(`Batch committed: ${createCount} creates, ${updateCount} updates, ${deleteCount} deletes`);
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
this.logger.error(`Failed to commit batch: ${error}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Handle batch flush with custom handlers (individual calls).
|
|
131
|
+
*/
|
|
132
|
+
async handleBatchFlushWithHandlers(batches, ctx) {
|
|
133
|
+
for (const [entityType, batch] of batches.entries()) {
|
|
134
|
+
// Process creates
|
|
135
|
+
for (const { id, data } of batch.creates) {
|
|
136
|
+
try {
|
|
137
|
+
if (this.syncHandlers?.onCreate) {
|
|
138
|
+
await this.syncHandlers.onCreate(entityType, id, data, ctx);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
await this.createSyncDocument(entityType, data);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
this.logger.error(`Failed to create ${entityType} ${id}: ${error}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Process updates
|
|
149
|
+
for (const { id, data } of batch.updates) {
|
|
150
|
+
try {
|
|
151
|
+
if (this.syncHandlers?.onUpdate) {
|
|
152
|
+
await this.syncHandlers.onUpdate(entityType, id, data, ctx);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
await this.updateSyncDocument(entityType, data);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
this.logger.error(`Failed to update ${entityType} ${id}: ${error}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Process deletes
|
|
163
|
+
for (const { id } of batch.deletes) {
|
|
164
|
+
try {
|
|
165
|
+
if (this.syncHandlers?.onDelete) {
|
|
166
|
+
await this.syncHandlers.onDelete(entityType, id, ctx);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
await this.delete(id);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
this.logger.error(`Failed to delete ${entityType} ${id}: ${error}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
this.logger.info(`Batch flush for ${entityType}: ${batch.creates.length} creates, ${batch.updates.length} updates, ${batch.deletes.length} deletes`);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Upsert a document to Sanity (create if not exists, update if exists).
|
|
181
|
+
*/
|
|
182
|
+
async upsertSyncDocument(entityType, data) {
|
|
183
|
+
const entity = this.entityRegistry.get(entityType);
|
|
184
|
+
if (!entity) {
|
|
185
|
+
throw new Error(`Entity type "${entityType}" is not registered`);
|
|
186
|
+
}
|
|
187
|
+
const [published, draft] = await this.client.getDocuments([
|
|
188
|
+
data.id,
|
|
189
|
+
`drafts.${data.id}`,
|
|
190
|
+
]);
|
|
191
|
+
if (published || draft) {
|
|
192
|
+
return this.updateSyncDocument(entityType, data);
|
|
193
|
+
}
|
|
194
|
+
return this.createSyncDocument(entityType, data);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create a new document in Sanity.
|
|
198
|
+
*/
|
|
199
|
+
async createSyncDocument(entityType, data, options) {
|
|
200
|
+
const entity = this.entityRegistry.get(entityType);
|
|
201
|
+
if (!entity) {
|
|
202
|
+
throw new Error(`Entity type "${entityType}" is not registered`);
|
|
203
|
+
}
|
|
204
|
+
const result = this.transformer.transformForCreate(entity, data, data.id);
|
|
205
|
+
// @ts-expect-error
|
|
206
|
+
const document = await this.client.create(result.data, options);
|
|
207
|
+
return { document, isCreate: true };
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Update an existing document in Sanity.
|
|
211
|
+
*/
|
|
212
|
+
async updateSyncDocument(entityType, data) {
|
|
213
|
+
const entity = this.entityRegistry.get(entityType);
|
|
214
|
+
if (!entity) {
|
|
215
|
+
throw new Error(`Entity type "${entityType}" is not registered`);
|
|
216
|
+
}
|
|
217
|
+
const result = this.transformer.transformForUpdate(entity, data);
|
|
218
|
+
const targetId = await this.getTargetId(data.id);
|
|
219
|
+
const document = await this.client
|
|
220
|
+
.patch(targetId)
|
|
221
|
+
.set(result.data)
|
|
222
|
+
.commit();
|
|
223
|
+
return { document, isCreate: false };
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Get the document ID to patch: prefers the draft if it exists, otherwise the published ID.
|
|
227
|
+
*/
|
|
228
|
+
async getTargetId(id) {
|
|
229
|
+
const draftId = `drafts.${id}`;
|
|
230
|
+
const draft = await this.client.getDocument(draftId);
|
|
231
|
+
return draft ? draftId : id;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Get target IDs for a batch of document IDs.
|
|
235
|
+
* Returns a map of original ID → target ID (draft or published).
|
|
236
|
+
*/
|
|
237
|
+
async getTargetIds(ids) {
|
|
238
|
+
const draftIds = ids.map((id) => `drafts.${id}`);
|
|
239
|
+
const drafts = await this.client.getDocuments(draftIds);
|
|
240
|
+
const targetMap = new Map();
|
|
241
|
+
for (let i = 0; i < ids.length; i++) {
|
|
242
|
+
targetMap.set(ids[i], drafts[i] ? draftIds[i] : ids[i]);
|
|
243
|
+
}
|
|
244
|
+
return targetMap;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Retrieve a document from Sanity by ID.
|
|
248
|
+
*/
|
|
249
|
+
retrieve(id) {
|
|
250
|
+
return this.client.getDocument(id);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Delete a document from Sanity by ID (both published and draft).
|
|
254
|
+
*/
|
|
255
|
+
delete(id) {
|
|
256
|
+
const tx = this.client.transaction();
|
|
257
|
+
tx.delete(id);
|
|
258
|
+
tx.delete(`drafts.${id}`);
|
|
259
|
+
return tx.commit();
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Update a document in Sanity with raw data.
|
|
263
|
+
* Targets the draft if one exists, otherwise the published document.
|
|
264
|
+
*/
|
|
265
|
+
async update(id, data) {
|
|
266
|
+
const targetId = await this.getTargetId(id);
|
|
267
|
+
return await this.client.patch(targetId, { set: data }).commit();
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* List documents from Sanity by IDs.
|
|
271
|
+
*/
|
|
272
|
+
async list(filter) {
|
|
273
|
+
const data = await this.client.getDocuments(Array.isArray(filter.id) ? filter.id : [filter.id]);
|
|
274
|
+
return data.map((doc) => ({
|
|
275
|
+
id: doc?._id,
|
|
276
|
+
...doc,
|
|
277
|
+
}));
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Compensate for failed sync operations (rollback).
|
|
281
|
+
*/
|
|
282
|
+
async compensate(upsertMap) {
|
|
283
|
+
await Promise.all(upsertMap.map(({ id, before, after, isCreate }) => {
|
|
284
|
+
if (isCreate) {
|
|
285
|
+
// Document was created, delete it
|
|
286
|
+
return this.delete(after._id);
|
|
287
|
+
}
|
|
288
|
+
// Document was updated, restore previous state
|
|
289
|
+
const { _id, _rev, _type, _createdAt, _updatedAt, ...oldData } = before;
|
|
290
|
+
return this.update(id, oldData);
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Get the Sanity client for advanced operations.
|
|
295
|
+
*/
|
|
296
|
+
getClient() {
|
|
297
|
+
return this.client;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
exports.default = SanityModuleService;
|
|
301
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9tb2R1bGVzL3Nhbml0eS9zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQ0EsMkNBSXdCO0FBQ3hCLHFDQU1vQjtBQUNwQix1REFBMEU7QUFhMUUsTUFBcUIsbUJBQW1CO0lBUXRDLFlBQVksRUFBRSxNQUFNLEVBQXdCLEVBQUUsT0FBNEI7UUFDeEUsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEVBQUM7WUFDekIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxVQUFVO1lBQzdCLFVBQVUsRUFBRSxPQUFPLENBQUMsV0FBVztZQUMvQixPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87WUFDeEIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1NBQ3pCLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxZQUFZLEdBQUcsT0FBTyxDQUFDLFlBQVksQ0FBQztRQUV6QyxrRUFBa0U7UUFDbEUsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsRUFBRSxNQUFNO1lBQ3ZDLENBQUMsQ0FBQyxPQUFPLENBQUMsUUFBUTtZQUNsQixDQUFDLENBQUMsc0JBQWUsQ0FBQztRQUNwQixJQUFJLENBQUMsY0FBYyxHQUFHLElBQUEsMkJBQW9CLEVBQUMsUUFBUSxDQUFDLENBQUM7UUFFckQsZ0VBQWdFO1FBQ2hFLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBQSx3QkFBaUIsRUFBQztZQUNuQyxNQUFNO1lBQ04sV0FBVyxFQUFFLE9BQU8sQ0FBQyxXQUFXO1NBQ2pDLENBQUMsQ0FBQztRQUVILHdDQUF3QztRQUN4QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksNEJBQVksQ0FDN0IsSUFBSSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFDaEMsT0FBTyxDQUFDLFFBQVEsQ0FD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
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework";
|
|
2
|
+
/**
|
|
3
|
+
* Options for creating an entity subscriber.
|
|
4
|
+
*/
|
|
5
|
+
export type EntitySubscriberOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* The Medusa entity type to sync (e.g., "product", "product_category")
|
|
8
|
+
*/
|
|
9
|
+
entityType: string;
|
|
10
|
+
/**
|
|
11
|
+
* The events that trigger the sync
|
|
12
|
+
*/
|
|
13
|
+
events: string[];
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Factory function to create a subscriber for syncing entities to Sanity.
|
|
17
|
+
* Use this to create subscribers for custom entity types.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // src/subscribers/my-custom-entity-sync.ts
|
|
22
|
+
* import { createEntitySubscriber } from "@tinloof/medusa-sanity-sync/subscribers";
|
|
23
|
+
*
|
|
24
|
+
* const { handler, config } = createEntitySubscriber({
|
|
25
|
+
* entityType: "my_custom_entity",
|
|
26
|
+
* events: [
|
|
27
|
+
* "my-custom-entity.created",
|
|
28
|
+
* "my-custom-entity.updated",
|
|
29
|
+
* "my-custom-entity.deleted",
|
|
30
|
+
* ],
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* export default handler;
|
|
34
|
+
* export { config };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function createEntitySubscriber(options: EntitySubscriberOptions): {
|
|
38
|
+
handler: (args: SubscriberArgs<{
|
|
39
|
+
id: string;
|
|
40
|
+
}>) => Promise<void>;
|
|
41
|
+
config: SubscriberConfig;
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../../src/subscribers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAM5E;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAYF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG;IACxE,OAAO,EAAE,CAAC,IAAI,EAAE,cAAc,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAuCA"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEntitySubscriber = createEntitySubscriber;
|
|
4
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
5
|
+
const sanity_1 = require("../modules/sanity");
|
|
6
|
+
function getOperationType(eventName) {
|
|
7
|
+
if (eventName.endsWith(".created")) {
|
|
8
|
+
return "create";
|
|
9
|
+
}
|
|
10
|
+
if (eventName.endsWith(".deleted")) {
|
|
11
|
+
return "delete";
|
|
12
|
+
}
|
|
13
|
+
return "update";
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Factory function to create a subscriber for syncing entities to Sanity.
|
|
17
|
+
* Use this to create subscribers for custom entity types.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* // src/subscribers/my-custom-entity-sync.ts
|
|
22
|
+
* import { createEntitySubscriber } from "@tinloof/medusa-sanity-sync/subscribers";
|
|
23
|
+
*
|
|
24
|
+
* const { handler, config } = createEntitySubscriber({
|
|
25
|
+
* entityType: "my_custom_entity",
|
|
26
|
+
* events: [
|
|
27
|
+
* "my-custom-entity.created",
|
|
28
|
+
* "my-custom-entity.updated",
|
|
29
|
+
* "my-custom-entity.deleted",
|
|
30
|
+
* ],
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* export default handler;
|
|
34
|
+
* export { config };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function createEntitySubscriber(options) {
|
|
38
|
+
const handler = async ({ event: { name: eventName, data }, container, }) => {
|
|
39
|
+
const sanityModule = container.resolve(sanity_1.SANITY_MODULE);
|
|
40
|
+
const batcher = sanityModule.getBatcher();
|
|
41
|
+
const operation = getOperationType(eventName);
|
|
42
|
+
// For delete, we don't need entity data
|
|
43
|
+
if (operation === "delete") {
|
|
44
|
+
await batcher.add(options.entityType, data.id, operation);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Fetch entity data for create/update
|
|
48
|
+
const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
49
|
+
const entityRegistry = sanityModule.getEntityRegistry();
|
|
50
|
+
const entity = entityRegistry.get(options.entityType);
|
|
51
|
+
const queryFields = entity?.queryFields?.length
|
|
52
|
+
? entity.queryFields
|
|
53
|
+
: ["*"];
|
|
54
|
+
const { data: entities } = await query.graph({
|
|
55
|
+
entity: entity?.medusaEntity ?? options.entityType,
|
|
56
|
+
fields: queryFields,
|
|
57
|
+
filters: { id: [data.id] },
|
|
58
|
+
});
|
|
59
|
+
if (entities.length > 0) {
|
|
60
|
+
await batcher.add(options.entityType, data.id, operation, entities[0]);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const config = {
|
|
64
|
+
event: options.events,
|
|
65
|
+
};
|
|
66
|
+
return { handler, config };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zdWJzY3JpYmVycy9mYWN0b3J5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0RBLHdEQTBDQztBQTdGRCxxREFBc0U7QUFFdEUsOENBQWtEO0FBaUJsRCxTQUFTLGdCQUFnQixDQUFDLFNBQWlCO0lBQ3pDLElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25DLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFDRCxJQUFJLFNBQVMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUNuQyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FxQkc7QUFDSCxTQUFnQixzQkFBc0IsQ0FBQyxPQUFnQztJQUlyRSxNQUFNLE9BQU8sR0FBRyxLQUFLLEVBQUUsRUFDckIsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsRUFDaEMsU0FBUyxHQUNzQixFQUFFLEVBQUU7UUFDbkMsTUFBTSxZQUFZLEdBQXdCLFNBQVMsQ0FBQyxPQUFPLENBQUMsc0JBQWEsQ0FBQyxDQUFDO1FBQzNFLE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUMxQyxNQUFNLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUU5Qyx3Q0FBd0M7UUFDeEMsSUFBSSxTQUFTLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDM0IsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMxRCxPQUFPO1FBQ1QsQ0FBQztRQUVELHNDQUFzQztRQUN0QyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLGlDQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pFLE1BQU0sY0FBYyxHQUFHLFlBQVksQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQ3hELE1BQU0sTUFBTSxHQUFHLGNBQWMsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3RELE1BQU0sV0FBVyxHQUFHLE1BQU0sRUFBRSxXQUFXLEVBQUUsTUFBTTtZQUM3QyxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVc7WUFDcEIsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFVixNQUFNLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQztZQUMzQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFlBQVksSUFBSSxPQUFPLENBQUMsVUFBVTtZQUNsRCxNQUFNLEVBQUUsV0FBVztZQUNuQixPQUFPLEVBQUUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUU7U0FDM0IsQ0FBQyxDQUFDO1FBRUgsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7SUFDSCxDQUFDLENBQUM7SUFFRixNQUFNLE1BQU0sR0FBcUI7UUFDL0IsS0FBSyxFQUFFLE9BQU8sQ0FBQyxNQUFNO0tBQ3RCLENBQUM7SUFFRixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDO0FBQzdCLENBQUMifQ==
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module exports subscriber utilities for creating custom entity sync subscribers.
|
|
3
|
+
*
|
|
4
|
+
* The default subscribers (product, category, collection) are automatically registered
|
|
5
|
+
* when the plugin is installed. For custom entities, you can use the createEntitySubscriber
|
|
6
|
+
* factory to create your own subscribers.
|
|
7
|
+
*/
|
|
8
|
+
export { createEntitySubscriber } from "./factory";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/subscribers/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* This module exports subscriber utilities for creating custom entity sync subscribers.
|
|
4
|
+
*
|
|
5
|
+
* The default subscribers (product, category, collection) are automatically registered
|
|
6
|
+
* when the plugin is installed. For custom entities, you can use the createEntitySubscriber
|
|
7
|
+
* factory to create your own subscribers.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createEntitySubscriber = void 0;
|
|
11
|
+
var factory_1 = require("./factory");
|
|
12
|
+
Object.defineProperty(exports, "createEntitySubscriber", { enumerable: true, get: function () { return factory_1.createEntitySubscriber; } });
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc3Vic2NyaWJlcnMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7R0FNRzs7O0FBRUgscUNBQW1EO0FBQTFDLGlIQUFBLHNCQUFzQixPQUFBIn0=
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SubscriberArgs, SubscriberConfig } from "@medusajs/framework";
|
|
2
|
+
/**
|
|
3
|
+
* Unified subscriber for syncing all entities to Sanity.
|
|
4
|
+
* Handles products, categories, and collections.
|
|
5
|
+
*/
|
|
6
|
+
export default function syncToSanity({ event: { name: eventName, data }, container, }: SubscriberArgs<{
|
|
7
|
+
id: string;
|
|
8
|
+
}>): Promise<void>;
|
|
9
|
+
export declare const config: SubscriberConfig;
|
|
10
|
+
//# sourceMappingURL=sanity-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanity-sync.d.ts","sourceRoot":"","sources":["../../../../src/subscribers/sanity-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA+B5E;;;GAGG;AACH,wBAA8B,YAAY,CAAC,EACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,EAChC,SAAS,GACV,EAAE,cAAc,CAAC;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,iBAsChC;AAED,eAAO,MAAM,MAAM,EAAE,gBAepB,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
exports.default = syncToSanity;
|
|
5
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
6
|
+
const sanity_1 = require("../modules/sanity");
|
|
7
|
+
/**
|
|
8
|
+
* Map event prefix to entity type
|
|
9
|
+
*/
|
|
10
|
+
const EVENT_TO_ENTITY = {
|
|
11
|
+
product: "product",
|
|
12
|
+
"product-category": "product_category",
|
|
13
|
+
"product-collection": "product_collection",
|
|
14
|
+
};
|
|
15
|
+
function getOperationType(eventName) {
|
|
16
|
+
if (eventName.endsWith(".created")) {
|
|
17
|
+
return "create";
|
|
18
|
+
}
|
|
19
|
+
if (eventName.endsWith(".deleted")) {
|
|
20
|
+
return "delete";
|
|
21
|
+
}
|
|
22
|
+
return "update";
|
|
23
|
+
}
|
|
24
|
+
function getEntityType(eventName) {
|
|
25
|
+
// Event format: "prefix.action" (e.g., "product.created", "product-category.updated")
|
|
26
|
+
const prefix = eventName.split(".")[0];
|
|
27
|
+
return EVENT_TO_ENTITY[prefix] ?? null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Unified subscriber for syncing all entities to Sanity.
|
|
31
|
+
* Handles products, categories, and collections.
|
|
32
|
+
*/
|
|
33
|
+
async function syncToSanity({ event: { name: eventName, data }, container, }) {
|
|
34
|
+
const sanityModule = container.resolve(sanity_1.SANITY_MODULE);
|
|
35
|
+
const batcher = sanityModule.getBatcher();
|
|
36
|
+
const entityRegistry = sanityModule.getEntityRegistry();
|
|
37
|
+
const entityType = getEntityType(eventName);
|
|
38
|
+
if (!entityType) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const entity = entityRegistry.get(entityType);
|
|
42
|
+
if (!entity) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const operation = getOperationType(eventName);
|
|
46
|
+
// For delete, we don't need entity data
|
|
47
|
+
if (operation === "delete") {
|
|
48
|
+
await batcher.add(entityType, data.id, operation);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Fetch entity data for create/update
|
|
52
|
+
const query = container.resolve(utils_1.ContainerRegistrationKeys.QUERY);
|
|
53
|
+
const queryFields = entity.queryFields?.length
|
|
54
|
+
? entity.queryFields
|
|
55
|
+
: ["*"];
|
|
56
|
+
const { data: entities } = await query.graph({
|
|
57
|
+
entity: entity.medusaEntity,
|
|
58
|
+
fields: queryFields,
|
|
59
|
+
filters: { id: [data.id] },
|
|
60
|
+
});
|
|
61
|
+
if (entities.length > 0) {
|
|
62
|
+
await batcher.add(entityType, data.id, operation, entities[0]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.config = {
|
|
66
|
+
event: [
|
|
67
|
+
// Products
|
|
68
|
+
"product.created",
|
|
69
|
+
"product.updated",
|
|
70
|
+
"product.deleted",
|
|
71
|
+
// Categories
|
|
72
|
+
"product-category.created",
|
|
73
|
+
"product-category.updated",
|
|
74
|
+
"product-category.deleted",
|
|
75
|
+
// Collections
|
|
76
|
+
"product-collection.created",
|
|
77
|
+
"product-collection.updated",
|
|
78
|
+
"product-collection.deleted",
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FuaXR5LXN5bmMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvc3Vic2NyaWJlcnMvc2FuaXR5LXN5bmMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBbUNBLCtCQXlDQztBQTNFRCxxREFBc0U7QUFFdEUsOENBQWtEO0FBR2xEOztHQUVHO0FBQ0gsTUFBTSxlQUFlLEdBQTJCO0lBQzlDLE9BQU8sRUFBRSxTQUFTO0lBQ2xCLGtCQUFrQixFQUFFLGtCQUFrQjtJQUN0QyxvQkFBb0IsRUFBRSxvQkFBb0I7Q0FDM0MsQ0FBQztBQUVGLFNBQVMsZ0JBQWdCLENBQUMsU0FBaUI7SUFDekMsSUFBSSxTQUFTLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDbkMsT0FBTyxRQUFRLENBQUM7SUFDbEIsQ0FBQztJQUNELElBQUksU0FBUyxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQ25DLE9BQU8sUUFBUSxDQUFDO0lBQ2xCLENBQUM7SUFDRCxPQUFPLFFBQVEsQ0FBQztBQUNsQixDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsU0FBaUI7SUFDdEMsc0ZBQXNGO0lBQ3RGLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkMsT0FBTyxlQUFlLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDO0FBQ3pDLENBQUM7QUFFRDs7O0dBR0c7QUFDWSxLQUFLLFVBQVUsWUFBWSxDQUFDLEVBQ3pDLEtBQUssRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEVBQ2hDLFNBQVMsR0FDc0I7SUFDL0IsTUFBTSxZQUFZLEdBQXdCLFNBQVMsQ0FBQyxPQUFPLENBQUMsc0JBQWEsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sT0FBTyxHQUFHLFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUMxQyxNQUFNLGNBQWMsR0FBRyxZQUFZLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztJQUV4RCxNQUFNLFVBQVUsR0FBRyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDNUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2hCLE9BQU87SUFDVCxDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUM5QyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixPQUFPO0lBQ1QsQ0FBQztJQUVELE1BQU0sU0FBUyxHQUFHLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRTlDLHdDQUF3QztJQUN4QyxJQUFJLFNBQVMsS0FBSyxRQUFRLEVBQUUsQ0FBQztRQUMzQixNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDbEQsT0FBTztJQUNULENBQUM7SUFFRCxzQ0FBc0M7SUFDdEMsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxpQ0FBeUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNqRSxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsV0FBVyxFQUFFLE1BQU07UUFDNUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxXQUFXO1FBQ3BCLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRVYsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUM7UUFDM0MsTUFBTSxFQUFFLE1BQU0sQ0FBQyxZQUFZO1FBQzNCLE1BQU0sRUFBRSxXQUFXO1FBQ25CLE9BQU8sRUFBRSxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsRUFBRTtLQUMzQixDQUFDLENBQUM7SUFFSCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDeEIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsRUFBRSxFQUFFLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0FBQ0gsQ0FBQztBQUVZLFFBQUEsTUFBTSxHQUFxQjtJQUN0QyxLQUFLLEVBQUU7UUFDTCxXQUFXO1FBQ1gsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsYUFBYTtRQUNiLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLGNBQWM7UUFDZCw0QkFBNEI7UUFDNUIsNEJBQTRCO1FBQzVCLDRCQUE0QjtLQUM3QjtDQUNGLENBQUMifQ==
|