@firestartr/cli 2.5.0-snapshot-2 → 2.5.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/build/index.js CHANGED
@@ -291270,6 +291270,27 @@ function definitions_getPluralFromKind(kind) {
291270
291270
  const plural = Object.keys(kindPluralMap).find((key) => kindPluralMap[key] === kind);
291271
291271
  return plural;
291272
291272
  }
291273
+ // ----------------------------------------------------
291274
+ // Operations, workitems and handlers definitions
291275
+ // ----------------------------------------------------
291276
+ /**
291277
+ * Helper to extract the canonical identity (metadata.uid) from a WorkItem or its item.
291278
+ *
291279
+ * Use this helper when you need a stable identity key for WorkItems, e.g. for
291280
+ * in-memory deferred-scheduling bookkeeping.
291281
+ *
291282
+ * Note: other subsystems may still use kind/namespace/name keys; this helper is
291283
+ * specifically intended for UID-based WorkItem identity.
291284
+ * Any future change to identity logic MUST be made here and nowhere else.
291285
+ *
291286
+ * Returns undefined if .metadata.uid is missing so scheduler/bookkeeping paths
291287
+ * can safely short-circuit instead of throwing and aborting an entire pass.
291288
+ */
291289
+ function getWorkItemIdentity(wi) {
291290
+ // Support either .item.metadata.uid or direct .metadata.uid for future extensibility
291291
+ const meta = wi.item && wi.item.metadata ? wi.item.metadata : wi.metadata;
291292
+ return meta && meta.uid ? meta.uid : undefined;
291293
+ }
291273
291294
  var OperationType;
291274
291295
  (function (OperationType) {
291275
291296
  OperationType["RENAMED"] = "RENAMED";
@@ -293513,6 +293534,134 @@ function fdummies_fWait(ms) {
293513
293534
  });
293514
293535
  }
293515
293536
 
