@elaraai/e3-types 1.0.86 → 1.0.88

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/src/api.ts CHANGED
@@ -217,6 +217,29 @@ export const GcStatusResultType = StructType({
217
217
  error: OptionType(StringType),
218
218
  });
219
219
 
220
+ /**
221
+ * A repository's removal, as the route a server names while it runs answers
222
+ * it.
223
+ *
224
+ * A server whose removal outlasts a request answers `DELETE /repos/:repo`
225
+ * `202 Accepted`, with a `Location` naming that route and a `Retry-After`;
226
+ * one that removes the repository within the request answers 200. The route
227
+ * answers:
228
+ *
229
+ * - `removing`: the removal runs, and is asked of again after the answer's
230
+ * `Retry-After`
231
+ * - `removed`: the repository is gone
232
+ * - `failed`: the removal stopped, and why
233
+ *
234
+ * A route of a repository that is gone may answer `repository_not_found`
235
+ * instead of `removed`.
236
+ */
237
+ export const RepositoryRemovalType = VariantType({
238
+ removing: NullType,
239
+ removed: NullType,
240
+ failed: StructType({ message: StringType }),
241
+ });
242
+
220
243
  // =============================================================================
221
244
  // Package Types
222
245
  // =============================================================================
@@ -275,6 +298,16 @@ export const WorkspaceCreateRequestType = StructType({
275
298
  name: StringType,
276
299
  });
277
300
 
301
+ /**
302
+ * Request to copy a workspace within its repository.
303
+ *
304
+ * @property to - The workspace the copy makes, or replaces whole: it becomes
305
+ * the workspace copied as it is now
306
+ */
307
+ export const WorkspaceCopyRequestType = StructType({
308
+ to: StringType,
309
+ });
310
+
278
311
  /**
279
312
  * Workspace summary information.
280
313
  *
@@ -306,11 +339,30 @@ export const SchemaPolicyType = VariantType({
306
339
  reset: NullType,
307
340
  });
308
341
 
342
+ /**
343
+ * What a deploy does with an input someone set: one whose value in the
344
+ * workspace is not the value the deployed package gave it.
345
+ *
346
+ * - `reset`: give it the new package's value, as every other input takes
347
+ * - `keep-edited`: keep it while its type is the new package's; one whose type
348
+ * changed takes the new package's value, and the plan says it was reset
349
+ *
350
+ * An input the new package takes from a file takes its file under either. One
351
+ * the deployed package took from a file takes the new package's value under
352
+ * either, since a value set since cannot be told from the file's, and so does
353
+ * one the new package declares as a dataset people do not set.
354
+ */
355
+ export const InputPolicyType = VariantType({
356
+ 'keep-edited': NullType,
357
+ reset: NullType,
358
+ });
359
+
309
360
  /**
310
361
  * Request to deploy a package to a workspace.
311
362
  *
312
363
  * @property packageRef - Package reference in format "name" or "name@version"
313
364
  * @property schema - What the deploy does with a record it cannot keep as it is
365
+ * @property inputs - What the deploy does with an input someone set
314
366
  * @property allowDropRecords - Whether a record the package no longer declares
315
367
  * may be dropped, with its state and history
316
368
  * @property plan - Say what the deploy would do, and write nothing
@@ -318,6 +370,7 @@ export const SchemaPolicyType = VariantType({
318
370
  export const WorkspaceDeployRequestType = StructType({
319
371
  packageRef: StringType,
320
372
  schema: SchemaPolicyType,
373
+ inputs: InputPolicyType,
321
374
  allowDropRecords: BooleanType,
322
375
  plan: BooleanType,
323
376
  });
@@ -369,6 +422,39 @@ export const RecordIndexPlanType = StructType({
369
422
  }),
370
423
  });
371
424
 
425
+ /**
426
+ * What a deploy decided for one input: a dataset its package marks writable,
427
+ * which people set.
428
+ *
429
+ * @property input - The input's dataset ref path
430
+ * @property action - What the deploy does to it:
431
+ * - `package`: it takes the new package's value: the workspace holds the
432
+ * value the deployed package gave it, or does not hold the input
433
+ * - `keep`: kept as the workspace holds it: someone set it, and its type is
434
+ * the new package's (`keep-edited`)
435
+ * - `reset`: it takes the new package's value in place of one someone may
436
+ * have set, and why: its type changed; the deployed package took it from a
437
+ * file, so a value set since cannot be told from the file's; the new
438
+ * package no longer marks it as an input; or the deploy resets what people
439
+ * set (`reset`), when `policy` is true, which `keep-edited` would keep
440
+ * - `file`: it takes the file the new package names, as every deploy does:
441
+ * the deploy takes it in, or, when `taken` is false, reads no file
442
+ * (`resolveFileSources: false`, as a server deploying for a client does)
443
+ * and leaves it unassigned for the client to complete over the dataset
444
+ * transfer protocol
445
+ * - `drop`: the new package does not declare it, so it goes, with its value
446
+ */
447
+ export const InputPlanType = StructType({
448
+ input: StringType,
449
+ action: VariantType({
450
+ package: NullType,
451
+ keep: NullType,
452
+ reset: StructType({ reason: StringType, policy: BooleanType }),
453
+ file: StructType({ path: StringType, taken: BooleanType }),
454
+ drop: NullType,
455
+ }),
456
+ });
457
+
372
458
  /**
373
459
  * The step a deploy is at with one record.
374
460
  *
@@ -419,12 +505,15 @@ export const DeployProgressType = StructType({
419
505
  *
420
506
  * @property records - What it decided for each record
421
507
  * @property indexes - What it decided for each index of the records it keeps
508
+ * @property inputs - What it decided for each input, the package's first and
509
+ * then each it drops
422
510
  * @property warnings - The inputs it left unassigned, and why: a server never
423
511
  * reads a `file` source, whose path is on the client's machine
424
512
  */
