@highstate/backend 0.7.2 → 0.7.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/{index.mjs → index.js} +1254 -915
  2. package/dist/library/source-resolution-worker.js +55 -0
  3. package/dist/library/worker/main.js +207 -0
  4. package/dist/{terminal-CqIsctlZ.mjs → library-BW5oPM7V.js} +210 -87
  5. package/dist/shared/index.js +6 -0
  6. package/dist/utils-ByadNcv4.js +102 -0
  7. package/package.json +14 -18
  8. package/src/common/index.ts +3 -0
  9. package/src/common/local.ts +22 -0
  10. package/src/common/pulumi.ts +230 -0
  11. package/src/common/utils.ts +137 -0
  12. package/src/config.ts +40 -0
  13. package/src/index.ts +6 -0
  14. package/src/library/abstractions.ts +83 -0
  15. package/src/library/factory.ts +20 -0
  16. package/src/library/index.ts +2 -0
  17. package/src/library/local.ts +404 -0
  18. package/src/library/source-resolution-worker.ts +96 -0
  19. package/src/library/worker/evaluator.ts +119 -0
  20. package/src/library/worker/loader.ts +93 -0
  21. package/src/library/worker/main.ts +82 -0
  22. package/src/library/worker/protocol.ts +38 -0
  23. package/src/orchestrator/index.ts +1 -0
  24. package/src/orchestrator/manager.ts +165 -0
  25. package/src/orchestrator/operation-workset.ts +483 -0
  26. package/src/orchestrator/operation.ts +647 -0
  27. package/src/preferences/shared.ts +1 -0
  28. package/src/project/abstractions.ts +89 -0
  29. package/src/project/factory.ts +11 -0
  30. package/src/project/index.ts +4 -0
  31. package/src/project/local.ts +412 -0
  32. package/src/project/lock.ts +39 -0
  33. package/src/project/manager.ts +374 -0
  34. package/src/runner/abstractions.ts +146 -0
  35. package/src/runner/factory.ts +22 -0
  36. package/src/runner/index.ts +2 -0
  37. package/src/runner/local.ts +698 -0
  38. package/src/secret/abstractions.ts +59 -0
  39. package/src/secret/factory.ts +22 -0
  40. package/src/secret/index.ts +2 -0
  41. package/src/secret/local.ts +152 -0
  42. package/src/services.ts +133 -0
  43. package/src/shared/index.ts +10 -0
  44. package/src/shared/library.ts +77 -0
  45. package/src/shared/operation.ts +85 -0
  46. package/src/shared/project.ts +62 -0
  47. package/src/shared/resolvers/graph-resolver.ts +111 -0
  48. package/src/shared/resolvers/input-hash.ts +77 -0
  49. package/src/shared/resolvers/input.ts +314 -0
  50. package/src/shared/resolvers/registry.ts +10 -0
  51. package/src/shared/resolvers/validation.ts +94 -0
  52. package/src/shared/state.ts +262 -0
  53. package/src/shared/terminal.ts +13 -0
  54. package/src/state/abstractions.ts +222 -0
  55. package/src/state/factory.ts +22 -0
  56. package/src/state/index.ts +3 -0
  57. package/src/state/local.ts +605 -0
  58. package/src/state/manager.ts +33 -0
  59. package/src/terminal/docker.ts +90 -0
  60. package/src/terminal/factory.ts +20 -0
  61. package/src/terminal/index.ts +3 -0
  62. package/src/terminal/manager.ts +330 -0
  63. package/src/terminal/run.sh.ts +37 -0
  64. package/src/terminal/shared.ts +50 -0
  65. package/src/workspace/abstractions.ts +41 -0
  66. package/src/workspace/factory.ts +14 -0
  67. package/src/workspace/index.ts +2 -0
  68. package/src/workspace/local.ts +54 -0
  69. package/dist/index.d.ts +0 -760
  70. package/dist/library/worker/main.mjs +0 -164
  71. package/dist/runner/source-resolution-worker.mjs +0 -22
  72. package/dist/shared/index.d.ts +0 -85
  73. package/dist/shared/index.mjs +0 -54
  74. package/dist/terminal-Cm2WqcyB.d.ts +0 -1589
@@ -1,6 +1,8 @@
1
1
  import { z } from 'zod';
2
- import { omit, unique, fromEntries } from 'remeda';
2
+ import { omit, unique, mapValues, fromEntries } from 'remeda';
3
+ import { isUnitModel } from '@highstate/contract';
3
4
  import { sha256 } from 'crypto-hash';
5
+ import { Ajv } from 'ajv';
4
6
 