293537
+ ;// CONCATENATED MODULE: ../operator/src/processItem.blocks.ts
293538
+ // processItem.blocks.ts
293539
+ // Responsible for all in-memory deferred-scheduling bookkeeping for blocked parent deletions.
293540
+ //
293541
+ // Always extract WorkItem identity for all in-memory maps and keys by calling
293542
+ // getWorkItemIdentity() from definitions.ts, and NOT by constructing your own key.
293543
+ // This ensures spec compliance and future maintainability.
293544
+ //
293545
+ // Does NOT detect "blocked" state (caller must supply outcome). Purely key/value scheduler-local state logic per spec.
293546
+
293547
+ // Only use getWorkItemIdentity(item) for identity bookkeeping and maps.
293548
+ // --- Config: Deferral Policy ---
293549
+ /**
293550
+ * Maximum number of blocked attempts allowed before an item is moved to the deferred segment.
293551
+ * An item becomes deferred once its blocked-attempt count exceeds this value.
293552
+ */
293553
+ const MAX_BLOCKED_ATTEMPTS_BEFORE_DEFER = 5;
293554
+ // Initial supported parent kind(s): extensible for future cases
293555
+ const SUPPORTED_PARENT_KINDS = new Set(['FirestartrGithubRepository']);
293556
+ // --- Bookkeeper Class ---
293557
+ /**
293558
+ * Encapsulates all deferred-scheduling bookkeeping state for one scheduler queue.
293559
+ * Instantiate once per queue (alongside processItemSlotsManager) inside loop().
293560
+ */
293561
+ class DeferredSchedulingBookkeeper {
293562
+ constructor() {
293563
+ this._blockedAttempts = new Map();
293564
+ this._deferredEntryOrder = new Map();
293565
+ this._deferredOrderCounter = 0;
293566
+ }
293567
+ // --- Applicability Logic ---
293568
+ /**
293569
+ * Returns true only for supported parent kinds AND only for deletion operations.
293570
+ * Per spec Definition 2: applicable when operation is MARKED_TO_DELETION,
293571
+ * or RETRY with metadata.deletionTimestamp set.
293572
+ */
293573
+ isDeferredSchedulingApplicable(item) {
293574
+ const kind = item.item && item.item.kind ? item.item.kind : item.kind;
293575
+ if (!SUPPORTED_PARENT_KINDS.has(kind))
293576
+ return false;
293577
+ const op = item.operation;
293578
+ if (op === OperationType.MARKED_TO_DELETION)
293579
+ return true;
293580
+ if (op === OperationType.RETRY && item.item?.metadata?.deletionTimestamp)
293581
+ return true;
293582
+ return false;
293583
+ }
293584
+ // --- Bookkeeping API ---
293585
+ /**
293586
+ * Increments block counter for item (only call when item has been detected as blocked).
293587
+ * Returns new value. Promotes item to deferred segment if threshold crossed.
293588
+ */
293589
+ incrementBlockedAttempt(item) {
293590
+ if (!this.isDeferredSchedulingApplicable(item))
293591
+ return 0;
293592
+ const id = getWorkItemIdentity(item);
293593
+ if (id === undefined)
293594
+ return 0;
293595
+ const prev = this._blockedAttempts.get(id) || 0;
293596
+ const next = prev + 1;
293597
+ this._blockedAttempts.set(id, next);
293598
+ if (next > MAX_BLOCKED_ATTEMPTS_BEFORE_DEFER &&
293599
+ !this._deferredEntryOrder.has(id)) {
293600
+ this._deferredEntryOrder.set(id, ++this._deferredOrderCounter);
293601
+ }
293602
+ return next;
293603
+ }
293604
+ getBlockedAttempts(item) {
293605
+ if (!this.isDeferredSchedulingApplicable(item))
293606
+ return 0;
293607
+ const id = getWorkItemIdentity(item);
293608
+ if (id === undefined)
293609
+ return 0;
293610
+ return this._blockedAttempts.get(id) || 0;
293611
+ }
293612
+ isDeferred(item) {
293613
+ if (!this.isDeferredSchedulingApplicable(item))
293614
+ return false;
293615
+ return this.getBlockedAttempts(item) > MAX_BLOCKED_ATTEMPTS_BEFORE_DEFER;
293616
+ }
293617
+ getDeferredOrder(item) {
293618
+ if (!this.isDeferredSchedulingApplicable(item))
293619
+ return undefined;
293620
+ const id = getWorkItemIdentity(item);
293621
+ if (id === undefined)
293622
+ return undefined;
293623
+ return this._deferredEntryOrder.get(id);
293624
+ }
293625
+ removeBookkeeping(item) {
293626
+ if (!this.isDeferredSchedulingApplicable(item))
293627
+ return;
293628
+ const id = getWorkItemIdentity(item);
293629
+ if (id === undefined)
293630
+ return;
293631
+ this._blockedAttempts.delete(id);
293632
+ this._deferredEntryOrder.delete(id);
293633
+ }
293634
+ // --- Queue Partitioning ---
293635
+ /**
293636
+ * Splits queue into non-deferred and deferred, preserving original order,
293637
+ * but sorts deferred by stable insertion order.
293638
+ */
293639
+ partitionQueueByDeferred(queue) {
293640
+ const nonDeferred = [];
293641
+ const deferred = [];
293642
+ for (const item of queue) {
293643
+ if (this.isDeferredSchedulingApplicable(item) && this.isDeferred(item)) {
293644
+ deferred.push(item);
293645
+ }
293646
+ else {
293647
+ nonDeferred.push(item);
293648
+ }
293649
+ }
293650
+ deferred.sort((a, b) => {
293651
+ const orderA = this.getDeferredOrder(a) || 0;
293652
+ const orderB = this.getDeferredOrder(b) || 0;
293653
+ return orderA - orderB;
293654
+ });
293655
+ return { nonDeferred, deferred };
293656
+ }
293657
+ // --- TESTING / DEBUG ---
293658
+ clearAllBookkeeping() {
293659
+ this._blockedAttempts.clear();
293660
+ this._deferredEntryOrder.clear();
293661
+ this._deferredOrderCounter = 0;
293662
+ }
293663
+ }
293664
+
293516
293665
  ;// CONCATENATED MODULE: ../operator/src/processItem.debug.ts
293517
293666
 
293518
293667
 