425
513
  export const WorkspaceDeployResultType = StructType({
426
514
  records: ArrayType(RecordPlanType),
427
515
  indexes: ArrayType(RecordIndexPlanType),
516
+ inputs: ArrayType(InputPlanType),
428
517
  warnings: ArrayType(StringType),
429
518
  });
430
519
 
@@ -825,15 +914,21 @@ export const DataflowEventType = VariantType({
825
914
  * Execution status for API polling responses.
826
915
  *
827
916
  * - `running`: Execution is in progress
917
+ * - `stopping`: Execution was asked to stop, and its tasks have not all
918
+ * stopped yet: it holds its workspace until they have
828
919
  * - `completed`: Execution finished successfully
829
920
  * - `failed`: Execution finished with failures
830
921
  * - `aborted`: Execution was cancelled
831
922
  *
923
+ * `stopping` is named to sort after every case before it, so its tag is the
924
+ * last and a poll a server answered before it read as itself.
925
+ *
832
926
  * Note: Named "Api*" to distinguish from the on-disk ExecutionStatusType
833
927
  * in execution.ts which tracks individual task execution states.
834
928
  */
835
929
  export const ApiExecutionStatusType = VariantType({
836
930
  running: NullType,
931
+ stopping: NullType,
837
932
  completed: NullType,
838
933
  failed: NullType,
839
934
  aborted: NullType,
@@ -1476,16 +1571,21 @@ export type GcResult = ValueTypeOf<typeof GcResultType>;
1476
1571
  export type AsyncOperationStatus = ValueTypeOf<typeof AsyncOperationStatusType>;
1477
1572
  export type GcStartResult = ValueTypeOf<typeof GcStartResultType>;
1478
1573
  export type GcStatusResult = ValueTypeOf<typeof GcStatusResultType>;
1574
+ export type RepositoryRemoval = ValueTypeOf<typeof RepositoryRemovalType>;
1479
1575
  export type PackageListItem = ValueTypeOf<typeof PackageListItemType>;
1480
1576
  export type PackageInfo = ValueTypeOf<typeof PackageInfoType>;
1481
1577
  export type PackageDetails = ValueTypeOf<typeof PackageDetailsType>;
1482
1578
  export type WorkspaceInfo = ValueTypeOf<typeof WorkspaceInfoType>;
1483
1579
  export type WorkspaceCreateRequest = ValueTypeOf<typeof WorkspaceCreateRequestType>;
1580
+ export type WorkspaceCopyRequest = ValueTypeOf<typeof WorkspaceCopyRequestType>;
1484
1581
  export type WorkspaceDeployRequest = ValueTypeOf<typeof WorkspaceDeployRequestType>;
1485
1582
  /** A {@link SchemaPolicyType} by its name, as a deploy's options take it. */
1486
1583
  export type SchemaPolicy = ValueTypeOf<typeof SchemaPolicyType>['type'];
1584
+ /** An {@link InputPolicyType} by its name, as a deploy's options take it. */
1585
+ export type InputPolicy = ValueTypeOf<typeof InputPolicyType>['type'];
1487
1586
  export type RecordPlan = ValueTypeOf<typeof RecordPlanType>;
1488
1587
  export type RecordIndexPlan = ValueTypeOf<typeof RecordIndexPlanType>;
1588
+ export type InputPlan = ValueTypeOf<typeof InputPlanType>;
1489
1589
  export type RecordDeployStep = ValueTypeOf<typeof RecordDeployStepType>;
1490
1590
  export type RecordDeployState = ValueTypeOf<typeof RecordDeployStateType>;
1491
1591
  export type DeployProgress = ValueTypeOf<typeof DeployProgressType>;
package/src/dataflow.ts CHANGED
@@ -598,6 +598,9 @@ export function decodeDataflowExecutionState(data: Uint8Array): DataflowExecutio
598
598
  * run. A store may keep it beside the state, written with each change of the
599
599
  * state; one that reads the whole state anyway derives it
600
600
  * ({@link executionStateSummary}).
601
+ *
602
+ * Nothing stores the summary as this type: a store that keeps one beside the
603
+ * state keeps it in its own form.
601
604
  */
602
605
  export const ExecutionStateSummaryType = StructType({
603
606
  /** The run's id, a UUIDv7 */
@@ -620,6 +623,11 @@ export const ExecutionStateSummaryType = StructType({
620
623
  error: OptionType(StringType),
621
624
  /** The sequence number of the run's last event: 0 while it has none */
622
625
  lastSeq: IntegerType,
626
+ /** Whether a cancel of the run is recorded that the run has not yet applied:
627
+ * a run asked to stop, whose tasks run in other processes or machines, that
628
+ * has not yet stopped. A poll answers such a run `stopping`. A store whose
629
+ * runs a cancel stops in place records none. */
630
+ cancelRequested: BooleanType,
623
631
  });
624
632
  export type ExecutionStateSummary = ValueTypeOf<typeof ExecutionStateSummaryType>;
625
633
 
@@ -644,7 +652,9 @@ export function lastEventSeq(state: Pick<DataflowExecutionState, 'events' | 'eve
644
652
  *
645
653
  * @param state - The run's state
646
654
  * @returns Its summary: its last event's sequence number is the last event's
647
- * own ({@link lastEventSeq}), however the event was recorded
655
+ * own ({@link lastEventSeq}), however the event was recorded; and no cancel
656
+ * requested, since the state records none — a run a cancel stops in place
657
+ * ends `cancelled`
648
658
  */
649
659
  export function executionStateSummary(state: DataflowExecutionState): ExecutionStateSummary {
650
660
  return {
@@ -658,6 +668,7 @@ export function executionStateSummary(state: DataflowExecutionState): ExecutionS
658
668
  completedAt: state.completedAt,
659
669
  error: state.error,
660
670
  lastSeq: lastEventSeq(state),
671
+ cancelRequested: false,
661
672
  };
662
673
  }
663
674
 
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+
6
+ import { describe, it } from 'node:test';
7
+ import assert from 'node:assert/strict';
8
+ import { IntegerType, StringType, StructType, variant, type EastTypeValue } from '@elaraai/east';
9
+ import { checkDatasetType } from './dataset-type.js';
10
+
11
+ /** A tree of `head`s, its wrapper numbered `id`, as a build or a header numbers it. */
12
+ const tree = (id: bigint, head: EastTypeValue): EastTypeValue => variant('Recursive', variant('wrapper', {
13
+ id,
14
+ inner: variant('Struct', [
15
+ { name: 'head', type: head },
16
+ { name: 'kids', type: variant('Array', variant('Recursive', variant('ref', id))) },
17
+ ]),
18
+ }));
19
+ const integer: EastTypeValue = variant('Integer', null);
20
+ const string: EastTypeValue = variant('String', null);
21
+
22
+ describe('checkDatasetType', () => {
23
+ it('passes the declared type, and names the first difference of another', () => {
24
+ const Row = StructType({ id: IntegerType, name: StringType });
25
+ assert.equal(checkDatasetType("dataset '.inputs.rows'", 'the value', Row, Row), null);
26
+ const mismatch = checkDatasetType("dataset '.inputs.rows'", 'the value', Row, StructType({ id: IntegerType, name: IntegerType }));
27
+ assert.match(mismatch?.message ?? '', /^dataset '\.inputs\.rows' declares .* but the value carries .* — first difference at /);
28
+ });
29
+
30
+ it('reads a recursive type by its structure: one id on both sides is not one type (#1233)', () => {
31
+ assert.notEqual(checkDatasetType("dataset '.inputs.tree'", 'the value', tree(0n, integer), tree(0n, string)), null,
32
+ 'a tree of strings is not a tree of integers, whatever id each gives its wrapper');
33
+ assert.equal(checkDatasetType("dataset '.inputs.tree'", 'the value', tree(228n, integer), tree(0n, integer)), null,
34
+ "a build's ids and a header's name one structure");
35
+ });
36
+ });
@@ -24,14 +24,22 @@
24
24
  *
25
25
  * **Equality, not assignability.** A runner decodes the object *by the declared
26
26
  * type* and beast2 decoding is type-directed, so a blob that is merely a
27
- * subtype still decodes wrong. `isTypeValueEqual` is the relation.
27
+ * subtype still decodes wrong.
28
+ *
29
+ * **Read by structure.** The bytes may come from another build than the
30
+ * package's — an app's UI deployed apart from its package, any client — and
31
+ * each build numbers its recursive types by its own counter, so a recursive
32
+ * type edited between two builds can keep its id. `isTypeValueEqual` takes one
33
+ * id as one type without reading it; `isTypeValueStructurallyEqual`, the
34
+ * relation here, reads it, at under a millisecond for a type as large as a UI
35
+ * component's.
28
36
  *
29
37
  * @packageDocumentation
30
38
  */
31
39
 
32
40
  import {
33
41
  diffTypeValues,
34
- isTypeValueEqual,
42
+ isTypeValueStructurallyEqual,
35
43
  isVariant,
36
44
  printTypeValueSummary,
37
45
  renderTypeDiff,
@@ -85,7 +93,7 @@ export function checkDatasetType(
85
93
  ): DatasetTypeMismatch | null {
86
94
  const declaredValue = asTypeValue(declared);
87
95
  const givenValue = asTypeValue(given);
88
- if (isTypeValueEqual(declaredValue, givenValue)) return null;
96
+ if (isTypeValueStructurallyEqual(declaredValue, givenValue)) return null;
89
97
 
90
98
  // Equality failed, so a diff normally localizes it — except where the two are
91
99
  // assignable but unequal (a subtype, or the same struct fields in another
package/src/index.ts CHANGED
@@ -325,17 +325,21 @@ export {
325
325
  AsyncOperationStatusType,
326
326
  GcStartResultType,
327
327
  GcStatusResultType,
328
+ RepositoryRemovalType,
328
329
  // Packages
329
330
  PackageListItemType,
330
331
  PackageInfoType,
331
332
  PackageDetailsType,
332
333
  // Workspaces
333
334
  WorkspaceCreateRequestType,
335
+ WorkspaceCopyRequestType,
334
336
  WorkspaceInfoType,
335
337
  SchemaPolicyType,
338
+ InputPolicyType,
336
339
  WorkspaceDeployRequestType,
337
340
  RecordPlanType,
338
341
  RecordIndexPlanType,
342
+ InputPlanType,
339
343
  RecordDeployStepType,
340
344
  RecordDeployStateType,
341
345
  DeployProgressType,
@@ -418,15 +422,19 @@ export {
418
422
  type AsyncOperationStatus,
419
423
  type GcStartResult,
420
424
  type GcStatusResult,
425
+ type RepositoryRemoval,
421
426
  type PackageListItem,
422
427
  type PackageInfo,
423
428
  type PackageDetails,
424
429
  type WorkspaceInfo,
425
430
  type WorkspaceCreateRequest,
431
+ type WorkspaceCopyRequest,
426
432
  type WorkspaceDeployRequest,
427
433
  type SchemaPolicy,
434
+ type InputPolicy,
428
435
  type RecordPlan,
429
436
  type RecordIndexPlan,
437
+ type InputPlan,
430
438
  type RecordDeployStep,
431
439
  type RecordDeployState,
432
440
  type DeployProgress,
package/src/lock.ts CHANGED
@@ -35,6 +35,11 @@ import { DeployProgressType } from './api.js';
35
35
 
36
36
  /**
37
37
  * Lock operation - what acquired the lock.
38
+ *
39
+ * @remarks
40
+ * A lock's state is stored, so a case it gains is named to sort after every
41
+ * case before it: its tag is then the last, and a lock an earlier release left
42
+ * still reads as itself.
38
43
  */
39
44
  export const LockOperationType = VariantType({
40
45
  /** Running a dataflow */
@@ -47,6 +52,9 @@ export const LockOperationType = VariantType({
47
52
  dataset_write: NullType,
48
53
  /** Exporting a workspace */
49
54
  export: NullType,
55
+ /** Copying a workspace: the one copied, held shared, and the one it is
56
+ * copied onto, held exclusively */
57
+ workspace_copy: NullType,
50
58
  });
51
59
 
52
60
  export type LockOperation = ValueTypeOf<typeof LockOperationType>;
package/src/release.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  */
18
18
 
19
19
  /** The release of e3 this build is. */
20
- export const E3_RELEASE = '1.0.86';
20
+ export const E3_RELEASE = '1.0.88';
21
21
 
22
22
  /** A semantic version: its core, a pre-release, and build metadata. */
23
23
  const RELEASE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
package/src/task.ts CHANGED
@@ -91,7 +91,9 @@ export type TaskOutput = ValueTypeOf<typeof TaskOutputType>;
91
91
  *
92
92
  * @property paths - Dataset paths it reads or writes through `Data.bind`,
93
93
  * including each bound record's own path, so the record's current value is
94
- * preloaded and polled like any dataset.
94
+ * preloaded and polled like any dataset — but a record it also reads a
95
+ * window at a time (`pages`), which is never preloaded or polled whole
96
+ * (#1199).
95
97
  * @property functions - Package functions it calls through `Func.bind`.
96
98
  * @property records - Records it binds through `Record.bind`.
97
99
  * @property pages - Dataset paths it reads a window at a time through