5
7
  const positionSchema = z.object({
6
8
  x: z.number(),
@@ -25,12 +27,15 @@ const instanceModelSchema = z.object({
25
27
  type: z.string(),
26
28
  name: z.string(),
27
29
  ...instanceModelPatchSchema.shape,
30
+ resolvedInputs: z.record(z.array(instanceInputSchema)).optional(),
28
31
  parentId: z.string().optional(),
29
- outputs: z.record(z.array(instanceInputSchema)).optional()
32
+ outputs: z.record(z.array(instanceInputSchema)).optional(),
33
+ resolvedOutputs: z.record(z.array(instanceInputSchema)).optional()
30
34
  });
31
35
  const compositeInstanceSchema = z.object({
32
36
  instance: instanceModelSchema,
33
- children: z.array(instanceModelSchema)
37
+ children: z.array(instanceModelSchema),
38
+ inputHash: z.string().optional()
34
39
  });
35
40
  const hubModelPatchSchema = z.object({
36
41
  position: positionSchema.optional(),
@@ -60,15 +65,17 @@ const instanceStatusFieldSchema = z.object({
60
65
  value: z.string().optional(),
61
66
  displayName: z.string().optional(),
62
67
  sensitive: z.boolean().optional(),
63
- url: z.string().optional()
68
+ url: z.string().optional(),
69
+ complementaryTo: z.string().optional()
64
70
  });
65
71
  const instanceFileMetaSchema = z.object({
66
72
  name: z.string(),
67
73
  contentType: z.string(),
74
+ size: z.number(),
68
75
  isBinary: z.boolean().optional()
69
76
  });
70
77
  const instanceFileSchema = z.object({
71
- ...instanceFileMetaSchema.shape,
78
+ meta: instanceFileMetaSchema,
72
79
  content: z.string()
73
80
  });
74
81
  const instancePageBlockSchema = z.union([
@@ -142,13 +149,14 @@ const instanceStateSchema = z.object({
142
149
  inputHash: z.string().nullable().default(null),
143
150
  outputHash: z.string().nullable().default(null),
144
151
  error: z.string().nullable().default(null),
152
+ evaluationError: z.string().nullable().default(null),
145
153
  statusFields: z.array(instanceStatusFieldSchema).default(() => []),
146
154
  files: z.array(instanceFileMetaSchema).default(() => []),
147
155
  pages: z.array(instancePageMetaSchema).default(() => []),
148
156
  terminals: z.array(instanceTerminalMetaSchema).default(() => []),
149
157
  triggers: z.array(instanceTriggerSchema).default(() => [])
150
158
  });
151
- const instanceStatePatchSchema = z.object({
159
+ const instanceStateUpdateSchema = z.object({
152
160
  ...instanceStateSchema.shape,
153
161
  // secrets updated by the unit
154
162
  secrets: z.record(z.string()).nullable(),
@@ -167,6 +175,7 @@ function createInstanceState(id, status = "not_created", fields = {}) {
167
175
  inputHash: null,
168
176
  outputHash: null,
169
177
  error: null,
178
+ evaluationError: null,
170
179
  statusFields: [],
171
180
  files: [],
172
181
  pages: [],
@@ -179,54 +188,13 @@ function applyPartialInstanceState(states, patch) {
179
188
  if (!patch.id) {
180
189
  throw new Error("The ID of the instance state is required.");
181
190
  }
182
- let state = states.get(patch.id);
183
- if (!state) {
184
- state = createInstanceState(patch.id, "unknown");
185
- states.set(patch.id, state);
186
- }
187
- if (patch.status !== void 0) {
188
- state.status = patch.status;
189
- }
190
- if (patch.dependencyIds !== void 0) {
191
- state.dependencyIds = patch.dependencyIds;
192
- }
193
- if (patch.latestOperationId !== void 0) {
194
- state.latestOperationId = patch.latestOperationId;
195
- }
196
- if (patch.currentResourceCount !== void 0) {
197
- state.currentResourceCount = patch.currentResourceCount;
198
- }
199
- if (patch.totalResourceCount !== void 0) {
200
- state.totalResourceCount = patch.totalResourceCount;
201
- }
202
- if (patch.inputHash !== void 0) {
203
- state.inputHash = patch.inputHash;
204
- }
205
- if (patch.outputHash !== void 0) {
206
- state.outputHash = patch.outputHash;
207
- }
208
- if (patch.error !== void 0) {
209
- state.error = patch.error;
210
- }
211
- if (patch.statusFields !== void 0) {
212
- state.statusFields = patch.statusFields;
213
- }
214
- if (patch.files !== void 0) {
215
- state.files = patch.files;
216
- }
217
- if (patch.pages !== void 0) {
218
- state.pages = patch.pages;
219
- }
220
- if (patch.terminals !== void 0) {
221
- state.terminals = patch.terminals;
222
- }
223
- if (patch.triggers !== void 0) {
224
- state.triggers = patch.triggers;
225
- }
191
+ let state = states.get(patch.id) ?? createInstanceState(patch.id, "unknown");
192
+ state = { ...state, ...patch };
193
+ states.set(state.id, state);
226
194
  return state;
227
195
  }
228
- function createInstanceStateFrontendPatch(patch) {
229
- return omit(patch, ["secrets", "logLine"]);
196
+ function createInstanceStatePatch(update) {
197
+ return omit(update, ["secrets", "logLine"]);
230
198
  }
231
199
  function buildDependentInstanceStateMap(instanceStates) {
232
200
  const dependentMap = /* @__PURE__ */ new Map();
@@ -259,17 +227,9 @@ function getAllDependentInstanceIds(dependentMap, instanceId) {
259
227
  return Array.from(result);
260
228
  }
261
229
 
262
- const operationTypeSchema = z.enum([
263
- "update",
264
- "preview",
265
- "destroy",
266
- "recreate",
267
- "refresh",
268
- "evaluate"
269
- ]);
230
+ const operationTypeSchema = z.enum(["update", "preview", "destroy", "recreate", "refresh"]);
270
231
  const operationStatusSchema = z.enum([
271
232
  "pending",
272
- "evaluating",
273
233
  "running",
274
234
  "completed",
275
235
  "failed",
@@ -323,6 +283,7 @@ const projectOperationSchema = z.object({
323
283
  projectId: z.string(),
324
284
  type: operationTypeSchema,
325
285
  instanceIds: z.array(z.string()),
286
+ affectedInstanceIds: z.array(z.string()).default(() => []),
326
287
  options: operationOptionsSchema.default(() => ({})),
327
288
  error: z.string().nullable(),
328
289
  startedAt: z.number(),
@@ -345,8 +306,10 @@ function createDefaultGraphResolverBackend() {
345
306
  };
346
307
  }
347
308
  function defineGraphResolver(options) {
348
- return (nodes, logger, backend) => {
309
+ const factory = (nodes, logger, backend) => {
349
310
  backend ??= createDefaultGraphResolverBackend();
311
+ logger = logger.child({ resolver: options.name });
312
+ const outputs = /* @__PURE__ */ new Map();
350
313
  const resolver = (itemId, dependencyChain) => {
351
314
  logger.trace({ itemId }, "resolving item");
352
315
  const existingPromise = backend.promiseCache.get(itemId);
@@ -364,19 +327,16 @@ function defineGraphResolver(options) {
364
327
  const dependencies = unique(options.getNodeDependencies(item));
365
328
  backend.setDependencies?.(itemId, dependencies);
366
329
  logger.trace({ itemId, dependencies }, "resolving item dependencies");
367
- const resolvedDependencies = /* @__PURE__ */ new Map();
368
330
  const newChain = [...dependencyChain, itemId];
369
331
  for (const depId of dependencies) {
370
- const depResult = await resolver(depId, newChain);
371
- if (depResult !== void 0) {
372
- resolvedDependencies.set(depId, depResult);
373
- }
332
+ await resolver(depId, newChain);
374
333
  }
375
- return await options.process(item, resolvedDependencies, logger);
334
+ return await options.process(item, outputs, logger);
376
335
  };
377
336
  const promise = resolve().then((result) => {
378
337
  if (backend.promiseCache.get(itemId) === promise) {
379
338
  backend.setOutput?.(itemId, result);
339
+ outputs.set(itemId, result);
380
340
  }
381
341
  return result;
382
342
  });
@@ -385,9 +345,12 @@ function defineGraphResolver(options) {
385
345
  };
386
346
  return (id) => resolver(id, []);
387
347
  };
348
+ factory.factoryName = options.name;
349
+ return factory;
388
350
  }
389
351
 
390
352
  const createInputResolver = defineGraphResolver({
353
+ name: "input-resolver",
391
354
  getNodeId(node) {
392
355
  if (node.kind === "hub") {
393
356
  return `hub:${node.hub.id}`;
@@ -405,6 +368,11 @@ const createInputResolver = defineGraphResolver({
405
368
  }
406
369
  return dependencies;
407
370
  }
371
+ for (const inputs of Object.values(node.instance.inputs ?? {})) {
372
+ for (const input of inputs) {
373
+ dependencies.push(`instance:${input.instanceId}`);
374
+ }
375
+ }
408
376
  for (const inputs of Object.values(node.instance.hubInputs ?? {})) {
409
377
  for (const input of inputs) {
410
378
  dependencies.push(`hub:${input.hubId}`);
@@ -429,12 +397,20 @@ const createInputResolver = defineGraphResolver({
429
397
  const getInstanceOutput = (input) => {
430
398
  const output = dependencies.get(`instance:${input.instanceId}`);
431
399
  if (!output) {
432
- return { component: null };
400
+ return {
401
+ component: null,
402
+ resolvedInputs: [],
403
+ resolvedOutputs: []
404
+ };
433
405
  }
434
406
  if (output.kind !== "instance") {
435
407
  throw new Error("Expected instance node");
436
408
  }
437
- return output;
409
+ return {
410
+ component: output.component,
411
+ resolvedInputs: output.resolvedInputs[input.output] ?? [],
412
+ resolvedOutputs: output.resolvedOutputs[input.output] ?? []
413
+ };
438
414
  };
439
415
  if (node.kind === "hub") {
440
416
  const hubResult = /* @__PURE__ */ new Map();
@@ -461,6 +437,27 @@ const createInputResolver = defineGraphResolver({
461
437
  resolvedInputs: Array.from(hubResult.values())
462
438
  };
463
439
  }
440
+ if (node.instance.resolvedInputs) {
441
+ return {
442
+ kind: "instance",
443
+ component: node.component,
444
+ resolvedInputs: mapValues(node.instance.resolvedInputs, (inputs, inputName) => {
445
+ const componentInput = node.component.inputs[inputName];
446
+ if (!componentInput) {
447
+ logger.warn({
448
+ msg: "input not found in the component",
449
+ inputName,
450
+ component: node.component
451
+ });
452
+ return [];
453
+ }
454
+ return inputs.map((input) => ({ input, type: componentInput.type }));
455
+ }),
456
+ resolvedOutputs: node.instance.resolvedOutputs ?? {},
457
+ resolvedInjectionInputs: [],
458
+ matchedInjectionInputs: []
459
+ };
460
+ }
464
461
  const resolvedInputsMap = /* @__PURE__ */ new Map();
465
462
  const addInstanceResult = (inputName, input) => {
466
463
  let inputs = resolvedInputsMap.get(inputName);
@@ -470,14 +467,28 @@ const createInputResolver = defineGraphResolver({
470
467
  }
471
468
  inputs.set(`${input.input.instanceId}:${input.input.output}`, input);
472
469
  };
470
+ const addInstanceInput = (inputName, input) => {
471
+ const componentInput = node.component.inputs[inputName];
472
+ if (!componentInput) {
473
+ logger.warn({ msg: "input not found in the component", input, component: node.component });
474
+ return;
475
+ }
476
+ const { component, resolvedOutputs } = getInstanceOutput(input);
477
+ if (!component) {
478
+ logger.warn({ instanceId: node.instance.id, input }, "no output found for the input");
479
+ return;
480
+ }
481
+ if (isUnitModel(component)) {
482
+ addInstanceResult(inputName, { input, type: componentInput.type });
483
+ return;
484
+ }
485
+ for (const output of resolvedOutputs) {
486
+ addInstanceResult(inputName, { input: output, type: componentInput.type });
487
+ }
488
+ };
473
489
  for (const [inputName, inputs] of Object.entries(node.instance.inputs ?? {})) {
474
490
  for (const input of inputs) {
475
- const componentInput = node.component.inputs[inputName];
476
- if (!componentInput) {
477
- logger.warn({ msg: "input not found in the component", input, component: node.component });
478
- continue;
479
- }
480
- addInstanceResult(inputName, { input, type: componentInput.type });
491
+ addInstanceInput(inputName, input);
481
492
  }
482
493
  }
483
494
  const injectionInputs = /* @__PURE__ */ new Map();
@@ -499,7 +510,7 @@ const createInputResolver = defineGraphResolver({
499
510
  }
500
511
  for (const input of allInputs.values()) {
501
512
  if (input.type === componentInput.type) {
502
- addInstanceResult(inputName, input);
513
+ addInstanceInput(inputName, input.input);
503
514
  const key = `${input.input.instanceId}:${input.input.output}`;
504
515
  if (injectionInputs.has(key)) {
505
516
  matchedInjectionInputs.set(key, input);
@@ -517,6 +528,7 @@ const createInputResolver = defineGraphResolver({
517
528
  kind: "instance",
518
529
  component: node.component,
519
530
  resolvedInputs,
531
+ resolvedOutputs: node.instance.resolvedOutputs ?? {},
520
532
  resolvedInjectionInputs: Array.from(injectionInputs.values()),
521
533
  matchedInjectionInputs: Array.from(matchedInjectionInputs.values())
522
534
  };
@@ -548,6 +560,7 @@ function getMatchedInjectionInstanceInputs(output) {
548
560
  }
549
561
 
550
562
  const createInputHashResolver = defineGraphResolver({
563
+ name: "input-hash-resolver",
551
564
  getNodeId: (node) => node.instance.id,
552
565
  getNodeDependencies({ resolvedInputs }) {
553
566
  const dependencies = [];
@@ -558,14 +571,11 @@ const createInputHashResolver = defineGraphResolver({
558
571
  }
559
572
  return dependencies;
560
573
  },
561
- async process({ instance, resolvedInputs, sourceHash, state }, dependencies) {
562
- let sink = JSON.stringify(instance.args ?? {});
574
+ async process({ instance, component, resolvedInputs, sourceHash, state }, dependencies) {
575
+ let sink = component.definitionHash + JSON.stringify(instance.args ?? {});
563
576
  if (sourceHash) {
564
577
  sink += sourceHash;
565
578
  }
566
- if (state?.outputHash) {
567
- sink += state.outputHash;
568
- }
569
579
  const sortedInputs = Object.entries(resolvedInputs).sort(([a], [b]) => a.localeCompare(b));
570
580
  for (const [inputKey, inputs] of sortedInputs) {
571
581
  if (Object.keys(inputs).length === 0) {
@@ -575,16 +585,129 @@ const createInputHashResolver = defineGraphResolver({
575
585
  const instanceIds = inputs.map((input) => input.input.instanceId);
576
586
  instanceIds.sort();
577
587
  for (const instanceId of instanceIds) {
578
- sink += dependencies.get(instanceId);
588
+ const dependency = dependencies.get(instanceId);
589
+ if (!dependency) continue;
590
+ sink += dependency.inputHash;
591
+ sink += dependency.outputHash;
579
592
  }
580
593
  }
581
- return await sha256(sink);
594
+ return {
595
+ inputHash: await sha256(sink),
596
+ outputHash: state?.outputHash ?? ""
597
+ };
582
598
  }
583
599
  });
584
600
 
601
+ const createValidationResolver = defineGraphResolver({
602
+ name: "validation-resolver",
603
+ getNodeId: (node) => node.instance.id,
604
+ getNodeDependencies({ resolvedInputs }) {
605
+ const dependencies = [];
606
+ for (const inputs of Object.values(resolvedInputs)) {
607
+ for (const input of inputs) {
608
+ dependencies.push(input.input.instanceId);
609
+ }
610
+ }
611
+ return dependencies;
612
+ },
613
+ process({ instance, component, resolvedInputs }, dependencies, logger) {
614
+ const ajv = new Ajv();
615
+ logger.debug({ instanceId: instance.id }, "validating instance");
616
+ for (const [name, argument] of Object.entries(component.args)) {
617
+ if (!argument.required && !instance.args?.[name]) {
618
+ continue;
619
+ }
620
+ if (!ajv.validate(argument.schema, instance.args?.[name])) {
621
+ logger.debug({ instanceId: instance.id, argumentName: name }, "invalid argument");
622
+ return {
623
+ status: "invalid-args",
624
+ errorText: ajv.errorsText()
625
+ };
626
+ }
627
+ }
628
+ for (const inputs of Object.values(resolvedInputs)) {
629
+ for (const input of inputs) {
630
+ const inputInstance = dependencies.get(input.input.instanceId);
631
+ if (inputInstance?.status !== "ok") {
632
+ return {
633
+ status: "invalid-inputs",
634
+ errorText: `instance "${input.input.instanceId}" is invalid`
635
+ };
636
+ }
637
+ }
638
+ }
639
+ for (const [name, input] of Object.entries(component.inputs)) {
640
+ if (!input.required || input.multiple) {
641
+ continue;
642
+ }
643
+ if (!resolvedInputs[name] || !resolvedInputs[name].length) {
644
+ return {
645
+ status: "missing-inputs",
646
+ errorText: `input "${name}" is missing`
647
+ };
648
+ }
649
+ }
650
+ return { status: "ok" };
651
+ }
652
+ });
653
+
654
+ const resolverFactories = {
655
+ [createInputResolver.factoryName]: createInputResolver,
656
+ [createInputHashResolver.factoryName]: createInputHashResolver,
657
+ [createValidationResolver.factoryName]: createValidationResolver
658
+ };
659
+
585
660
  const terminalSessionSchema = z.object({
586
- id: z.string().uuid(),
587
- terminalName: z.string()
661
+ id: z.string().nanoid(),
662
+ projectId: z.string(),
663
+ instanceId: z.string(),
664
+ terminalName: z.string(),
665
+ terminalTitle: z.string(),
666
+ createdAt: z.coerce.date(),
667
+ finishedAt: z.coerce.date().optional()
588
668
  });
589
669
 
590
- export { instancePageMetaSchema as A, instanceTerminalMetaSchema as B, instanceTerminalFileSchema as C, instanceTriggerSpecSchema as D, instanceTriggerInvocationSchema as E, instanceStatePatchSchema as F, buildDependentInstanceStateMap as G, getAllDependentInstanceIds as H, operationTypeSchema as I, operationStatusSchema as J, operationOptionsSchema as K, projectOperationRequestSchema as L, CircularDependencyError as M, createDefaultGraphResolverBackend as N, getResolvedHubInputs as O, getResolvedInstanceInputs as P, getResolvedInjectionInstanceInputs as Q, getMatchedInjectionInstanceInputs as R, createInputHashResolver as a, createInstanceState as b, createInputResolver as c, instanceTerminalSchema as d, instancePageSchema as e, instanceFileSchema as f, instanceStatusFieldSchema as g, hubModelSchema as h, instanceModelSchema as i, instanceTriggerSchema as j, compositeInstanceSchema as k, instanceStateSchema as l, isFinalOperationStatus as m, createInstanceStateFrontendPatch as n, applyPartialInstanceState as o, projectOperationSchema as p, defineGraphResolver as q, positionSchema as r, instanceInputSchema as s, terminalSessionSchema as t, hubInstanceInputSchema as u, instanceModelPatchSchema as v, hubModelPatchSchema as w, instanceStatusSchema as x, instanceFileMetaSchema as y, instancePageBlockSchema as z };
670
+ function diffLibraries(oldLibrary, newLibrary) {
671
+ const updates = [];
672
+ for (const [componentType, newComponent] of Object.entries(newLibrary.components)) {
673
+ const existingComponent = oldLibrary.components[componentType];
674
+ if (existingComponent?.definitionHash !== newComponent.definitionHash) {
675
+ updates.push({ type: "component-updated", component: newComponent });
676
+ }
677
+ }
678
+ for (const componentType of Object.keys(oldLibrary.components)) {
679
+ if (!newLibrary.components[componentType]) {
680
+ updates.push({ type: "component-removed", componentType });
681
+ }
682
+ }
683
+ for (const [entityType, newEntity] of Object.entries(newLibrary.entities)) {
684
+ const existingEntity = oldLibrary.entities[entityType];
685
+ if (existingEntity?.definitionHash !== newEntity.definitionHash) {
686
+ updates.push({ type: "entity-updated", entity: newEntity });
687
+ }
688
+ }
689
+ for (const entityType of Object.keys(oldLibrary.entities)) {
690
+ if (!newLibrary.entities[entityType]) {
691
+ updates.push({ type: "entity-removed", entityType });
692
+ }
693
+ }
694
+ return updates;
695
+ }
696
+ function applyLibraryUpdate(components, entities, update) {
697
+ switch (update.type) {
698
+ case "component-updated":
699
+ components[update.component.type] = update.component;
700
+ break;
701
+ case "entity-updated":
702
+ entities[update.entity.type] = update.entity;
703
+ break;
704
+ case "component-removed":
705
+ delete components[update.componentType];
706
+ break;
707
+ case "entity-removed":
708
+ delete entities[update.entityType];
709
+ break;
710
+ }
711
+ }
712
+
713
+ export { buildDependentInstanceStateMap as A, getAllDependentInstanceIds as B, operationTypeSchema as C, operationStatusSchema as D, operationOptionsSchema as E, projectOperationRequestSchema as F, projectOperationSchema as G, isFinalOperationStatus as H, CircularDependencyError as I, createDefaultGraphResolverBackend as J, defineGraphResolver as K, resolverFactories as L, createInputResolver as M, getResolvedHubInputs as N, getResolvedInstanceInputs as O, getResolvedInjectionInstanceInputs as P, getMatchedInjectionInstanceInputs as Q, createInputHashResolver as R, createValidationResolver as S, terminalSessionSchema as T, diffLibraries as U, applyLibraryUpdate as V, instanceModelPatchSchema as a, instanceModelSchema as b, compositeInstanceSchema as c, hubModelPatchSchema as d, hubModelSchema as e, instanceStatusSchema as f, instanceStatusFieldSchema as g, hubInstanceInputSchema as h, instanceInputSchema as i, instanceFileMetaSchema as j, instanceFileSchema as k, instancePageBlockSchema as l, instancePageMetaSchema as m, instancePageSchema as n, instanceTerminalMetaSchema as o, positionSchema as p, instanceTerminalFileSchema as q, instanceTerminalSchema as r, instanceTriggerSpecSchema as s, instanceTriggerSchema as t, instanceTriggerInvocationSchema as u, instanceStateSchema as v, instanceStateUpdateSchema as w, createInstanceState as x, applyPartialInstanceState as y, createInstanceStatePatch as z };
@@ -0,0 +1,6 @@
1
+ export { I as CircularDependencyError, V as applyLibraryUpdate, y as applyPartialInstanceState, A as buildDependentInstanceStateMap, c as compositeInstanceSchema, J as createDefaultGraphResolverBackend, R as createInputHashResolver, M as createInputResolver, x as createInstanceState, z as createInstanceStatePatch, S as createValidationResolver, K as defineGraphResolver, U as diffLibraries, B as getAllDependentInstanceIds, Q as getMatchedInjectionInstanceInputs, N as getResolvedHubInputs, P as getResolvedInjectionInstanceInputs, O as getResolvedInstanceInputs, h as hubInstanceInputSchema, d as hubModelPatchSchema, e as hubModelSchema, j as instanceFileMetaSchema, k as instanceFileSchema, i as instanceInputSchema, a as instanceModelPatchSchema, b as instanceModelSchema, l as instancePageBlockSchema, m as instancePageMetaSchema, n as instancePageSchema, v as instanceStateSchema, w as instanceStateUpdateSchema, g as instanceStatusFieldSchema, f as instanceStatusSchema, q as instanceTerminalFileSchema, o as instanceTerminalMetaSchema, r as instanceTerminalSchema, u as instanceTriggerInvocationSchema, t as instanceTriggerSchema, s as instanceTriggerSpecSchema, H as isFinalOperationStatus, E as operationOptionsSchema, D as operationStatusSchema, C as operationTypeSchema, p as positionSchema, F as projectOperationRequestSchema, G as projectOperationSchema, L as resolverFactories, T as terminalSessionSchema } from '../library-BW5oPM7V.js';
2
+ import 'zod';
3
+ import 'remeda';
4
+ import '@highstate/contract';
5
+ import 'crypto-hash';
6
+ import 'ajv';
@@ -0,0 +1,102 @@
1
+ import { z } from 'zod';
2
+
3
+ async function runWithRetryOnError(runner, tryHandleError, maxRetries = 1) {
4
+ let lastError;
5
+ for (let i = 0; i < maxRetries + 1; i++) {
6
+ try {
7
+ return await runner();
8
+ } catch (e) {
9
+ lastError = e;
10
+ if (await tryHandleError(e)) {
11
+ continue;
12
+ }
13
+ throw e;
14
+ }
15
+ }
16
+ throw lastError;
17
+ }
18
+ class AbortError extends Error {
19
+ constructor(options) {
20
+ super("Operation aborted", options);
21
+ }
22
+ }
23
+ function isAbortError(error) {
24
+ return error instanceof Error && error.name === "AbortError";
25
+ }
26
+ const abortMessagePatterns = ["Operation aborted", "Command was killed with SIGINT"];
27
+ function isAbortErrorLike(error) {
28
+ if (error instanceof Error) {
29
+ return abortMessagePatterns.some((pattern) => error.message.includes(pattern));
30
+ }
31
+ return false;
32
+ }
33
+ function tryWrapAbortErrorLike(error) {
34
+ if (isAbortErrorLike(error)) {
35
+ return new AbortError({ cause: error });
36
+ }
37
+ return error;
38
+ }
39
+ const stringArrayType = z.string().transform((args) => args.split(",").map((arg) => arg.trim()));
40
+ function errorToString(error) {
41
+ if (error instanceof Error) {
42
+ return error.stack || error.message;
43
+ }
44
+ return JSON.stringify(error);
45
+ }
46
+ function createAsyncBatcher(fn, { waitMs = 100, maxWaitTimeMs = 1e3 } = {}) {
47
+ let batch = [];
48
+ let activeTimeout = null;
49
+ let maxWaitTimeout = null;
50
+ let firstCallTimestamp = null;
51
+ async function processBatch() {
52
+ if (batch.length === 0) return;
53
+ const currentBatch = batch;
54
+ batch = [];
55
+ await fn(currentBatch);
56
+ if (maxWaitTimeout) {
57
+ clearTimeout(maxWaitTimeout);
58
+ maxWaitTimeout = null;
59
+ }
60
+ firstCallTimestamp = null;
61
+ }
62
+ function schedule() {
63
+ if (activeTimeout) clearTimeout(activeTimeout);
64
+ activeTimeout = setTimeout(() => {
65
+ activeTimeout = null;
66
+ void processBatch();
67
+ }, waitMs);
68
+ if (!firstCallTimestamp) {
69
+ firstCallTimestamp = Date.now();
70
+ maxWaitTimeout = setTimeout(() => {
71
+ if (activeTimeout) clearTimeout(activeTimeout);
72
+ activeTimeout = null;
73
+ void processBatch();
74
+ }, maxWaitTimeMs);
75
+ }
76
+ }
77
+ return {
78
+ /**
79
+ * Add an item to the batch.
80
+ */
81
+ call(item) {
82
+ batch.push(item);
83
+ schedule();
84
+ },
85
+ /**
86
+ * Immediately flush the pending batch (if any).
87
+ */
88
+ async flush() {
89
+ if (activeTimeout) {
90
+ clearTimeout(activeTimeout);
91
+ activeTimeout = null;
92
+ }
93
+ if (maxWaitTimeout) {
94
+ clearTimeout(maxWaitTimeout);
95
+ maxWaitTimeout = null;
96
+ }
97
+ await processBatch();
98
+ }
99
+ };
100
+ }
101
+
102
+ export { AbortError as A, isAbortError as a, createAsyncBatcher as c, errorToString as e, isAbortErrorLike as i, runWithRetryOnError as r, stringArrayType as s, tryWrapAbortErrorLike as t };
package/package.json CHANGED
@@ -1,36 +1,31 @@
1
1
  {
2
2
  "name": "@highstate/backend",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "type": "module",
5
- "module": "dist/index.mjs",
6
- "types": "dist/index.d.ts",
7
5
  "files": [
8
- "dist"
6
+ "dist",
7
+ "src"
9
8
  ],
10
9
  "exports": {
11
10
  ".": {
12
- "types": "./dist/index.d.ts",
13
- "default": "./dist/index.mjs"
11
+ "types": "./src/index.ts",
12
+ "default": "./dist/index.js"
14
13
  },
15
14
  "./shared": {
16
- "types": "./dist/shared/index.d.ts",
17
- "default": "./dist/shared/index.mjs"
15
+ "types": "./src/shared/index.ts",
16
+ "default": "./dist/shared/index.js"
18
17
  },
19
- "./library-worker": {
20
- "default": "./dist/library/worker/main.mjs"
21
- },
22
- "./source-resolution-worker": {
23
- "default": "./dist/runner/source-resolution-worker.mjs"
24
- }
18
+ "./library-worker": "./dist/library/worker/main.js",
19
+ "./source-resolution-worker": "./dist/library/source-resolution-worker.js"
25
20
  },
26
21
  "publishConfig": {
27
22
  "access": "public"
28
23
  },
29
24
  "scripts": {
30
- "build": "pkgroll --tsconfig=tsconfig.build.json"
25
+ "build": "pkgroll --clean --tsconfig=tsconfig.build.json"
31
26
  },
32
27
  "dependencies": {
33
- "@highstate/contract": "^0.7.2",
28
+ "@highstate/contract": "^0.7.3",
34
29
  "@types/node": "^22.10.1",
35
30
  "ajv": "^8.17.1",
36
31
  "better-lock": "^3.2.0",
@@ -44,6 +39,7 @@
44
39
  "pino": "^9.6.0",
45
40
  "pkg-types": "^1.2.1",
46
41
  "remeda": "^2.21.0",
42
+ "rev-dep": "^1.5.4",
47
43
  "uuidv7": "^1.0.2",
48
44
  "watcher": "^2.3.1",
49
45
  "zod": "^3.23.8"
@@ -61,12 +57,12 @@
61
57
  }
62
58
  },
63
59
  "devDependencies": {
64
- "@pulumi/pulumi": "^3.152.0",
60
+ "@pulumi/pulumi": "patch:@pulumi/pulumi@npm%3A3.159.0#~/.yarn/patches/@pulumi-pulumi-npm-3.159.0-d07eefce5c.patch",
65
61
  "classic-level": "^2.0.0",
66
62
  "pino-pretty": "^13.0.0",
67
63
  "pkgroll": "^2.5.1",
68
64
  "rollup": "^4.28.1",
69
65
  "typescript": "^5.7.2"
70
66
  },
71
- "gitHead": "e177535015e0fa3c74ae8ddc0bc6d31b191d2c54"
67
+ "gitHead": "5cf7cec27262c8fa1d96f6478833b94841459d64"
72
68
  }
@@ -0,0 +1,3 @@
1
+ export * from "./utils"
2
+ export * from "./pulumi"
3
+ export * from "./local"
@@ -0,0 +1,22 @@
1
+ import { basename } from "node:path"
2
+ import { findWorkspaceDir, readPackageJSON } from "pkg-types"
3
+
4
+ export async function resolveMainLocalProject(
5
+ projectPath?: string,
6
+ projectName?: string,
7
+ ): Promise<[projecPath: string, projectName: string]> {
8
+ if (!projectPath) {
9
+ projectPath = await findWorkspaceDir()
10
+ }
11
+
12
+ if (!projectName) {
13
+ const packageJson = await readPackageJSON(projectPath)
14
+ projectName = packageJson.name
15
+ }
16
+
17
+ if (!projectName) {
18
+ projectName = basename(projectPath)
19
+ }
20
+
21
+ return [projectPath, projectName]
22
+ }