@@ -294003,12 +294152,12 @@ async function startCRStates(meter, kindList, namespace) {
294003
294152
 
294004
294153
 
294005
294154
 
294006
- function initProcessItemsSlots(nSlots, initMetrics = true) {
294155
+ function initProcessItemsSlots(nSlots, initMetrics = true, onWorkItemBlockedByHandler) {
294007
294156
  operator_src_logger.info(`Initializing ${nSlots} processing slots...`);
294008
- return new ProcessItemSlots(nSlots, initMetrics);
294157
+ return new ProcessItemSlots(nSlots, initMetrics, onWorkItemBlockedByHandler);
294009
294158
  }
294010
294159
  class ProcessItemSlots {
294011
- constructor(nSlots, initMetrics) {
294160
+ constructor(nSlots, initMetrics, onWorkItemBlockedByHandler) {
294012
294161
  this._guardRails = new GuardRails();
294013
294162
  // let's init the slots
294014
294163
  this._nSlots = nSlots;
@@ -294025,6 +294174,7 @@ class ProcessItemSlots {
294025
294174
  slot.actions = {
294026
294175
  blockItem: (item) => this._guardRails.block(item),
294027
294176
  unblockItem: (item) => this._guardRails.unblock(item),
294177
+ onWorkItemBlockedByHandler,
294028
294178
  };
294029
294179
  return slot;
294030
294180
  });
@@ -294135,6 +294285,9 @@ class ProcessItemSlot {
294135
294285
  if ('needsBlocking' in workItem.handler &&
294136
294286
  workItem.handler.needsBlocking(item, workItem.operation)) {
294137
294287
  operator_src_logger.debug(`Item ${item.kind}/${item.metadata.namespace} needs blocking`);
294288
+ // Fire-and-forget: the callback is synchronous bookkeeping only;
294289
+ // no async side effects are expected from this callback.
294290
+ this._actions?.onWorkItemBlockedByHandler?.(workItem);
294138
294291
  return;
294139
294292
  }
294140
294293
  workItem.workStatus = WorkStatus.PROCESSING;
@@ -294156,6 +294309,7 @@ class ProcessItemSlot {
294156
294309
 
294157
294310
 
294158
294311
 
294312
+
294159
294313
  const queue = [];
294160
294314
  const WEIGHTS = {
294161
294315
  RENAMED: 15,
@@ -294276,12 +294430,26 @@ async function processItem(workItem) {
294276
294430
  async function processItem_loop() {
294277
294431
  loopWorkItemDebug(queue);
294278
294432
  let podIsTerminating = false;
294279
- const processItemSlotsManager = initProcessItemsSlots(MAX_SLOTS);
294280
- const nextWorkItem = () => sortQueue(queue)
294281
- .filter((w) => !w.isBlocked &&
294282
- !w.isPicked &&
294283
- !processItemSlotsManager.isWorkItemBlocked(w))
294284
- .find((w) => w.workStatus === WorkStatus.PENDING);
294433
+ const deferredBookkeeper = new DeferredSchedulingBookkeeper();
294434
+ const processItemSlotsManager = initProcessItemsSlots(MAX_SLOTS, true, (w) => deferredBookkeeper.incrementBlockedAttempt(w));
294435
+ if (process.env.GARBAGE_QUEUE_COLLECTOR) {
294436
+ void workItemGarbageCollector(queue, deferredBookkeeper);
294437
+ }
294438
+ const nextWorkItem = () => {
294439
+ // First, sort the queue and partition it for deferred scheduling.
294440
+ const sorted = sortQueue(queue);
294441
+ const { nonDeferred, deferred } = deferredBookkeeper.partitionQueueByDeferred(sorted);
294442
+ // Helper for selection logic
294443
+ function pickEligible(arr) {
294444
+ return arr
294445
+ .filter((w) => !w.isBlocked &&
294446
+ !w.isPicked &&
294447
+ !processItemSlotsManager.isWorkItemBlocked(w))
294448
+ .find((w) => w.workStatus === WorkStatus.PENDING);
294449
+ }
294450
+ // Always prefer non-deferred, only defer if absolutely nothing eligible
294451
+ return pickEligible(nonDeferred) || pickEligible(deferred);
294452
+ };
294285
294453
  initSignalsHandler(new Map([['SIGTERM', () => (podIsTerminating = true)]]));
294286
294454
  operator_src_logger.info(`
294287
294455
  ------- Processor main loop started with a maximum of '${MAX_SLOTS}' concurrent slots to process items. -------
@@ -294358,24 +294526,23 @@ function processItem_wait(t = 2000) {
294358
294526
  * Periodically checks the queue for finished WorkItems and removes them
294359
294527
  * @param {WorkItem[]} queue - Queue of WorkItems
294360
294528
  */
294361
- async function workItemGarbageCollector(queue) {
294529
+ async function workItemGarbageCollector(queue, bookkeeper) {
294362
294530
  while (1) {
294363
294531
  operator_src_logger.debug(`The garbage collector processed '${queue.length}' work items.`);
294364
- for (const [index, wi] of queue.entries()) {
294532
+ for (let i = queue.length - 1; i >= 0; i--) {
294533
+ const wi = queue[i];
294365
294534
  if (wi.workStatus === WorkStatus.FINISHED) {
294535
+ bookkeeper?.removeBookkeeping(wi);
294366
294536
  // Because the queue is a constant, we cannot reassign it, instead we
294367
294537
  // use splice which modifies the array in place
294368
294538
  //wi.onDelete()
294369
- queue.splice(index, 1);
294539
+ queue.splice(i, 1);
294370
294540
  }
294371
294541
  }
294372
294542
  operator_src_logger.debug(`The garbage collector finished its run, leaving '${queue.length}' work items in the queue.`);
294373
294543
  await processItem_wait(10 * 1000);
294374
294544
  }
294375
294545
  }
294376
- if (process.env.GARBAGE_QUEUE_COLLECTOR) {
294377
- void workItemGarbageCollector(queue);
294378
- }
294379
294546
 
294380
294547
  ;// CONCATENATED MODULE: ../terraform_provisioner/src/tf/analyzer.ts
294381
294548
 
@@ -298337,8 +298504,8 @@ const MODULES = {
298337
298504
  },
298338
298505
  FirestartrGithubRepository: {
298339
298506
  module: 'git::https://github.com/prefapp/tfm.git//modules/github-repo',
298340
- // github-repo-v0.4.1
298341
- ref: 'addd7ce4a1054933c7f254a3d650c550c6a44024',
298507
+ // github-repo-v0.5.1
298508
+ ref: '67c7afaec38c1fdc9f1928090c181ef310fb81ec',
298342
298509
  },
298343
298510
  FirestartrGithubRepositoryFeature: {
298344
298511
  module: 'git::https://github.com/prefapp/tfm.git//modules/github-files-set',
@@ -299056,6 +299223,48 @@ function checkIfLabelExists(labelName, repoIssuesList) {
299056
299223
  return repoIssuesList.some((label) => label.name === labelName);
299057
299224
  }
299058
299225
 
299226
+ ;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghrepo/helpers/branch_protections.ts
299227
+
299228
+
299229
+ /**
299230
+ * Adds branch protection config to the synthesized Terraform config,
299231
+ * preserving legacy field semantics exactly (empty lists, explicit booleans, names).
299232
+ * @param entity The EntityGHRepo instance
299233
+ */
299234
+ function provisionBranchProtections(entity) {
299235
+ const protections = entity.cr.spec.branchProtections;
299236
+ if (!protections || !Array.isArray(protections) || protections.length === 0) {
299237
+ return;
299238
+ }
299239
+ for (const protection of protections) {
299240
+ // This shape should match the compatible Terraform contract
299241
+ const output = {};
299242
+ // Only emit legacy fields in allowed order
299243
+ output.branch = protection.branch;
299244
+ output.statusChecks =
299245
+ 'statusChecks' in protection ? (protection.statusChecks ?? []) : [];
299246
+ if ('requiredReviewersCount' in protection)
299247
+ output.requiredReviewersCount = protection.requiredReviewersCount;
299248
+ if ('requiredCodeownersReviewers' in protection)
299249
+ output.requiredCodeownersReviewers =
299250
+ protection.requiredCodeownersReviewers;
299251
+ if ('enforceAdmins' in protection)
299252
+ output.enforceAdmins = protection.enforceAdmins;
299253
+ if ('requireSignedCommits' in protection)
299254
+ output.requireSignedCommits = protection.requireSignedCommits;
299255
+ if ('requireConversationResolution' in protection)
299256
+ output.requireConversationResolution =
299257
+ protection.requireConversationResolution;
299258
+ // Only keep fields that are present, including explicit false/empty
299259
+ gh_provisioner_src_logger.debug(`[gh-provisioner] Adding branch protection config: ${JSON.stringify(output)}`);
299260
+ entity.patchData({
299261
+ op: PatchOperations.add,
299262
+ path: '/config/branch_protections/-',
299263
+ value: output,
299264
+ });
299265
+ }
299266
+ }
299267
+
299059
299268
  ;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghrepo/helpers/index.ts
299060
299269
 
299061
299270
 
@@ -299064,6 +299273,7 @@ function checkIfLabelExists(labelName, repoIssuesList) {
299064
299273
 
299065
299274
 
299066
299275
 
299276
+
299067
299277
  ;// CONCATENATED MODULE: ../gh_provisioner/src/entities/ghrepo/post/additional_branches.ts
299068
299278
 
299069
299279
 
@@ -299130,6 +299340,9 @@ async function provisionRegularBranch(repo, branchName, sourceBranch, org) {
299130
299340
 
299131
299341
 
299132
299342
  class EntityGHRepo extends base_Entity {
299343
+ escapeTerraformBranchName(value) {
299344
+ return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
299345
+ }
299133
299346
  constructor(artifact) {
299134
299347
  super(artifact, {
299135
299348
  config: {
@@ -299138,6 +299351,7 @@ class EntityGHRepo extends base_Entity {
299138
299351
  teams: [],
299139
299352
  collaborators: [],
299140
299353
  labels: [],
299354
+ branch_protections: [],
299141
299355
  },
299142
299356
  });
299143
299357
  }
@@ -299192,6 +299406,8 @@ class EntityGHRepo extends base_Entity {
299192
299406
  await provisionDefaultBranch(this);
299193
299407
  await provisionCodeowners(this);
299194
299408
  await provisionVariables(this);
299409
+ // Add branch protections to config if defined
299410
+ provisionBranchProtections(this);
299195
299411
  await provisionOIDCSubjectClaim(this);
299196
299412
  await provisionPermissions(this);
299197
299413
  await provisionLabels(this, repoAlreadyExists);
@@ -299241,6 +299457,21 @@ class EntityGHRepo extends base_Entity {
299241
299457
  id: this.cr.name,
299242
299458
  },
299243
299459
  });
299460
+ // Import github_branch_protection ONLY for protections declared in CR, not GitHub state
299461
+ const protections = this.cr.spec.branchProtections;
299462
+ if (protections && Array.isArray(protections) && protections.length > 0) {
299463
+ for (const protection of protections) {
299464
+ const branch = protection.branch;
299465
+ this.patchImportData({
299466
+ op: PatchOperations.add,
299467
+ path: '/imports/-',
299468
+ value: {
299469
+ to: `github_branch_protection.this["${this.escapeTerraformBranchName(branch)}"]`,
299470
+ id: `${this.cr.name}:${this.escapeTerraformBranchName(branch)}`,
299471
+ },
299472
+ });
299473
+ }
299474
+ }
299244
299475
  // we cannot ensure the files exist, thus we need to check
299245
299476
  // it they exist before importing them
299246
299477
  //for (const file of this.document.config.files) {
@@ -299263,6 +299494,19 @@ class EntityGHRepo extends base_Entity {
299263
299494
  },
299264
299495
  });
299265
299496
  }
299497
+ // Import Pages resource if configured.
299498
+ // When a repository is manually created with Pages already enabled,
299499
+ // we must import the existing resource to avoid a 409 conflict on apply.
299500
+ if (this.cr.spec.pages) {
299501
+ this.patchImportData({
299502
+ op: PatchOperations.add,
299503
+ path: '/imports/-',
299504
+ value: {
299505
+ to: 'github_repository_pages.this[0]',
299506
+ id: this.cr.name,
299507
+ },
299508
+ });
299509
+ }
299266
299510
  }
299267
299511
  async provisionRepository() {
299268
299512
  this.patchData({
@@ -301909,9 +302153,9 @@ const crs_analyzerSubcommand = {
301909
302153
  };
301910
302154
 
301911
302155
  ;// CONCATENATED MODULE: ./package.json
301912
- const package_namespaceObject = JSON.parse('{"i8":"2.5.0-snapshot-2"}');
302156
+ const package_namespaceObject = {"i8":"2.5.0"};
301913
302157
  ;// CONCATENATED MODULE: ../../package.json
301914
- const package_namespaceObject_1 = {"i8":"2.4.0"};
302158
+ const package_namespaceObject_1 = {"i8":"2.5.0"};
301915
302159
  ;// CONCATENATED MODULE: ./src/subcommands/index.ts
301916
302160
 
301917
302161
 
@@ -0,0 +1,7 @@
1
+ import { EntityGHRepo } from '../';
2
+ /**
3
+ * Adds branch protection config to the synthesized Terraform config,
4
+ * preserving legacy field semantics exactly (empty lists, explicit booleans, names).
5
+ * @param entity The EntityGHRepo instance
6
+ */
7
+ export declare function provisionBranchProtections(entity: EntityGHRepo): void;
@@ -4,3 +4,4 @@ export { provisionVariables } from './variables';
4
4
  export { provisionOIDCSubjectClaim } from './actions_oidc';
5
5
  export { provisionPermissions } from './teams';
6
6
  export { provisionLabels } from './labels';
7
+ export { provisionBranchProtections } from './branch_protections';
@@ -1,5 +1,6 @@
1
1
  import { Entity } from '../base';
2
2
  export declare class EntityGHRepo extends Entity {
3
+ private escapeTerraformBranchName;
3
4
  constructor(artifact: any);
4
5
  /**
5
6
  * Validation logic for GitHub Pages branch settings:
@@ -1,6 +1,20 @@
1
+ import type { Dependencies } from './resolver';
1
2
  export declare function getKindFromPlural(plural: string): any;
2
3
  export declare function getPluralFromKind(kind: string): string;
3
- import type { Dependencies } from './resolver';
4
+ /**
5
+ * Helper to extract the canonical identity (metadata.uid) from a WorkItem or its item.
6
+ *
7
+ * Use this helper when you need a stable identity key for WorkItems, e.g. for
8
+ * in-memory deferred-scheduling bookkeeping.
9
+ *
10
+ * Note: other subsystems may still use kind/namespace/name keys; this helper is
11
+ * specifically intended for UID-based WorkItem identity.
12
+ * Any future change to identity logic MUST be made here and nowhere else.
13
+ *
14
+ * Returns undefined if .metadata.uid is missing so scheduler/bookkeeping paths
15
+ * can safely short-circuit instead of throwing and aborting an entire pass.
16
+ */
17
+ export declare function getWorkItemIdentity(wi: WorkItem): string | undefined;
4
18
  export declare enum OperationType {
5
19
  RENAMED = "RENAMED",
6
20
  UPDATED = "UPDATED",
@@ -0,0 +1,40 @@
1
+ import type { WorkItem } from './definitions';
2
+ /**
3
+ * Maximum number of blocked attempts allowed before an item is moved to the deferred segment.
4
+ * An item becomes deferred once its blocked-attempt count exceeds this value.
5
+ */
6
+ export declare const MAX_BLOCKED_ATTEMPTS_BEFORE_DEFER = 5;
7
+ export declare const SUPPORTED_PARENT_KINDS: Set<string>;
8
+ /**
9
+ * Encapsulates all deferred-scheduling bookkeeping state for one scheduler queue.
10
+ * Instantiate once per queue (alongside processItemSlotsManager) inside loop().
11
+ */
12
+ export declare class DeferredSchedulingBookkeeper {
13
+ private _blockedAttempts;
14
+ private _deferredEntryOrder;
15
+ private _deferredOrderCounter;
16
+ /**
17
+ * Returns true only for supported parent kinds AND only for deletion operations.
18
+ * Per spec Definition 2: applicable when operation is MARKED_TO_DELETION,
19
+ * or RETRY with metadata.deletionTimestamp set.
20
+ */
21
+ isDeferredSchedulingApplicable(item: WorkItem): boolean;
22
+ /**
23
+ * Increments block counter for item (only call when item has been detected as blocked).
24
+ * Returns new value. Promotes item to deferred segment if threshold crossed.
25
+ */
26
+ incrementBlockedAttempt(item: WorkItem): number;
27
+ getBlockedAttempts(item: WorkItem): number;
28
+ isDeferred(item: WorkItem): boolean;
29
+ getDeferredOrder(item: WorkItem): number | undefined;
30
+ removeBookkeeping(item: WorkItem): void;
31
+ /**
32
+ * Splits queue into non-deferred and deferred, preserving original order,
33
+ * but sorts deferred by stable insertion order.
34
+ */
35
+ partitionQueueByDeferred<T extends WorkItem>(queue: T[]): {
36
+ nonDeferred: T[];
37
+ deferred: T[];
38
+ };
39
+ clearAllBookkeeping(): void;
40
+ }
@@ -1,4 +1,5 @@
1
1
  import { WorkItem } from './informer';
2
+ import { DeferredSchedulingBookkeeper } from './processItem.blocks';
2
3
  export declare function getQueueMetrics(): {
3
4
  nItems: number;
4
5
  nItemsFinished: number;
@@ -25,4 +26,4 @@ export declare function processItem(workItem: WorkItem): Promise<void>;
25
26
  * Periodically checks the queue for finished WorkItems and removes them
26
27
  * @param {WorkItem[]} queue - Queue of WorkItems
27
28
  */
28
- export declare function workItemGarbageCollector(queue: WorkItem[]): Promise<void>;
29
+ export declare function workItemGarbageCollector(queue: WorkItem[], bookkeeper?: DeferredSchedulingBookkeeper): Promise<void>;
@@ -1,11 +1,11 @@
1
1
  import { WorkItem } from './definitions';
2
2
  import { ProcessItemSlotMetrics } from './metrics/processItem.slot.metrics';
3
- export declare function initProcessItemsSlots(nSlots: number, initMetrics?: boolean): ProcessItemSlots;
3
+ export declare function initProcessItemsSlots(nSlots: number, initMetrics?: boolean, onWorkItemBlockedByHandler?: (workItem: WorkItem) => void): ProcessItemSlots;
4
4
  export declare class ProcessItemSlots {
5
5
  _slots: ProcessItemSlot[];
6
6
  _nSlots: number;
7
7
  _guardRails: GuardRails;
8
- constructor(nSlots: number, initMetrics: boolean);
8
+ constructor(nSlots: number, initMetrics: boolean, onWorkItemBlockedByHandler?: (workItem: WorkItem) => void);
9
9
  getIdleSlots(): Generator<ProcessItemSlot, void, unknown>;
10
10
  allSlotsAreIdle(): boolean;
11
11
  isWorkItemBlocked(workItem: WorkItem): boolean;
@@ -24,16 +24,19 @@ export declare class ProcessItemSlot {
24
24
  _actions: {
25
25
  blockItem: (item: any) => void;
26
26
  unblockItem: (item: any) => void;
27
+ onWorkItemBlockedByHandler?: (workItem: WorkItem) => void;
27
28
  } | undefined;
28
29
  _metrics: ProcessItemSlotMetrics;
29
30
  constructor(id: number);
30
31
  set actions(actions: {
31
32
  blockItem: (item: any) => void;
32
33
  unblockItem: (item: any) => void;
34
+ onWorkItemBlockedByHandler?: (workItem: WorkItem) => void;
33
35
  });
34
36
  get actions(): {
35
37
  blockItem: (item: any) => void;
36
38
  unblockItem: (item: any) => void;
39
+ onWorkItemBlockedByHandler?: (workItem: WorkItem) => void;
37
40
  };
38
41
  get idle(): boolean;
39
42
  get id(): number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@firestartr/cli",
3
- "version": "2.5.0-snapshot-2",
3
+ "version": "2.5.0",
4
4
  "private": false,
5
5
  "description": "Commandline tool",
6
6
  "main": "build/main.js",