@serve.zone/interfaces 32.33.0 → 32.34.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/changelog.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-09-28 - 32.34.0
4
+
5
+ ### Features
6
+
7
+ - A fresh service can take over a legacy service's Corestore data. An
8
+ `adoptCorestoreLegacyResources` selection entry may name `successorServiceId`: the adopting
9
+ binding is then created on that successor, and `IPlatformBindingCorestoreLegacyAdoption` records
10
+ the legacy owner as `legacyServiceId`. `ICorestoreLegacyResourceAdoptionPlanEntry` carries the
11
+ same `successorServiceId`, so Corestore's offline adoption moves the resource from the legacy
12
+ owner's manifest entry to the successor's binding. `validateCorestoreLegacyResourceSelections`,
13
+ `validateCorestoreLegacyResourceAdoptionPlan`, `validatePlatformBindingCorestoreLegacyAdoption` and
14
+ `createCorestoreLegacyResourceAdoptionPlan` apply the rules: the successor is never the legacy
15
+ owner, owns no legacy resource of the capability, and no service capability adopts twice. New
16
+ refusals: `legacy-resource-adopted-elsewhere`, `successor-organization-mismatch`,
17
+ `successor-not-greenfield` and `successor-owns-legacy-resource`. Until now a legacy resource could
18
+ only be adopted by its own service, so a service replaced by a greenfield deployment stranded its
19
+ database and bucket.
20
+
3
21
  ## 2026-09-28 - 32.33.0
4
22
 
5
23
  ### Features
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.33.0',
6
+ version: '32.34.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLHVGQUF1RjtDQUNyRyxDQUFBIn0=
@@ -15,6 +15,12 @@ import type { TPlatformBindingStatusReason } from '../platform/types.js';
15
15
  * answers the plan (`ICorestoreLegacyResourceAdoptionPlanEntry[]`).
16
16
  * 3. The operator stops Corestore and runs its `legacy-resource-adoption` migration with that plan.
17
17
  * Until then Corestore refuses the binding, which reports `legacy-adoption-pending`.
18
+ *
19
+ * A resource is adopted by a binding of the service that owns it, or, when the selection names a
20
+ * `successorServiceId`, by a binding of that successor: a fresh service of the same organization
21
+ * that replaces the legacy one and takes over its data. The successor's binding records the legacy
22
+ * owner as `corestoreLegacyAdoption.legacyServiceId`, and the plan entry carries the successor, so
23
+ * Corestore moves the resource from the legacy owner's manifest entry to the successor's binding.
18
24
  */
19
25
  export type TCorestoreLegacyCapability = 'database' | 'objectstorage';
20
26
  /**
@@ -83,20 +89,29 @@ export type TClusterCorestoreLegacyResourceInventory = {
83
89
  reachable: false;
84
90
  errorCode: 'CORESTORE_ENDPOINT_UNKNOWN' | 'CORESTORE_UNREACHABLE';
85
91
  };
86
- /** One resource an administrator selects for adoption. */
92
+ /**
93
+ * One resource an administrator selects for adoption: the legacy resource `serviceId` owns of
94
+ * `capability`. Without `successorServiceId` a binding of `serviceId` adopts it; with it, a binding of
95
+ * that other service does, which must be a greenfield service of the same organization.
96
+ */
87
97
  export interface ICorestoreLegacyResourceSelection {
88
98
  serviceId: string;
89
99
  capability: TCorestoreLegacyCapability;
100
+ /** The service whose binding adopts the resource, when it is not `serviceId`; never `serviceId`. */
101
+ successorServiceId?: string;
90
102
  }
91
103
  /**
92
104
  * One entry of Corestore's offline adoption plan, exactly the object its
93
- * `legacy-resource-adoption` migration reads: the service, the capability and the binding that may
94
- * adopt its legacy resource. The legacy identity is Corestore's own and is not restated here.
105
+ * `legacy-resource-adoption` migration reads: the service that owns the legacy resource, the
106
+ * capability, the binding that may adopt it and, when that binding belongs to another service, that
107
+ * successor service. The legacy identity is Corestore's own and is not restated here.
95
108
  */
96
109
  export interface ICorestoreLegacyResourceAdoptionPlanEntry {
97
110
  serviceId: string;
98
111
  capability: TCorestoreLegacyCapability;
99
112
  bindingId: string;
113
+ /** The service `bindingId` belongs to, when it is not `serviceId`; never `serviceId`. */
114
+ successorServiceId?: string;
100
115
  }
101
116
  /**
102
117
  * Why `adoptCorestoreLegacyResources` wrote nothing:
@@ -107,11 +122,19 @@ export interface ICorestoreLegacyResourceAdoptionPlanEntry {
107
122
  * - `legacy-resource-blocked`: a selected resource is unadopted with a blocker;
108
123
  * - `legacy-resource-authorized-elsewhere`: a selected resource is authorized for a binding Cloudly
109
124
  * does not hold as that resource's adoption;
110
- * - `service-absent`: Cloudly has no such service;
111
- * - `binding-exists`: the service already has a binding of that capability that adopts nothing,
112
- * or adopts another resource.
125
+ * - `legacy-resource-adopted-elsewhere`: Cloudly already holds a binding of another service as a
126
+ * selected resource's adoption;
127
+ * - `service-absent`: Cloudly has no such service, legacy owner or successor;
128
+ * - `binding-exists`: the adopting service already has a binding of that capability that adopts
129
+ * nothing, or adopts another resource;
130
+ * - `successor-organization-mismatch`: the successor belongs to another organization than the
131
+ * legacy owner, or either names none;
132
+ * - `successor-not-greenfield`: the successor is not an immutable-deployment service (it deploys on
133
+ * push, or does not require an immutable image);
134
+ * - `successor-owns-legacy-resource`: the successor owns a legacy resource of that capability
135
+ * itself, which Corestore would keep beside the adopted one.
113
136
  */
114
- export type TCorestoreLegacyAdoptionRefusal = 'legacy-inventory-unreachable' | 'legacy-inventory-changed' | 'legacy-resource-absent' | 'legacy-resource-blocked' | 'legacy-resource-authorized-elsewhere' | 'service-absent' | 'binding-exists';
137
+ export type TCorestoreLegacyAdoptionRefusal = 'legacy-inventory-unreachable' | 'legacy-inventory-changed' | 'legacy-resource-absent' | 'legacy-resource-blocked' | 'legacy-resource-authorized-elsewhere' | 'legacy-resource-adopted-elsewhere' | 'service-absent' | 'binding-exists' | 'successor-organization-mismatch' | 'successor-not-greenfield' | 'successor-owns-legacy-resource';
115
138
  /** The named refusal of `adoptCorestoreLegacyResources`, sent as `TypedResponseError.errorData`. */
116
139
  export interface ICorestoreLegacyAdoptionErrorData {
117
140
  code: TCorestoreLegacyAdoptionRefusal;
@@ -136,11 +159,15 @@ export declare const validateClusterCorestoreLegacyResourceInventory: (valueArg:
136
159
  * reads of an unchanged Corestore agree. Throws for an invalid or unreachable inventory.
137
160
  */
138
161
  export declare const computeClusterCorestoreLegacyResourceInventorySha256: (inventoryArg: TClusterCorestoreLegacyResourceInventory) => Promise<string>;
139
- /** Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability. */
162
+ /**
163
+ * Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability,
164
+ * and no service capability adopting twice, whether as legacy owner or as successor.
165
+ */
140
166
  export declare const validateCorestoreLegacyResourceSelections: (valueArg: unknown, pathArg?: string) => string[];
141
167
  /**
142
168
  * Validates an adoption plan by the rules Corestore's migration applies: a non-empty array of at
143
- * most 4096 exact `{ serviceId, capability, bindingId }` entries, canonical identifiers, and no
169
+ * most 4096 exact `{ serviceId, capability, bindingId }` entries, each with `successorServiceId`
170
+ * when it names another service, canonical identifiers, and no legacy service capability, adopting
144
171
  * service capability or binding id twice. Order is free.
145
172
  */
146
173
  export declare const validateCorestoreLegacyResourceAdoptionPlan: (valueArg: unknown, pathArg?: string) => string[];
@@ -157,21 +184,25 @@ export interface ICorestoreLegacyAdoptionBindingView {
157
184
  nodeId: string;
158
185
  resourceName: string;
159
186
  inventorySha256: string;
187
+ legacyServiceId?: string;
160
188
  };
161
189
  }
162
190
  /**
163
191
  * Content check of one adopting binding against the inventory it was adopted at, and the one rule
164
192
  * that lets a binding carry a legacy bucket name: the binding names this node, this inventory
165
- * digest and the legacy resource's name; the resource is unadopted without a blocker or authorized
166
- * for exactly this binding; an adopted bucket's `objectstorageBucketName` is the legacy bucket and
167
- * its retention intent the legacy intent exactly, absent when the legacy bucket has none; a
168
- * database binding carries neither. Whether the digest is current is the caller's to check.
193
+ * digest and the legacy resource's name; the resource belongs to `legacyServiceId` when the binding
194
+ * names one, and then its own service owns no legacy resource of the capability, otherwise to its
195
+ * own service; the resource is unadopted without a blocker or authorized for exactly this binding;
196
+ * an adopted bucket's `objectstorageBucketName` is the legacy bucket and its retention intent the
197
+ * legacy intent exactly, absent when the legacy bucket has none; a database binding carries
198
+ * neither. Whether the digest is current is the caller's to check.
169
199
  */
170
200
  export declare const validatePlatformBindingCorestoreLegacyAdoption: (bindingArg: ICorestoreLegacyAdoptionBindingView, inventoryArg: TClusterCorestoreLegacyResourceInventory, inventorySha256Arg: string, pathArg?: string) => string[];
171
201
  /**
172
- * The plan for every adopting binding, sorted by service then capability, in the exact entry shape
173
- * Corestore's migration reads. Throws unless every binding adopts a legacy resource and the result
174
- * is a valid plan.
202
+ * The plan for every adopting binding, sorted by legacy service then capability, in the exact entry
203
+ * shape Corestore's migration reads: a binding adopting another service's resource names that
204
+ * service as `serviceId` and its own as `successorServiceId`. Throws unless every binding adopts a
205
+ * legacy resource and the result is a valid plan.
175
206
  */
176
207
  export declare const createCorestoreLegacyResourceAdoptionPlan: (bindingsArg: readonly ICorestoreLegacyAdoptionBindingView[]) => ICorestoreLegacyResourceAdoptionPlanEntry[];
177
208
  /**
@@ -164,7 +164,24 @@ export const computeClusterCorestoreLegacyResourceInventorySha256 = async (inven
164
164
  }, failDigest, 'corestore legacy resource inventory'), failDigest);
165
165
  };
166
166
  const selectionKey = (entryArg) => `${entryArg.serviceId}\u0000${entryArg.capability}`;
167
- /** Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability. */
167
+ /** The service capability whose binding adopts the entry's resource: the successor's, or the owner's. */
168
+ const adoptingKey = (entryArg) => selectionKey({ serviceId: entryArg.successorServiceId ?? entryArg.serviceId, capability: entryArg.capability });
169
+ /**
170
+ * Whether an entry has exactly `baseKeysArg`, and `successorServiceId` at most: `shape` when not,
171
+ * `successor` when its successor is not a canonical identifier other than its `serviceId`.
172
+ */
173
+ const successorShape = (entryArg, baseKeysArg) => {
174
+ if (!hasExactKeys(entryArg, baseKeysArg, ['successorServiceId']))
175
+ return 'shape';
176
+ return !Object.keys(entryArg).includes('successorServiceId')
177
+ || (isIdentifier(entryArg.successorServiceId) && entryArg.successorServiceId !== entryArg.serviceId)
178
+ ? 'exact'
179
+ : 'successor';
180
+ };
181
+ /**
182
+ * Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability,
183
+ * and no service capability adopting twice, whether as legacy owner or as successor.
184
+ */
168
185
  export const validateCorestoreLegacyResourceSelections = (valueArg, pathArg = 'corestore legacy resource selection') => {
169
186
  if (!Array.isArray(valueArg) || valueArg.length < 1
170
187
  || valueArg.length > corestoreLegacyAdoptionContract.maximumPlanEntries) {
@@ -172,23 +189,35 @@ export const validateCorestoreLegacyResourceSelections = (valueArg, pathArg = 'c
172
189
  }
173
190
  const errors = [];
174
191
  let previous;
192
+ const adopting = new Set();
175
193
  for (const [index, entry] of valueArg.entries()) {
176
- if (!isPlainRecord(entry) || !hasExactKeys(entry, ['serviceId', 'capability'])
177
- || !isIdentifier(entry.serviceId) || !isCapability(entry.capability)) {
194
+ const shape = isPlainRecord(entry) ? successorShape(entry, ['serviceId', 'capability']) : 'shape';
195
+ if (shape === 'shape' || !isIdentifier(entry.serviceId)
196
+ || !isCapability(entry.capability)) {
178
197
  errors.push(`${pathArg}[${index}] must be an exact { serviceId, capability }`);
179
198
  continue;
180
199
  }
181
- const key = selectionKey(entry);
200
+ if (shape === 'successor') {
201
+ errors.push(`${pathArg}[${index}] successorServiceId must name another service`);
202
+ continue;
203
+ }
204
+ const selection = entry;
205
+ const key = selectionKey(selection);
182
206
  if (previous !== undefined && compareWireTokens(previous, key) >= 0) {
183
207
  errors.push(`${pathArg} must be sorted by serviceId then capability without repeats`);
184
208
  }
185
209
  previous = key;
210
+ if (adopting.has(adoptingKey(selection))) {
211
+ errors.push(`${pathArg}[${index}] adopts into a service capability another entry adopts into`);
212
+ }
213
+ adopting.add(adoptingKey(selection));
186
214
  }
187
215
  return errors;
188
216
  };
189
217
  /**
190
218
  * Validates an adoption plan by the rules Corestore's migration applies: a non-empty array of at
191
- * most 4096 exact `{ serviceId, capability, bindingId }` entries, canonical identifiers, and no
219
+ * most 4096 exact `{ serviceId, capability, bindingId }` entries, each with `successorServiceId`
220
+ * when it names another service, canonical identifiers, and no legacy service capability, adopting
192
221
  * service capability or binding id twice. Order is free.
193
222
  */
194
223
  export const validateCorestoreLegacyResourceAdoptionPlan = (valueArg, pathArg = 'adoption plan') => {
@@ -198,29 +227,44 @@ export const validateCorestoreLegacyResourceAdoptionPlan = (valueArg, pathArg =
198
227
  }
199
228
  const errors = [];
200
229
  const serviceCapabilities = new Set();
230
+ const adoptingCapabilities = new Set();
201
231
  const bindingIds = new Set();
202
232
  for (const [index, entry] of valueArg.entries()) {
203
- if (!isPlainRecord(entry) || !hasExactKeys(entry, ['serviceId', 'capability', 'bindingId'])
204
- || !isIdentifier(entry.serviceId) || !isIdentifier(entry.bindingId) || !isCapability(entry.capability)) {
233
+ const shape = isPlainRecord(entry) ? successorShape(entry, ['serviceId', 'capability', 'bindingId']) : 'shape';
234
+ const record = entry;
235
+ if (shape === 'shape' || !isIdentifier(record.serviceId) || !isIdentifier(record.bindingId)
236
+ || !isCapability(record.capability)) {
205
237
  errors.push(`${pathArg} entry ${index} must be an exact { serviceId, capability, bindingId }`);
206
238
  continue;
207
239
  }
208
- const serviceCapability = selectionKey(entry);
209
- if (serviceCapabilities.has(serviceCapability) || bindingIds.has(entry.bindingId)) {
240
+ if (shape === 'successor') {
241
+ errors.push(`${pathArg} entry ${index} successorServiceId must name another service`);
242
+ continue;
243
+ }
244
+ const planEntry = entry;
245
+ const serviceCapability = selectionKey(planEntry);
246
+ const adoptingCapability = adoptingKey(planEntry);
247
+ if (serviceCapabilities.has(serviceCapability) || adoptingCapabilities.has(adoptingCapability)
248
+ || bindingIds.has(planEntry.bindingId)) {
210
249
  errors.push(`${pathArg} entry ${index} repeats a service capability or binding id`);
211
250
  }
212
251
  serviceCapabilities.add(serviceCapability);
213
- bindingIds.add(entry.bindingId);
252
+ adoptingCapabilities.add(adoptingCapability);
253
+ bindingIds.add(planEntry.bindingId);
214
254
  }
215
255
  return errors;
216
256
  };
257
+ /** The service that owns the legacy resource a binding adopts: its `legacyServiceId`, else its own. */
258
+ const legacyOwnerOf = (bindingArg) => bindingArg.corestoreLegacyAdoption?.legacyServiceId ?? bindingArg.serviceId;
217
259
  /**
218
260
  * Content check of one adopting binding against the inventory it was adopted at, and the one rule
219
261
  * that lets a binding carry a legacy bucket name: the binding names this node, this inventory
220
- * digest and the legacy resource's name; the resource is unadopted without a blocker or authorized
221
- * for exactly this binding; an adopted bucket's `objectstorageBucketName` is the legacy bucket and
222
- * its retention intent the legacy intent exactly, absent when the legacy bucket has none; a
223
- * database binding carries neither. Whether the digest is current is the caller's to check.
262
+ * digest and the legacy resource's name; the resource belongs to `legacyServiceId` when the binding
263
+ * names one, and then its own service owns no legacy resource of the capability, otherwise to its
264
+ * own service; the resource is unadopted without a blocker or authorized for exactly this binding;
265
+ * an adopted bucket's `objectstorageBucketName` is the legacy bucket and its retention intent the
266
+ * legacy intent exactly, absent when the legacy bucket has none; a database binding carries
267
+ * neither. Whether the digest is current is the caller's to check.
224
268
  */
225
269
  export const validatePlatformBindingCorestoreLegacyAdoption = (bindingArg, inventoryArg, inventorySha256Arg, pathArg = 'platform binding corestoreLegacyAdoption') => {
226
270
  if (validateClusterCorestoreLegacyResourceInventory(inventoryArg).length > 0 || inventoryArg.reachable !== true
@@ -228,18 +272,29 @@ export const validatePlatformBindingCorestoreLegacyAdoption = (bindingArg, inven
228
272
  return [`${pathArg} needs a valid reachable inventory and its digest`];
229
273
  }
230
274
  const adoption = bindingArg.corestoreLegacyAdoption;
231
- if (!isPlainRecord(adoption) || !hasExactKeys(adoption, ['nodeId', 'resourceName', 'inventorySha256'])) {
275
+ if (!isPlainRecord(adoption)
276
+ || !hasExactKeys(adoption, ['nodeId', 'resourceName', 'inventorySha256'], ['legacyServiceId'])) {
232
277
  return [`${pathArg} must use its exact schema`];
233
278
  }
279
+ if (Object.keys(adoption).includes('legacyServiceId')
280
+ && (!isIdentifier(adoption.legacyServiceId) || adoption.legacyServiceId === bindingArg.serviceId)) {
281
+ return [`${pathArg} legacyServiceId must name another service than the binding's`];
282
+ }
234
283
  if (adoption.nodeId !== inventoryArg.nodeId || adoption.inventorySha256 !== inventorySha256Arg) {
235
284
  return [`${pathArg} must name the inventory's node and digest`];
236
285
  }
237
286
  if (!isCapability(bindingArg.capability))
238
287
  return [`${pathArg} needs a database or objectstorage binding`];
239
- const resource = inventoryArg.services.find((serviceArg) => serviceArg.serviceId === bindingArg.serviceId)
288
+ const resourceOf = (serviceIdArg) => inventoryArg.services
289
+ .find((serviceArg) => serviceArg.serviceId === serviceIdArg)
240
290
  ?.resources.find((resourceArg) => resourceArg.capability === bindingArg.capability);
291
+ const legacyOwner = legacyOwnerOf(bindingArg);
292
+ const resource = resourceOf(legacyOwner);
241
293
  if (!resource)
242
294
  return [`${pathArg} names no legacy resource of the service and capability`];
295
+ if (legacyOwner !== bindingArg.serviceId && resourceOf(bindingArg.serviceId)) {
296
+ return [`${pathArg} names a successor that owns a legacy resource of the capability itself`];
297
+ }
243
298
  const errors = [];
244
299
  const legacyName = resource.capability === 'database' ? resource.databaseName : resource.bucketName;
245
300
  if (adoption.resourceName !== legacyName)
@@ -264,16 +319,25 @@ export const validatePlatformBindingCorestoreLegacyAdoption = (bindingArg, inven
264
319
  return errors;
265
320
  };
266
321
  /**
267
- * The plan for every adopting binding, sorted by service then capability, in the exact entry shape
268
- * Corestore's migration reads. Throws unless every binding adopts a legacy resource and the result
269
- * is a valid plan.
322
+ * The plan for every adopting binding, sorted by legacy service then capability, in the exact entry
323
+ * shape Corestore's migration reads: a binding adopting another service's resource names that
324
+ * service as `serviceId` and its own as `successorServiceId`. Throws unless every binding adopts a
325
+ * legacy resource and the result is a valid plan.
270
326
  */
271
327
  export const createCorestoreLegacyResourceAdoptionPlan = (bindingsArg) => {
272
328
  const plan = bindingsArg.map((bindingArg) => {
273
329
  if (bindingArg.corestoreLegacyAdoption === undefined || !isCapability(bindingArg.capability)) {
274
330
  throw new Error(`binding ${bindingArg.id} adopts no legacy Corestore resource`);
275
331
  }
276
- return { serviceId: bindingArg.serviceId, capability: bindingArg.capability, bindingId: bindingArg.id };
332
+ const legacyServiceId = bindingArg.corestoreLegacyAdoption.legacyServiceId;
333
+ return legacyServiceId === undefined
334
+ ? { serviceId: bindingArg.serviceId, capability: bindingArg.capability, bindingId: bindingArg.id }
335
+ : {
336
+ serviceId: legacyServiceId,
337
+ capability: bindingArg.capability,
338
+ bindingId: bindingArg.id,
339
+ successorServiceId: bindingArg.serviceId,
340
+ };
277
341
  }).sort((leftArg, rightArg) => compareWireTokens(selectionKey(leftArg), selectionKey(rightArg)));
278
342
  const errors = validateCorestoreLegacyResourceAdoptionPlan(plan);
279
343
  if (errors.length > 0)
@@ -289,4 +353,4 @@ export const readCorestoreLegacyAdoptionRefusal = (statusCodeArg, bodyArg) => (s
289
353
  && platformBindingStatusReasons.includes(bodyArg.code)
290
354
  ? bodyArg.code
291
355
  : null);
292
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZXN0b3JlbGVnYWN5YWRvcHRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2NvcmVzdG9yZWxlZ2FjeWFkb3B0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFDTCxrQ0FBa0MsRUFDbEMsb0NBQW9DLEdBQ3JDLE1BQU0sdUNBQXVDLENBQUM7QUFDL0MsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFdkYsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEUsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixpQkFBaUIsRUFDakIsNEJBQTRCLEdBQzdCLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMzRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFzSS9ELE1BQU0sQ0FBQyxNQUFNLCtCQUErQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDM0QsZ0dBQWdHO0lBQ2hHLGFBQWEsRUFBRSwyQkFBMkI7SUFDMUMsa0ZBQWtGO0lBQ2xGLGtCQUFrQixFQUFFLElBQUk7SUFDeEIsZUFBZSxFQUFFLElBQUk7SUFDckIsaUJBQWlCLEVBQUUsR0FBRztJQUN0QixZQUFZLEVBQUUsdUNBQXVDO0NBQzdDLENBQUMsQ0FBQztBQUVaLE1BQU0saUJBQWlCLEdBQUcscUNBQXFDLENBQUM7QUFDaEUsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDO0FBQzNDLE1BQU0sUUFBUSxHQUErQztJQUMzRCxlQUFlLEVBQUUsOEJBQThCLEVBQUUsa0JBQWtCLEVBQUUsd0JBQXdCO0NBQzlGLENBQUM7QUFFRixNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWlCLEVBQXNCLEVBQUUsQ0FBQyxDQUM5RCxPQUFPLFFBQVEsS0FBSyxRQUFRLElBQUksaUJBQWlCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUNqRSxDQUFDO0FBRUYsTUFBTSxZQUFZLEdBQUcsQ0FBQyxRQUFpQixFQUFzQixFQUFFLENBQUMsQ0FDOUQsT0FBTyxRQUFRLEtBQUssUUFBUTtPQUN6QixRQUFRLENBQUMsTUFBTSxJQUFJLCtCQUErQixDQUFDLGlCQUFpQjtPQUNwRSxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQ3ZDLENBQUM7QUFFRixNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWlCLEVBQTBDLEVBQUUsQ0FBQyxDQUNsRixRQUFRLEtBQUssVUFBVSxJQUFJLFFBQVEsS0FBSyxlQUFlLENBQ3hELENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUFHLENBQ3ZCLFFBQWlCLEVBQUUsYUFBeUMsRUFBRSxPQUFlLEVBQ25FLEVBQUU7SUFDWixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQztRQUFFLE9BQU8sQ0FBQyxHQUFHLE9BQU8sNEJBQTRCLENBQUMsQ0FBQztJQUM5RSxJQUFJLFFBQVEsQ0FBQyxLQUFLLEtBQUssV0FBVyxFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFBRSxPQUFPLENBQUMsR0FBRyxPQUFPLDRCQUE0QixDQUFDLENBQUM7UUFDbkcsSUFBSSxRQUFRLENBQUMsT0FBTyxLQUFLLElBQUksSUFBSSxDQUFFLFFBQStCLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzlGLE9BQU8sQ0FBQyxHQUFHLE9BQU8sMENBQTBDLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsT0FBTyxRQUFRLENBQUMsT0FBTyxLQUFLLHdCQUF3QixJQUFJLGFBQWEsS0FBSyxlQUFlO1lBQ3ZGLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxvREFBb0QsQ0FBQztZQUNsRSxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ1QsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLEtBQUssS0FBSyxZQUFZLEVBQUUsQ0FBQztRQUNwQyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDLE9BQU8sRUFBRSxXQUFXLENBQUMsQ0FBQztZQUFFLE9BQU8sQ0FBQyxHQUFHLE9BQU8sNEJBQTRCLENBQUMsQ0FBQztRQUNyRyxPQUFPLFlBQVksQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLE9BQU8sMkNBQTJDLENBQUMsQ0FBQztJQUN6RyxDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsT0FBTyx3Q0FBd0MsQ0FBQyxDQUFDO0FBQzlELENBQUMsQ0FBQztBQUVGLHdGQUF3RjtBQUN4RixNQUFNLFdBQVcsR0FBRyxDQUFDLFdBQW9CLEVBQVcsRUFBRSxDQUFDLENBQ3JELGFBQWEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLEtBQUssWUFBWSxJQUFJLFdBQVcsQ0FBQyxPQUFPLEtBQUssSUFBSSxDQUFDLENBQ25HLENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUFHLENBQUMsUUFBaUIsRUFBRSxPQUFlLEVBQVksRUFBRTtJQUN4RSxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQztRQUFFLE9BQU8sQ0FBQyxHQUFHLE9BQU8sNEJBQTRCLENBQUMsQ0FBQztJQUM5RSxJQUFJLFFBQVEsQ0FBQyxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDdkMsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxZQUFZLEVBQUUsY0FBYyxFQUFFLFVBQVUsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUN4RSxPQUFPLENBQUMsR0FBRyxPQUFPLDRCQUE0QixDQUFDLENBQUM7UUFDbEQsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUFHLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxXQUFXLENBQUMsQ0FBQztRQUN0RixJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUM7WUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ2xILE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFDRCxJQUFJLFFBQVEsQ0FBQyxVQUFVLEtBQUssZUFBZSxFQUFFLENBQUM7UUFDNUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxZQUFZLEVBQUUsWUFBWSxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQyxFQUFFLENBQUM7WUFDbkYsT0FBTyxDQUFDLEdBQUcsT0FBTyw0QkFBNEIsQ0FBQyxDQUFDO1FBQ2xELENBQUM7UUFDRCxNQUFNLE1BQU0sR0FBRyxnQkFBZ0IsQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLGVBQWUsRUFBRSxHQUFHLE9BQU8sV0FBVyxDQUFDLENBQUM7UUFDM0YsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUN2QyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyw4Q0FBOEMsQ0FBQyxDQUFDO1FBQ3hFLENBQUM7YUFBTSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLFdBQVcsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNqRSwyRkFBMkY7WUFDM0YsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLHVDQUF1QyxDQUFDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsR0FBRyxPQUFPLGFBQWEsQ0FBQyxDQUFDLENBQUM7UUFDeEcsQ0FBQztRQUNELElBQUksUUFBUSxDQUFDLFNBQVMsS0FBSyxJQUFJLEVBQUUsQ0FBQztZQUNoQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsb0NBQW9DLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxHQUFHLE9BQU8sWUFBWSxDQUFDLENBQUMsQ0FBQztRQUNuRyxDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUNELE9BQU8sQ0FBQyxHQUFHLE9BQU8sK0NBQStDLENBQUMsQ0FBQztBQUNyRSxDQUFDLENBQUM7QUFFRixNQUFNLGdCQUFnQixHQUFHLENBQUMsUUFBaUIsRUFBRSxPQUFlLEVBQVksRUFBRTtJQUN4RSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxRQUFRLENBQUMsTUFBTSxHQUFHLCtCQUErQixDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ2xHLE9BQU8sQ0FBQyxHQUFHLE9BQU8sMEJBQTBCLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBQ0QsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBQzVCLElBQUksaUJBQXFDLENBQUM7SUFDMUMsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxJQUFJLFFBQVEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1FBQ2xELE1BQU0sV0FBVyxHQUFHLEdBQUcsT0FBTyxJQUFJLEtBQUssR0FBRyxDQUFDO1FBQzNDLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUMsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUNsRixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsV0FBVyw0QkFBNEIsQ0FBQyxDQUFDO1lBQ3hELFNBQVM7UUFDWCxDQUFDO1FBQ0QsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUNyQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsV0FBVywyQ0FBMkMsQ0FBQyxDQUFDO1FBQ3pFLENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxpQkFBaUIsS0FBSyxTQUFTLElBQUksaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNwRyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyw4Q0FBOEMsQ0FBQyxDQUFDO1lBQ3hFLENBQUM7WUFDRCxpQkFBaUIsR0FBRyxPQUFPLENBQUMsU0FBUyxDQUFDO1FBQ3hDLENBQUM7UUFDRCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxXQUFXLDJDQUEyQyxDQUFDLENBQUM7WUFDdkUsU0FBUztRQUNYLENBQUM7UUFDRCxLQUFLLE1BQU0sQ0FBQyxhQUFhLEVBQUUsUUFBUSxDQUFDLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3BFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsR0FBRyxXQUFXLGNBQWMsYUFBYSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzNGLENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsTUFBTSxLQUFLLENBQUM7ZUFDN0IsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLEtBQUssVUFBVTttQkFDckYsYUFBYSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsS0FBSyxlQUFlLENBQUMsRUFBRSxDQUFDO1lBQ25HLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxXQUFXLHFFQUFxRSxDQUFDLENBQUM7UUFDbkcsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRixzR0FBc0c7QUFDdEcsTUFBTSxDQUFDLE1BQU0sd0NBQXdDLEdBQUcsQ0FDdEQsUUFBaUIsRUFDakIsT0FBTyxHQUFHLHFDQUFxQyxFQUNyQyxFQUFFO0lBQ1osSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdEUsT0FBTyxDQUFDLEdBQUcsT0FBTyw0QkFBNEIsQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFDRCxPQUFPLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsR0FBRyxPQUFPLFdBQVcsQ0FBQyxDQUFDO0FBQ3BFLENBQUMsQ0FBQztBQUVGLGlGQUFpRjtBQUNqRixNQUFNLENBQUMsTUFBTSwrQ0FBK0MsR0FBRyxDQUM3RCxRQUFpQixFQUNqQixPQUFPLEdBQUcsNkNBQTZDLEVBQzdDLEVBQUU7SUFDWixJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQztRQUFFLE9BQU8sQ0FBQyxHQUFHLE9BQU8sNEJBQTRCLENBQUMsQ0FBQztJQUM5RSxNQUFNLFNBQVMsR0FBRyxRQUFRLENBQUMsU0FBUyxDQUFDO0lBQ3JDLElBQUksU0FBUyxLQUFLLElBQUk7UUFDcEIsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQzNFLENBQUMsQ0FBQyxTQUFTLEtBQUssS0FBSyxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLFdBQVcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN0RyxPQUFPLENBQUMsR0FBRyxPQUFPLDRCQUE0QixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUM7UUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTywyQkFBMkIsQ0FBQyxDQUFDO0lBQzFGLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsSUFBSyxRQUFRLENBQUMsU0FBb0IsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNwRixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxnREFBZ0QsQ0FBQyxDQUFDO0lBQzFFLENBQUM7SUFDRCxJQUFJLFNBQVMsS0FBSyxJQUFJLEVBQUUsQ0FBQztRQUN2QixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLFFBQVEsRUFBRSxHQUFHLE9BQU8sV0FBVyxDQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO1NBQU0sSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLDRCQUE0QixJQUFJLFFBQVEsQ0FBQyxTQUFTLEtBQUssdUJBQXVCLEVBQUUsQ0FBQztRQUNqSCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxxREFBcUQsQ0FBQyxDQUFDO0lBQy9FLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRixNQUFNLFVBQVUsR0FBRyxDQUFDLFNBQWlCLEVBQVMsRUFBRTtJQUM5QyxNQUFNLElBQUksS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQzdCLENBQUMsQ0FBQztBQUVGOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9EQUFvRCxHQUFHLEtBQUssRUFDdkUsWUFBc0QsRUFDckMsRUFBRTtJQUNuQixNQUFNLE1BQU0sR0FBRywrQ0FBK0MsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUM3RSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsSUFBSSxZQUFZLENBQUMsU0FBUyxLQUFLLElBQUk7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7SUFDdEcsT0FBTyw0QkFBNEIsQ0FBQyxzQkFBc0IsQ0FBQztRQUN6RCxNQUFNLEVBQUUsK0JBQStCLENBQUMsWUFBWTtRQUNwRCxNQUFNLEVBQUUsWUFBWSxDQUFDLE1BQU07UUFDM0IsUUFBUSxFQUFFLFlBQVksQ0FBQyxRQUFRO0tBQ2hDLEVBQUUsVUFBVSxFQUFFLHFDQUFxQyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7QUFDckUsQ0FBQyxDQUFDO0FBRUYsTUFBTSxZQUFZLEdBQUcsQ0FBQyxRQUFtRCxFQUFVLEVBQUUsQ0FDbkYsR0FBRyxRQUFRLENBQUMsU0FBUyxTQUFTLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztBQUV0RCx3R0FBd0c7QUFDeEcsTUFBTSxDQUFDLE1BQU0seUNBQXlDLEdBQUcsQ0FDdkQsUUFBaUIsRUFDakIsT0FBTyxHQUFHLHFDQUFxQyxFQUNyQyxFQUFFO0lBQ1osSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDO1dBQzlDLFFBQVEsQ0FBQyxNQUFNLEdBQUcsK0JBQStCLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxRSxPQUFPLENBQUMsR0FBRyxPQUFPLG9DQUFvQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixJQUFJLFFBQTRCLENBQUM7SUFDakMsS0FBSyxNQUFNLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxJQUFJLFFBQVEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1FBQ2hELElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxFQUFFLENBQUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxDQUFDO2VBQ3pFLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztZQUN2RSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxJQUFJLEtBQUssOENBQThDLENBQUMsQ0FBQztZQUMvRSxTQUFTO1FBQ1gsQ0FBQztRQUNELE1BQU0sR0FBRyxHQUFHLFlBQVksQ0FBQyxLQUFxRCxDQUFDLENBQUM7UUFDaEYsSUFBSSxRQUFRLEtBQUssU0FBUyxJQUFJLGlCQUFpQixDQUFDLFFBQVEsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUNwRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyw4REFBOEQsQ0FBQyxDQUFDO1FBQ3hGLENBQUM7UUFDRCxRQUFRLEdBQUcsR0FBRyxDQUFDO0lBQ2pCLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sMkNBQTJDLEdBQUcsQ0FDekQsUUFBaUIsRUFDakIsT0FBTyxHQUFHLGVBQWUsRUFDZixFQUFFO0lBQ1osSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDO1dBQ2hELFFBQVEsQ0FBQyxNQUFNLEdBQUcsK0JBQStCLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMxRSxPQUFPLENBQUMsR0FBRyxPQUFPLG9DQUFvQyxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFhLEVBQUUsQ0FBQztJQUM1QixNQUFNLG1CQUFtQixHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFDOUMsTUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUNyQyxLQUFLLE1BQU0sQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLElBQUksUUFBUSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUM7UUFDaEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxXQUFXLEVBQUUsWUFBWSxFQUFFLFdBQVcsQ0FBQyxDQUFDO2VBQ3RGLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDekcsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sVUFBVSxLQUFLLHdEQUF3RCxDQUFDLENBQUM7WUFDL0YsU0FBUztRQUNYLENBQUM7UUFDRCxNQUFNLGlCQUFpQixHQUFHLFlBQVksQ0FBQyxLQUFxRCxDQUFDLENBQUM7UUFDOUYsSUFBSSxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUMsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFtQixDQUFDLEVBQUUsQ0FBQztZQUM1RixNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsT0FBTyxVQUFVLEtBQUssNkNBQTZDLENBQUMsQ0FBQztRQUN0RixDQUFDO1FBQ0QsbUJBQW1CLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDM0MsVUFBVSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsU0FBbUIsQ0FBQyxDQUFDO0lBQzVDLENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQztBQUNoQixDQUFDLENBQUM7QUFZRjs7Ozs7OztHQU9HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sOENBQThDLEdBQUcsQ0FDNUQsVUFBK0MsRUFDL0MsWUFBc0QsRUFDdEQsa0JBQTBCLEVBQzFCLE9BQU8sR0FBRywwQ0FBMEMsRUFDMUMsRUFBRTtJQUNaLElBQUksK0NBQStDLENBQUMsWUFBWSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxZQUFZLENBQUMsU0FBUyxLQUFLLElBQUk7V0FDMUcsT0FBTyxrQkFBa0IsS0FBSyxRQUFRLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsa0JBQWtCLENBQUMsRUFBRSxDQUFDO1FBQzNGLE9BQU8sQ0FBQyxHQUFHLE9BQU8sbURBQW1ELENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBQ0QsTUFBTSxRQUFRLEdBQUcsVUFBVSxDQUFDLHVCQUF1QixDQUFDO0lBQ3BELElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxFQUFFLGNBQWMsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUN2RyxPQUFPLENBQUMsR0FBRyxPQUFPLDRCQUE0QixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxZQUFZLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxlQUFlLEtBQUssa0JBQWtCLEVBQUUsQ0FBQztRQUMvRixPQUFPLENBQUMsR0FBRyxPQUFPLDRDQUE0QyxDQUFDLENBQUM7SUFDbEUsQ0FBQztJQUNELElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQztRQUFFLE9BQU8sQ0FBQyxHQUFHLE9BQU8sNENBQTRDLENBQUMsQ0FBQztJQUMxRyxNQUFNLFFBQVEsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLFNBQVMsS0FBSyxVQUFVLENBQUMsU0FBUyxDQUFDO1FBQ3hHLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLFVBQVUsS0FBSyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdEYsSUFBSSxDQUFDLFFBQVE7UUFBRSxPQUFPLENBQUMsR0FBRyxPQUFPLHlEQUF5RCxDQUFDLENBQUM7SUFDNUYsTUFBTSxNQUFNLEdBQWEsRUFBRSxDQUFDO0lBQzVCLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxVQUFVLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDO0lBQ3BHLElBQUksUUFBUSxDQUFDLFlBQVksS0FBSyxVQUFVO1FBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sa0RBQWtELENBQUMsQ0FBQztJQUNwSCxJQUFJLFFBQVEsQ0FBQyxRQUFRLENBQUMsS0FBSyxLQUFLLFdBQVcsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxPQUFPLEtBQUssSUFBSTtRQUM5RSxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQ2xELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxPQUFPLHFFQUFxRSxDQUFDLENBQUM7SUFDL0YsQ0FBQztJQUNELElBQUksUUFBUSxDQUFDLFVBQVUsS0FBSyxlQUFlLEVBQUUsQ0FBQztRQUM1QyxJQUFJLFVBQVUsQ0FBQyx1QkFBdUIsS0FBSyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDL0QsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sb0RBQW9ELENBQUMsQ0FBQztRQUM5RSxDQUFDO1FBQ0QsSUFBSSxRQUFRLENBQUMsU0FBUyxLQUFLLElBQUk7WUFDN0IsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxzQkFBc0IsS0FBSyxTQUFTO1lBQ2pELENBQUMsQ0FBQyxDQUFDLGtDQUFrQyxDQUFDLFVBQVUsQ0FBQyxzQkFBc0IsRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDdkcsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sdURBQXVELENBQUMsQ0FBQztRQUNqRixDQUFDO0lBQ0gsQ0FBQztTQUFNLElBQUksVUFBVSxDQUFDLHVCQUF1QixLQUFLLFNBQVMsSUFBSSxVQUFVLENBQUMsc0JBQXNCLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDL0csTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8scURBQXFELENBQUMsQ0FBQztJQUMvRSxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQyxDQUFDO0FBRUY7Ozs7R0FJRztBQUNILE1BQU0sQ0FBQyxNQUFNLHlDQUF5QyxHQUFHLENBQ3ZELFdBQTJELEVBQ2QsRUFBRTtJQUMvQyxNQUFNLElBQUksR0FBRyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsVUFBVSxFQUFFLEVBQUU7UUFDMUMsSUFBSSxVQUFVLENBQUMsdUJBQXVCLEtBQUssU0FBUyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzdGLE1BQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxVQUFVLENBQUMsRUFBRSxzQ0FBc0MsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFDRCxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxVQUFVLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUUsQ0FBQztJQUMxRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLEVBQUUsWUFBWSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNqRyxNQUFNLE1BQU0sR0FBRywyQ0FBMkMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNqRSxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbEQsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sa0NBQWtDLEdBQUcsQ0FDaEQsYUFBcUIsRUFDckIsT0FBZ0IsRUFDcUIsRUFBRSxDQUFDLENBQ3hDLGFBQWEsS0FBSyxHQUFHLElBQUksYUFBYSxDQUFDLE9BQU8sQ0FBQyxJQUFJLE9BQU8sQ0FBQyxFQUFFLEtBQUssS0FBSztPQUNqRSw0QkFBbUQsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQztJQUM5RSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQW9DO0lBQzlDLENBQUMsQ0FBQyxJQUFJLENBQ1QsQ0FBQyJ9
356
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29yZXN0b3JlbGVnYWN5YWRvcHRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9kYXRhL2NvcmVzdG9yZWxlZ2FjeWFkb3B0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFDTCxrQ0FBa0MsRUFDbEMsb0NBQW9DLEdBQ3JDLE1BQU0sdUNBQXVDLENBQUM7QUFDL0MsT0FBTyxFQUFFLHVDQUF1QyxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFFdkYsT0FBTyxFQUFFLDRCQUE0QixFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEUsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixpQkFBaUIsRUFDakIsNEJBQTRCLEdBQzdCLE1BQU0sNkJBQTZCLENBQUM7QUFDckMsT0FBTyxFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUMzRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFpSy9ELE1BQU0sQ0FBQyxNQUFNLCtCQUErQixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDM0QsZ0dBQWdHO0lBQ2hHLGFBQWEsRUFBRSwyQkFBMkI7SUFDMUMsa0ZBQWtGO0lBQ2xGLGtCQUFrQixFQUFFLElBQUk7SUFDeEIsZUFBZSxFQUFFLElBQUk7SUFDckIsaUJBQWlCLEVBQUUsR0FBRztJQUN0QixZQUFZLEVBQUUsdUNBQXVDO0NBQzdDLENBQUMsQ0FBQztBQUVaLE1BQU0saUJBQWlCLEdBQUcscUNBQXFDLENBQUM7QUFDaEUsTUFBTSxvQkFBb0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM5QyxNQUFNLGlCQUFpQixHQUFHLGdCQUFnQixDQUFDO0FBQzNDLE1BQU0sUUFBUSxHQUErQztJQUMzRCxlQUFlLEVBQUUsOEJBQThCLEVBQUUsa0JBQWtCLEVBQUUsd0JBQXdCO0NBQzlGLENBQUM7QUFFRixNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWlCLEVBQXNCLEVBQUUsQ0FBQyxD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
@@ -62,14 +62,18 @@ export interface IPlatformServiceEndpoint {
62
62
  * the binding, and Cloudly refuses it (and `objectstorageBucketName`) on `upsertPlatformBinding`.
63
63
  * `nodeId` is the node whose Corestore holds the resource, so the binding is placed there and
64
64
  * nowhere else; `resourceName` is the legacy database or bucket name; `inventorySha256` is the
65
- * legacy inventory the adoption was checked against. An adopted bucket's
66
- * `objectstorageBucketName` is the legacy bucket and its `objectstorageRetention.intent` the legacy
67
- * intent exactly, or absent when the legacy bucket has none.
65
+ * legacy inventory the adoption was checked against; `legacyServiceId` is the service that owned the
66
+ * legacy resource when that is not the binding's own service (a successor adopting its
67
+ * predecessor's data), absent otherwise. An adopted bucket's `objectstorageBucketName` is the legacy
68
+ * bucket and its `objectstorageRetention.intent` the legacy intent exactly, or absent when the
69
+ * legacy bucket has none.
68
70
  */
69
71
  export interface IPlatformBindingCorestoreLegacyAdoption {
70
72
  nodeId: string;
71
73
  resourceName: string;
72
74
  inventorySha256: string;
75
+ /** The legacy resource's owner, when it is another service than the binding's; never its own. */
76
+ legacyServiceId?: string;
73
77
  }
74
78
  export interface IPlatformBinding {
75
79
  id: string;
@@ -171,8 +171,12 @@ export interface IReq_Any_Cloudly_GetCorestoreLegacyResources extends plugins.ty
171
171
  * Cloudly reads the node's legacy inventory again, requires `expectedInventorySha256`, and for
172
172
  * each selected resource creates the adopting binding in one transaction: enabled, placed on
173
173
  * `nodeId`, with `corestoreLegacyAdoption`, and for a bucket the legacy bucket name and retention
174
- * intent (`validatePlatformBindingCorestoreLegacyAdoption`). A resource whose adopting binding
175
- * already exists is answered unchanged. The response lists the adopting bindings and the plan
174
+ * intent (`validatePlatformBindingCorestoreLegacyAdoption`). A selection naming a
175
+ * `successorServiceId` creates the binding on that successor instead, with
176
+ * `corestoreLegacyAdoption.legacyServiceId` naming the legacy owner; the successor must exist, share
177
+ * the legacy owner's organization, be an immutable-deployment service, own no legacy resource of
178
+ * that capability and hold no other binding of it. A legacy resource is adopted by one service
179
+ * only. A resource whose adopting binding already exists is answered unchanged. The response lists the adopting bindings and the plan
176
180
  * (`createCorestoreLegacyResourceAdoptionPlan`) the operator hands to Corestore's offline
177
181
  * `legacy-resource-adoption` migration. Refusals travel as `ICorestoreLegacyAdoptionErrorData`.
178
182
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serve.zone/interfaces",
3
- "version": "32.33.0",
3
+ "version": "32.34.0",
4
4
  "private": false,
5
5
  "description": "Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.",
6
6
  "exports": {
package/readme.md CHANGED
@@ -3679,13 +3679,25 @@ Coreflow, all exported from `data` and `platform`:
3679
3679
  answer lists the bindings and the `plan`. Refusals travel as
3680
3680
  `ICorestoreLegacyAdoptionErrorData { code, retryable }`: `legacy-inventory-unreachable` (the only
3681
3681
  retryable one), `legacy-inventory-changed`, `legacy-resource-absent`, `legacy-resource-blocked`,
3682
- `legacy-resource-authorized-elsewhere`, `service-absent` and `binding-exists`.
3682
+ `legacy-resource-authorized-elsewhere`, `legacy-resource-adopted-elsewhere`, `service-absent`,
3683
+ `binding-exists`, `successor-organization-mismatch`, `successor-not-greenfield` and
3684
+ `successor-owns-legacy-resource`.
3685
+
3686
+ **Successor.** A selection entry may name `successorServiceId`, another service that replaces the
3687
+ legacy owner: a fresh immutable-deployment service of the same organization, created by its
3688
+ greenfield reserve, that takes over the legacy data. The adopting binding is then the successor's,
3689
+ and its `corestoreLegacyAdoption.legacyServiceId` names the legacy owner (present only when the
3690
+ owner is another service; never the binding's own). The successor must own no legacy resource of
3691
+ that capability and hold no other binding of it, and a legacy resource is adopted by one service
3692
+ only. The selection refuses two entries adopting into the same service capability.
3683
3693
  4. **Plan.** `ICorestoreLegacyResourceAdoptionPlanEntry` is exactly the
3684
3694
  `{ serviceId, capability, bindingId }` object Corestore's `legacy-resource-adoption` migration
3685
- reads. `validateCorestoreLegacyResourceAdoptionPlan` applies that migration's rules: a non-empty
3686
- array of at most 4096 exact entries, canonical identifiers, no service capability or binding id
3687
- twice, any order. `createCorestoreLegacyResourceAdoptionPlan(bindings)` builds it from the adopting
3688
- bindings, sorted by service then capability. The plan restates no legacy name or retention intent:
3695
+ reads, plus `successorServiceId` when the binding belongs to a successor; `serviceId` is always
3696
+ the legacy owner. `validateCorestoreLegacyResourceAdoptionPlan` applies that migration's rules: a
3697
+ non-empty array of at most 4096 exact entries, canonical identifiers, no legacy service capability,
3698
+ adopting service capability or binding id twice, any order.
3699
+ `createCorestoreLegacyResourceAdoptionPlan(bindings)` builds it from the adopting bindings, sorted
3700
+ by legacy service then capability. The plan restates no legacy name or retention intent:
3689
3701
  Corestore holds those itself, and the binding request that later reaches it carries the bucket and
3690
3702
  intent it compares.
3691
3703
  5. **Status.** Until the operator has run the migration, Corestore refuses the binding with a 409
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.33.0',
6
+ version: '32.34.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  }
@@ -29,6 +29,12 @@ import { isClusterNodeId } from '../private/nodeidentifier.js';
29
29
  * answers the plan (`ICorestoreLegacyResourceAdoptionPlanEntry[]`).
30
30
  * 3. The operator stops Corestore and runs its `legacy-resource-adoption` migration with that plan.
31
31
  * Until then Corestore refuses the binding, which reports `legacy-adoption-pending`.
32
+ *
33
+ * A resource is adopted by a binding of the service that owns it, or, when the selection names a
34
+ * `successorServiceId`, by a binding of that successor: a fresh service of the same organization
35
+ * that replaces the legacy one and takes over its data. The successor's binding records the legacy
36
+ * owner as `corestoreLegacyAdoption.legacyServiceId`, and the plan entry carries the successor, so
37
+ * Corestore moves the resource from the legacy owner's manifest entry to the successor's binding.
32
38
  */
33
39
 
34
40
  export type TCorestoreLegacyCapability = 'database' | 'objectstorage';
@@ -100,21 +106,30 @@ export type TClusterCorestoreLegacyResourceInventory =
100
106
  errorCode: 'CORESTORE_ENDPOINT_UNKNOWN' | 'CORESTORE_UNREACHABLE';
101
107
  };
102
108
 
103
- /** One resource an administrator selects for adoption. */
109
+ /**
110
+ * One resource an administrator selects for adoption: the legacy resource `serviceId` owns of
111
+ * `capability`. Without `successorServiceId` a binding of `serviceId` adopts it; with it, a binding of
112
+ * that other service does, which must be a greenfield service of the same organization.
113
+ */
104
114
  export interface ICorestoreLegacyResourceSelection {
105
115
  serviceId: string;
106
116
  capability: TCorestoreLegacyCapability;
117
+ /** The service whose binding adopts the resource, when it is not `serviceId`; never `serviceId`. */
118
+ successorServiceId?: string;
107
119
  }
108
120
 
109
121
  /**
110
122
  * One entry of Corestore's offline adoption plan, exactly the object its
111
- * `legacy-resource-adoption` migration reads: the service, the capability and the binding that may
112
- * adopt its legacy resource. The legacy identity is Corestore's own and is not restated here.
123
+ * `legacy-resource-adoption` migration reads: the service that owns the legacy resource, the
124
+ * capability, the binding that may adopt it and, when that binding belongs to another service, that
125
+ * successor service. The legacy identity is Corestore's own and is not restated here.
113
126
  */
114
127
  export interface ICorestoreLegacyResourceAdoptionPlanEntry {
115
128
  serviceId: string;
116
129
  capability: TCorestoreLegacyCapability;
117
130
  bindingId: string;
131
+ /** The service `bindingId` belongs to, when it is not `serviceId`; never `serviceId`. */
132
+ successorServiceId?: string;
118
133
  }
119
134
 
120
135
  /**
@@ -126,9 +141,17 @@ export interface ICorestoreLegacyResourceAdoptionPlanEntry {
126
141
  * - `legacy-resource-blocked`: a selected resource is unadopted with a blocker;
127
142
  * - `legacy-resource-authorized-elsewhere`: a selected resource is authorized for a binding Cloudly
128
143
  * does not hold as that resource's adoption;
129
- * - `service-absent`: Cloudly has no such service;
130
- * - `binding-exists`: the service already has a binding of that capability that adopts nothing,
131
- * or adopts another resource.
144
+ * - `legacy-resource-adopted-elsewhere`: Cloudly already holds a binding of another service as a
145
+ * selected resource's adoption;
146
+ * - `service-absent`: Cloudly has no such service, legacy owner or successor;
147
+ * - `binding-exists`: the adopting service already has a binding of that capability that adopts
148
+ * nothing, or adopts another resource;
149
+ * - `successor-organization-mismatch`: the successor belongs to another organization than the
150
+ * legacy owner, or either names none;
151
+ * - `successor-not-greenfield`: the successor is not an immutable-deployment service (it deploys on
152
+ * push, or does not require an immutable image);
153
+ * - `successor-owns-legacy-resource`: the successor owns a legacy resource of that capability
154
+ * itself, which Corestore would keep beside the adopted one.
132
155
  */
133
156
  export type TCorestoreLegacyAdoptionRefusal =
134
157
  | 'legacy-inventory-unreachable'
@@ -136,8 +159,12 @@ export type TCorestoreLegacyAdoptionRefusal =
136
159
  | 'legacy-resource-absent'
137
160
  | 'legacy-resource-blocked'
138
161
  | 'legacy-resource-authorized-elsewhere'
162
+ | 'legacy-resource-adopted-elsewhere'
139
163
  | 'service-absent'
140
- | 'binding-exists';
164
+ | 'binding-exists'
165
+ | 'successor-organization-mismatch'
166
+ | 'successor-not-greenfield'
167
+ | 'successor-owns-legacy-resource';
141
168
 
142
169
  /** The named refusal of `adoptCorestoreLegacyResources`, sent as `TypedResponseError.errorData`. */
143
170
  export interface ICorestoreLegacyAdoptionErrorData {
@@ -327,7 +354,29 @@ export const computeClusterCorestoreLegacyResourceInventorySha256 = async (
327
354
  const selectionKey = (entryArg: { serviceId: string; capability: string }): string =>
328
355
  `${entryArg.serviceId}\u0000${entryArg.capability}`;
329
356
 
330
- /** Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability. */
357
+ /** The service capability whose binding adopts the entry's resource: the successor's, or the owner's. */
358
+ const adoptingKey = (entryArg: { serviceId: string; capability: string; successorServiceId?: string }): string =>
359
+ selectionKey({ serviceId: entryArg.successorServiceId ?? entryArg.serviceId, capability: entryArg.capability });
360
+
361
+ /**
362
+ * Whether an entry has exactly `baseKeysArg`, and `successorServiceId` at most: `shape` when not,
363
+ * `successor` when its successor is not a canonical identifier other than its `serviceId`.
364
+ */
365
+ const successorShape = (
366
+ entryArg: Record<string, unknown>,
367
+ baseKeysArg: readonly string[],
368
+ ): 'exact' | 'shape' | 'successor' => {
369
+ if (!hasExactKeys(entryArg, baseKeysArg, ['successorServiceId'])) return 'shape';
370
+ return !Object.keys(entryArg).includes('successorServiceId')
371
+ || (isIdentifier(entryArg.successorServiceId) && entryArg.successorServiceId !== entryArg.serviceId)
372
+ ? 'exact'
373
+ : 'successor';
374
+ };
375
+
376
+ /**
377
+ * Validates an administrator's selection: 1..4096 exact entries, sorted by service then capability,
378
+ * and no service capability adopting twice, whether as legacy owner or as successor.
379
+ */
331
380
  export const validateCorestoreLegacyResourceSelections = (
332
381
  valueArg: unknown,
333
382
  pathArg = 'corestore legacy resource selection',
@@ -338,24 +387,36 @@ export const validateCorestoreLegacyResourceSelections = (
338
387
  }
339
388
  const errors: string[] = [];
340
389
  let previous: string | undefined;
390
+ const adopting = new Set<string>();
341
391
  for (const [index, entry] of valueArg.entries()) {
342
- if (!isPlainRecord(entry) || !hasExactKeys(entry, ['serviceId', 'capability'])
343
- || !isIdentifier(entry.serviceId) || !isCapability(entry.capability)) {
392
+ const shape = isPlainRecord(entry) ? successorShape(entry, ['serviceId', 'capability']) : 'shape';
393
+ if (shape === 'shape' || !isIdentifier((entry as Record<string, unknown>).serviceId)
394
+ || !isCapability((entry as Record<string, unknown>).capability)) {
344
395
  errors.push(`${pathArg}[${index}] must be an exact { serviceId, capability }`);
345
396
  continue;
346
397
  }
347
- const key = selectionKey(entry as unknown as ICorestoreLegacyResourceSelection);
398
+ if (shape === 'successor') {
399
+ errors.push(`${pathArg}[${index}] successorServiceId must name another service`);
400
+ continue;
401
+ }
402
+ const selection = entry as ICorestoreLegacyResourceSelection;
403
+ const key = selectionKey(selection);
348
404
  if (previous !== undefined && compareWireTokens(previous, key) >= 0) {
349
405
  errors.push(`${pathArg} must be sorted by serviceId then capability without repeats`);
350
406
  }
351
407
  previous = key;
408
+ if (adopting.has(adoptingKey(selection))) {
409
+ errors.push(`${pathArg}[${index}] adopts into a service capability another entry adopts into`);
410
+ }
411
+ adopting.add(adoptingKey(selection));
352
412
  }
353
413
  return errors;
354
414
  };
355
415
 
356
416
  /**
357
417
  * Validates an adoption plan by the rules Corestore's migration applies: a non-empty array of at
358
- * most 4096 exact `{ serviceId, capability, bindingId }` entries, canonical identifiers, and no
418
+ * most 4096 exact `{ serviceId, capability, bindingId }` entries, each with `successorServiceId`
419
+ * when it names another service, canonical identifiers, and no legacy service capability, adopting
359
420
  * service capability or binding id twice. Order is free.
360
421
  */
361
422
  export const validateCorestoreLegacyResourceAdoptionPlan = (
@@ -368,19 +429,30 @@ export const validateCorestoreLegacyResourceAdoptionPlan = (
368
429
  }
369
430
  const errors: string[] = [];
370
431
  const serviceCapabilities = new Set<string>();
432
+ const adoptingCapabilities = new Set<string>();
371
433
  const bindingIds = new Set<string>();
372
434
  for (const [index, entry] of valueArg.entries()) {
373
- if (!isPlainRecord(entry) || !hasExactKeys(entry, ['serviceId', 'capability', 'bindingId'])
374
- || !isIdentifier(entry.serviceId) || !isIdentifier(entry.bindingId) || !isCapability(entry.capability)) {
435
+ const shape = isPlainRecord(entry) ? successorShape(entry, ['serviceId', 'capability', 'bindingId']) : 'shape';
436
+ const record = entry as Record<string, unknown>;
437
+ if (shape === 'shape' || !isIdentifier(record.serviceId) || !isIdentifier(record.bindingId)
438
+ || !isCapability(record.capability)) {
375
439
  errors.push(`${pathArg} entry ${index} must be an exact { serviceId, capability, bindingId }`);
376
440
  continue;
377
441
  }
378
- const serviceCapability = selectionKey(entry as unknown as ICorestoreLegacyResourceSelection);
379
- if (serviceCapabilities.has(serviceCapability) || bindingIds.has(entry.bindingId as string)) {
442
+ if (shape === 'successor') {
443
+ errors.push(`${pathArg} entry ${index} successorServiceId must name another service`);
444
+ continue;
445
+ }
446
+ const planEntry = entry as ICorestoreLegacyResourceAdoptionPlanEntry;
447
+ const serviceCapability = selectionKey(planEntry);
448
+ const adoptingCapability = adoptingKey(planEntry);
449
+ if (serviceCapabilities.has(serviceCapability) || adoptingCapabilities.has(adoptingCapability)
450
+ || bindingIds.has(planEntry.bindingId)) {
380
451
  errors.push(`${pathArg} entry ${index} repeats a service capability or binding id`);
381
452
  }
382
453
  serviceCapabilities.add(serviceCapability);
383
- bindingIds.add(entry.bindingId as string);
454
+ adoptingCapabilities.add(adoptingCapability);
455
+ bindingIds.add(planEntry.bindingId);
384
456
  }
385
457
  return errors;
386
458
  };
@@ -392,16 +464,27 @@ export interface ICorestoreLegacyAdoptionBindingView {
392
464
  capability: string;
393
465
  objectstorageBucketName?: string;
394
466
  objectstorageRetention?: { intent: IObjectStorageRetentionIntent };
395
- corestoreLegacyAdoption?: { nodeId: string; resourceName: string; inventorySha256: string };
467
+ corestoreLegacyAdoption?: {
468
+ nodeId: string;
469
+ resourceName: string;
470
+ inventorySha256: string;
471
+ legacyServiceId?: string;
472
+ };
396
473
  }
397
474
 
475
+ /** The service that owns the legacy resource a binding adopts: its `legacyServiceId`, else its own. */
476
+ const legacyOwnerOf = (bindingArg: ICorestoreLegacyAdoptionBindingView): string =>
477
+ bindingArg.corestoreLegacyAdoption?.legacyServiceId ?? bindingArg.serviceId;
478
+
398
479
  /**
399
480
  * Content check of one adopting binding against the inventory it was adopted at, and the one rule
400
481
  * that lets a binding carry a legacy bucket name: the binding names this node, this inventory
401
- * digest and the legacy resource's name; the resource is unadopted without a blocker or authorized
402
- * for exactly this binding; an adopted bucket's `objectstorageBucketName` is the legacy bucket and
403
- * its retention intent the legacy intent exactly, absent when the legacy bucket has none; a
404
- * database binding carries neither. Whether the digest is current is the caller's to check.
482
+ * digest and the legacy resource's name; the resource belongs to `legacyServiceId` when the binding
483
+ * names one, and then its own service owns no legacy resource of the capability, otherwise to its
484
+ * own service; the resource is unadopted without a blocker or authorized for exactly this binding;
485
+ * an adopted bucket's `objectstorageBucketName` is the legacy bucket and its retention intent the
486
+ * legacy intent exactly, absent when the legacy bucket has none; a database binding carries
487
+ * neither. Whether the digest is current is the caller's to check.
405
488
  */
406
489
  export const validatePlatformBindingCorestoreLegacyAdoption = (
407
490
  bindingArg: ICorestoreLegacyAdoptionBindingView,
@@ -414,16 +497,27 @@ export const validatePlatformBindingCorestoreLegacyAdoption = (
414
497
  return [`${pathArg} needs a valid reachable inventory and its digest`];
415
498
  }
416
499
  const adoption = bindingArg.corestoreLegacyAdoption;
417
- if (!isPlainRecord(adoption) || !hasExactKeys(adoption, ['nodeId', 'resourceName', 'inventorySha256'])) {
500
+ if (!isPlainRecord(adoption)
501
+ || !hasExactKeys(adoption, ['nodeId', 'resourceName', 'inventorySha256'], ['legacyServiceId'])) {
418
502
  return [`${pathArg} must use its exact schema`];
419
503
  }
504
+ if (Object.keys(adoption).includes('legacyServiceId')
505
+ && (!isIdentifier(adoption.legacyServiceId) || adoption.legacyServiceId === bindingArg.serviceId)) {
506
+ return [`${pathArg} legacyServiceId must name another service than the binding's`];
507
+ }
420
508
  if (adoption.nodeId !== inventoryArg.nodeId || adoption.inventorySha256 !== inventorySha256Arg) {
421
509
  return [`${pathArg} must name the inventory's node and digest`];
422
510
  }
423
511
  if (!isCapability(bindingArg.capability)) return [`${pathArg} needs a database or objectstorage binding`];
424
- const resource = inventoryArg.services.find((serviceArg) => serviceArg.serviceId === bindingArg.serviceId)
512
+ const resourceOf = (serviceIdArg: string) => inventoryArg.services
513
+ .find((serviceArg) => serviceArg.serviceId === serviceIdArg)
425
514
  ?.resources.find((resourceArg) => resourceArg.capability === bindingArg.capability);
515
+ const legacyOwner = legacyOwnerOf(bindingArg);
516
+ const resource = resourceOf(legacyOwner);
426
517
  if (!resource) return [`${pathArg} names no legacy resource of the service and capability`];
518
+ if (legacyOwner !== bindingArg.serviceId && resourceOf(bindingArg.serviceId)) {
519
+ return [`${pathArg} names a successor that owns a legacy resource of the capability itself`];
520
+ }
427
521
  const errors: string[] = [];
428
522
  const legacyName = resource.capability === 'database' ? resource.databaseName : resource.bucketName;
429
523
  if (adoption.resourceName !== legacyName) errors.push(`${pathArg} resourceName must be the legacy resource's name`);
@@ -447,18 +541,27 @@ export const validatePlatformBindingCorestoreLegacyAdoption = (
447
541
  };
448
542
 
449
543
  /**
450
- * The plan for every adopting binding, sorted by service then capability, in the exact entry shape
451
- * Corestore's migration reads. Throws unless every binding adopts a legacy resource and the result
452
- * is a valid plan.
544
+ * The plan for every adopting binding, sorted by legacy service then capability, in the exact entry
545
+ * shape Corestore's migration reads: a binding adopting another service's resource names that
546
+ * service as `serviceId` and its own as `successorServiceId`. Throws unless every binding adopts a
547
+ * legacy resource and the result is a valid plan.
453
548
  */
454
549
  export const createCorestoreLegacyResourceAdoptionPlan = (
455
550
  bindingsArg: readonly ICorestoreLegacyAdoptionBindingView[],
456
551
  ): ICorestoreLegacyResourceAdoptionPlanEntry[] => {
457
- const plan = bindingsArg.map((bindingArg) => {
552
+ const plan = bindingsArg.map((bindingArg): ICorestoreLegacyResourceAdoptionPlanEntry => {
458
553
  if (bindingArg.corestoreLegacyAdoption === undefined || !isCapability(bindingArg.capability)) {
459
554
  throw new Error(`binding ${bindingArg.id} adopts no legacy Corestore resource`);
460
555
  }
461
- return { serviceId: bindingArg.serviceId, capability: bindingArg.capability, bindingId: bindingArg.id };
556
+ const legacyServiceId = bindingArg.corestoreLegacyAdoption.legacyServiceId;
557
+ return legacyServiceId === undefined
558
+ ? { serviceId: bindingArg.serviceId, capability: bindingArg.capability, bindingId: bindingArg.id }
559
+ : {
560
+ serviceId: legacyServiceId,
561
+ capability: bindingArg.capability,
562
+ bindingId: bindingArg.id,
563
+ successorServiceId: bindingArg.serviceId,
564
+ };
462
565
  }).sort((leftArg, rightArg) => compareWireTokens(selectionKey(leftArg), selectionKey(rightArg)));
463
566
  const errors = validateCorestoreLegacyResourceAdoptionPlan(plan);
464
567
  if (errors.length > 0) throw new Error(errors[0]);
@@ -116,14 +116,18 @@ export interface IPlatformServiceEndpoint {
116
116
  * the binding, and Cloudly refuses it (and `objectstorageBucketName`) on `upsertPlatformBinding`.
117
117
  * `nodeId` is the node whose Corestore holds the resource, so the binding is placed there and
118
118
  * nowhere else; `resourceName` is the legacy database or bucket name; `inventorySha256` is the
119
- * legacy inventory the adoption was checked against. An adopted bucket's
120
- * `objectstorageBucketName` is the legacy bucket and its `objectstorageRetention.intent` the legacy
121
- * intent exactly, or absent when the legacy bucket has none.
119
+ * legacy inventory the adoption was checked against; `legacyServiceId` is the service that owned the
120
+ * legacy resource when that is not the binding's own service (a successor adopting its
121
+ * predecessor's data), absent otherwise. An adopted bucket's `objectstorageBucketName` is the legacy
122
+ * bucket and its `objectstorageRetention.intent` the legacy intent exactly, or absent when the
123
+ * legacy bucket has none.
122
124
  */
123
125
  export interface IPlatformBindingCorestoreLegacyAdoption {
124
126
  nodeId: string;
125
127
  resourceName: string;
126
128
  inventorySha256: string;
129
+ /** The legacy resource's owner, when it is another service than the binding's; never its own. */
130
+ legacyServiceId?: string;
127
131
  }
128
132
 
129
133
  export interface IPlatformBinding {
@@ -332,8 +332,12 @@ extends plugins.typedrequestInterfaces.implementsTR<
332
332
  * Cloudly reads the node's legacy inventory again, requires `expectedInventorySha256`, and for
333
333
  * each selected resource creates the adopting binding in one transaction: enabled, placed on
334
334
  * `nodeId`, with `corestoreLegacyAdoption`, and for a bucket the legacy bucket name and retention
335
- * intent (`validatePlatformBindingCorestoreLegacyAdoption`). A resource whose adopting binding
336
- * already exists is answered unchanged. The response lists the adopting bindings and the plan
335
+ * intent (`validatePlatformBindingCorestoreLegacyAdoption`). A selection naming a
336
+ * `successorServiceId` creates the binding on that successor instead, with
337
+ * `corestoreLegacyAdoption.legacyServiceId` naming the legacy owner; the successor must exist, share
338
+ * the legacy owner's organization, be an immutable-deployment service, own no legacy resource of
339
+ * that capability and hold no other binding of it. A legacy resource is adopted by one service
340
+ * only. A resource whose adopting binding already exists is answered unchanged. The response lists the adopting bindings and the plan
337
341
  * (`createCorestoreLegacyResourceAdoptionPlan`) the operator hands to Corestore's offline
338
342
  * `legacy-resource-adoption` migration. Refusals travel as `ICorestoreLegacyAdoptionErrorData`.
339
343
  */