@reboot-dev/reboot 0.34.0 → 0.35.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/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { errors_pb, IdempotencyOptions, protobuf_es, tasks_pb } from "@reboot-dev/reboot-api";
2
+ import type { StandardSchemaV1 } from "@standard-schema/spec";
2
3
  import { z } from "zod/v4";
3
4
  import * as reboot_native from "./reboot_native.cjs";
4
5
  import { Application as ExpressApplication, NextFunction as ExpressNextFunction, Request as ExpressRequest, Response as ExpressResponse } from "express";
@@ -55,8 +56,8 @@ export declare class Context {
55
56
  readonly stateId: string;
56
57
  readonly method: string;
57
58
  readonly stateTypeName: string;
58
- readonly callerBearerToken: string;
59
- readonly cookie: string;
59
+ readonly callerBearerToken: string | null;
60
+ readonly cookie: string | null;
60
61
  readonly appInternal: boolean;
61
62
  readonly auth: Auth | null;
62
63
  constructor({ external, stateId, method, stateTypeName, callerBearerToken, cookie, appInternal, auth, cancelled, }: {
@@ -64,8 +65,8 @@ export declare class Context {
64
65
  stateId: string;
65
66
  method: string;
66
67
  stateTypeName: string;
67
- callerBearerToken: string;
68
- cookie: string;
68
+ callerBearerToken: string | null;
69
+ cookie: string | null;
69
70
  appInternal: boolean;
70
71
  auth: Auth | null;
71
72
  cancelled: Promise<void>;
@@ -245,7 +246,7 @@ export declare namespace Application {
245
246
  }
246
247
  }
247
248
  export declare function retryReactivelyUntil(context: WorkflowContext, condition: () => Promise<boolean>): Promise<void>;
248
- export declare function retryReactivelyUntil<T>(context: WorkflowContext, condition: () => Promise<false | Exclude<T, boolean>>): Promise<Exclude<T, boolean>>;
249
+ export declare function retryReactivelyUntil<T>(context: WorkflowContext, condition: () => Promise<false | T>): Promise<T>;
249
250
  export declare const ALWAYS: "ALWAYS";
250
251
  export declare const PER_WORKFLOW: "PER_WORKFLOW";
251
252
  export declare const PER_ITERATION: "PER_ITERATION";
@@ -255,99 +256,49 @@ export type AtMostLeastOnceTupleType = [
255
256
  "PER_WORKFLOW" | "PER_ITERATION"
256
257
  ];
257
258
  export declare function atMostOnce(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<void>, options?: {
258
- stringify?: undefined;
259
- parse?: undefined;
260
- validate?: undefined;
259
+ schema?: undefined;
261
260
  }): Promise<void>;
262
- export declare function atMostOnce<T>(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<T>, options: {
263
- stringify?: (result: T) => string;
264
- parse: (value: string) => T;
265
- validate?: undefined;
266
- } | {
267
- stringify?: (result: T) => string;
268
- parse?: undefined;
269
- validate: (result: T) => boolean;
270
- }): Promise<T>;
261
+ export declare function atMostOnce<Schema extends StandardSchemaV1>(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<StandardSchemaV1.InferInput<Schema>>, options: {
262
+ schema: Schema;
263
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
271
264
  export declare function atMostOncePerWorkflow(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<void>, options?: {
272
- stringify?: undefined;
273
- parse?: undefined;
274
- validate?: undefined;
265
+ schema?: undefined;
275
266
  }): Promise<void>;
276
- export declare function atMostOncePerWorkflow<T>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<T>, options: {
277
- stringify?: (result: T) => string;
278
- parse: (value: string) => T;
279
- validate?: undefined;
280
- } | {
281
- stringify?: (result: T) => string;
282
- parse?: undefined;
283
- validate: (result: T) => boolean;
284
- }): Promise<T>;
267
+ export declare function atMostOncePerWorkflow<Schema extends StandardSchemaV1>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<StandardSchemaV1.InferInput<Schema>>, options: {
268
+ schema: Schema;
269
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
285
270
  export declare function atLeastOnce(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<void>, options?: {
286
- stringify?: undefined;
287
- parse?: undefined;
288
- validate?: undefined;
271
+ schema?: undefined;
289
272
  }): Promise<void>;
290
- export declare function atLeastOnce<T>(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<T>, options: {
291
- stringify?: (result: T) => string;
292
- parse: (value: string) => T;
293
- validate?: undefined;
294
- } | {
295
- stringify?: (result: T) => string;
296
- parse?: undefined;
297
- validate: (result: T) => boolean;
298
- }): Promise<T>;
273
+ export declare function atLeastOnce<Schema extends StandardSchemaV1>(idempotencyAliasOrTuple: string | AtMostLeastOnceTupleType, context: WorkflowContext, callable: () => Promise<StandardSchemaV1.InferInput<Schema>>, options: {
274
+ schema: Schema;
275
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
299
276
  export declare function atLeastOncePerWorkflow(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<void>, options?: {
300
- stringify?: undefined;
301
- parse?: undefined;
302
- validate?: undefined;
277
+ schema?: undefined;
303
278
  }): Promise<void>;
304
- export declare function atLeastOncePerWorkflow<T>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<T>, options: {
305
- stringify?: (result: T) => string;
306
- parse: (value: string) => T;
307
- validate?: undefined;
308
- } | {
309
- stringify?: (result: T) => string;
310
- parse?: undefined;
311
- validate: (result: T) => boolean;
312
- }): Promise<T>;
279
+ export declare function atLeastOncePerWorkflow<Schema extends StandardSchemaV1>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<StandardSchemaV1.InferInput<Schema>>, options: {
280
+ schema: Schema;
281
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
313
282
  export type UntilTupleType = [
314
283
  string,
315
284
  "ALWAYS" | "PER_WORKFLOW" | "PER_ITERATION"
316
285
  ];
317
286
  export declare function until(idempotencyAliasOrTuple: string | UntilTupleType, context: WorkflowContext, callable: () => Promise<boolean>, options?: {
318
- stringify?: undefined;
319
- parse?: undefined;
320
- validate?: undefined;
287
+ schema?: undefined;
321
288
  }): Promise<void>;
322
- export declare function until<T>(idempotencyAliasOrTuple: string | UntilTupleType, context: WorkflowContext, callable: () => Promise<false | Exclude<T, boolean>>, options: {
323
- stringify?: (result: T) => string;
324
- parse: (value: string) => T;
325
- validate?: undefined;
326
- } | {
327
- stringify?: (result: T) => string;
328
- parse?: undefined;
329
- validate: (result: T) => boolean;
330
- }): Promise<Exclude<T, boolean>>;
289
+ export declare function until<Schema extends StandardSchemaV1>(idempotencyAliasOrTuple: string | UntilTupleType, context: WorkflowContext, callable: () => Promise<false | StandardSchemaV1.InferInput<Schema>>, options: {
290
+ schema: Schema;
291
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
331
292
  export declare function untilPerWorkflow(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<boolean>, options?: {
332
- stringify?: undefined;
333
- parse?: undefined;
334
- validate?: undefined;
293
+ schema?: undefined;
335
294
  }): Promise<void>;
336
- export declare function untilPerWorkflow<T>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<false | Exclude<T, boolean>>, options: {
337
- stringify?: (result: T) => string;
338
- parse: (value: string) => T;
339
- validate?: undefined;
340
- } | {
341
- stringify?: (result: T) => string;
342
- parse?: undefined;
343
- validate: (result: T) => boolean;
344
- }): Promise<Exclude<T, boolean>>;
345
- export declare function untilChanges<T>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<T>, options: {
346
- equals: (previous: T, current: T) => boolean;
347
- stringify?: (result: T) => string;
348
- parse?: (value: string) => T;
349
- validate?: (result: T) => boolean;
350
- }): Promise<T>;
295
+ export declare function untilPerWorkflow<Schema extends StandardSchemaV1>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<false | StandardSchemaV1.InferInput<Schema>>, options: {
296
+ schema: Schema;
297
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
298
+ export declare function untilChanges<Schema extends StandardSchemaV1>(idempotencyAlias: string, context: WorkflowContext, callable: () => Promise<StandardSchemaV1.InferInput<Schema>>, { equals, schema, }: {
299
+ equals: (previous: StandardSchemaV1.InferOutput<Schema>, current: StandardSchemaV1.InferOutput<Schema>) => boolean;
300
+ schema: Schema;
301
+ }): Promise<StandardSchemaV1.InferOutput<Schema>>;
351
302
  export declare const zod: {
352
303
  tasks: {
353
304
  TaskId: z.ZodCustom<protobuf_es.PartialMessage<tasks_pb.TaskId>, protobuf_es.PartialMessage<tasks_pb.TaskId>>;
package/index.js CHANGED
@@ -10,8 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
12
  var _Reboot_external, _ExternalContext_external, _a, _Context_external, _Context_isInternalConstructing, _ReaderContext_kind, _WriterContext_kind, _TransactionContext_kind, _WorkflowContext_kind, _Application_servicers, _Application_tokenVerifier, _Application_express, _Application_http, _Application_servers, _Application_createExternalContext, _Application_external;
13
- import { auth_pb, errors_pb, nodejs_pb, protobuf_es, tasks_pb, toCamelCase, } from "@reboot-dev/reboot-api";
14
- import { strict as assert } from "assert";
13
+ import { assert, auth_pb, errors_pb, nodejs_pb, parse, protobuf_es, stringify, tasks_pb, toCamelCase, } from "@reboot-dev/reboot-api";
15
14
  import { AsyncLocalStorage } from "node:async_hooks";
16
15
  import { fork } from "node:child_process";
17
16
  import { createRequire } from "node:module";
@@ -726,9 +725,7 @@ export async function retryReactivelyUntil(context, condition) {
726
725
  export const ALWAYS = "ALWAYS";
727
726
  export const PER_WORKFLOW = "PER_WORKFLOW";
728
727
  export const PER_ITERATION = "PER_ITERATION";
729
- async function memoize(idempotencyAliasOrTuple, context, callable, { stringify = JSON.stringify, parse = JSON.parse, validate, atMostOnce, until = false, }) {
730
- assert(stringify !== undefined);
731
- assert(parse !== undefined);
728
+ async function memoize(idempotencyAliasOrTuple, context, callable, { schema, atMostOnce, until = false, }) {
732
729
  assert(atMostOnce !== undefined);
733
730
  if (!(typeof idempotencyAliasOrTuple === "string" ||
734
731
  (Array.isArray(idempotencyAliasOrTuple) &&
@@ -744,27 +741,38 @@ async function memoize(idempotencyAliasOrTuple, context, callable, { stringify =
744
741
  try {
745
742
  const t = await callable();
746
743
  if (t !== undefined) {
747
- if (validate === undefined) {
748
- // TODO: link to docs about why this is required, when those docs exist.
749
- throw new Error(`Result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' is not 'boolean' but 'validate' option is undefined`);
744
+ // Fail early if the developer forgot to pass `schema`.
745
+ if (schema === undefined) {
746
+ throw new Error(`Expecting 'schema' as you are returning a value from the function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}'`);
750
747
  }
751
- else if (!validate(t)) {
752
- throw new Error(`Calling 'validate' on result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' returned 'false'`);
748
+ let validate = schema["~standard"].validate(t);
749
+ if (validate instanceof Promise) {
750
+ validate = await validate;
753
751
  }
752
+ // If the `issues` field exists, the validation failed.
753
+ if (validate.issues) {
754
+ throw new Error(`Failed to validate result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}': ${JSON.stringify(validate.issues, null, 2)}`);
755
+ }
756
+ // We use `stringify` from `@reboot-dev/reboot-api` because
757
+ // it can handle `BigInt` and `Uint8Array` which are common
758
+ // types from protobuf.
759
+ //
754
760
  // NOTE: to differentiate `callable` returning `void` (or
755
- // explicitly `undefined`) from `stringify` returning an empty
756
- // string we use `{ value: stringify(t) }`.
757
- const result = { value: stringify(t) };
758
- return JSON.stringify(result);
761
+ // explicitly `undefined`) from `stringify` returning
762
+ // an empty string we use `{ value: t }`.
763
+ const result = { value: t };
764
+ return stringify(result);
759
765
  }
760
- // Fail early if the developer thinks that they have some value
761
- // that they want to validate but we got `undefined`.
762
- if (validate !== undefined) {
763
- throw new Error("Not expecting `validate` as you are returning `void` (or explicitly `undefined`); did you mean to return a value (or if you want to explicitly return the absence of a value use `null`)");
766
+ else {
767
+ // Fail early if the developer thinks that they have some
768
+ // value that they want to validate but we got `undefined`.
769
+ if (schema !== undefined) {
770
+ throw new Error(`Not expecting 'schema' as you are returning 'void' (or explicitly 'undefined') from the function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' ; did you mean to return a value (or if you want to explicitly return the absence of a value use 'null')`);
771
+ }
772
+ // NOTE: using the empty string to represent a `callable`
773
+ // returning `void` (or explicitly `undefined`).
774
+ return "";
764
775
  }
765
- // NOTE: using the empty string to represent a `callable`
766
- // returning `void` (or explicitly `undefined`).
767
- return "";
768
776
  }
769
777
  catch (e) {
770
778
  const error = ensureError(e);
@@ -782,22 +790,27 @@ async function memoize(idempotencyAliasOrTuple, context, callable, { stringify =
782
790
  // instead of the `parse` and `validate` properties we use here).
783
791
  assert(result !== undefined);
784
792
  if (result !== "") {
785
- const { value } = JSON.parse(result);
786
- const t = parse(value);
787
- if (parse !== JSON.parse) {
788
- if (validate === undefined) {
789
- throw new Error(`Result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' is not 'boolean' but 'validate' option is undefined`);
790
- }
791
- else if (!validate(t)) {
792
- throw new Error(`Calling 'validate' on result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' returned 'false'`);
793
- }
793
+ // We use `parse` from `@reboot-dev/reboot-api` because it can
794
+ // handle `BigInt` and `Uint8Array` which are common types from
795
+ // protobuf.
796
+ const { value } = parse(result);
797
+ if (schema === undefined) {
798
+ throw new Error(`Expecting 'schema' as we have already memoized a result for the function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}' has the code been updated to remove a previously existing 'schema'`);
799
+ }
800
+ let validate = schema["~standard"].validate(value);
801
+ if (validate instanceof Promise) {
802
+ validate = await validate;
803
+ }
804
+ // If the `issues` field exists, the validation failed.
805
+ if (validate.issues) {
806
+ throw new Error(`Failed to validate result of function passed to '${atMostOnce ? "atMostOnce" : until ? "until" : "atLeastOnce"}': ${JSON.stringify(validate.issues, null, 2)}`);
794
807
  }
795
- return t;
808
+ return validate.value;
796
809
  }
797
810
  // Otherwise `callable` must have returned void (or explicitly
798
811
  // `undefined`), fall through.
799
812
  }
800
- export async function atMostOnce(idempotencyAliasOrTuple, context, callable, options = { validate: undefined }) {
813
+ export async function atMostOnce(idempotencyAliasOrTuple, context, callable, options = {}) {
801
814
  try {
802
815
  return await memoize(idempotencyAliasOrTuple, context, callable, {
803
816
  ...options,
@@ -811,19 +824,19 @@ export async function atMostOnce(idempotencyAliasOrTuple, context, callable, opt
811
824
  throw e;
812
825
  }
813
826
  }
814
- export async function atMostOncePerWorkflow(idempotencyAlias, context, callable, options = { validate: undefined }) {
827
+ export async function atMostOncePerWorkflow(idempotencyAlias, context, callable, options = {}) {
815
828
  return atMostOnce([idempotencyAlias, PER_WORKFLOW], context, callable, options);
816
829
  }
817
- export async function atLeastOnce(idempotencyAliasOrTuple, context, callable, options = { validate: undefined }) {
830
+ export async function atLeastOnce(idempotencyAliasOrTuple, context, callable, options = {}) {
818
831
  return memoize(idempotencyAliasOrTuple, context, callable, {
819
832
  ...options,
820
833
  atMostOnce: false,
821
834
  });
822
835
  }
823
- export async function atLeastOncePerWorkflow(idempotencyAlias, context, callable, options = { validate: undefined }) {
836
+ export async function atLeastOncePerWorkflow(idempotencyAlias, context, callable, options = {}) {
824
837
  return await atLeastOnce([idempotencyAlias, PER_WORKFLOW], context, callable, options);
825
838
  }
826
- export async function until(idempotencyAliasOrTuple, context, callable, options = { validate: undefined }) {
839
+ export async function until(idempotencyAliasOrTuple, context, callable, options = {}) {
827
840
  // TODO(benh): figure out how to not use `as` type assertions here
828
841
  // to appease the TypeScript compiler which otherwise isn't happy
829
842
  // with passing on these types.
@@ -838,26 +851,25 @@ export async function until(idempotencyAliasOrTuple, context, callable, options
838
851
  until: true,
839
852
  });
840
853
  }
841
- export async function untilPerWorkflow(idempotencyAlias, context, callable, options = { validate: undefined }) {
854
+ export async function untilPerWorkflow(idempotencyAlias, context, callable, options = {}) {
842
855
  return await until([idempotencyAlias, PER_WORKFLOW], context, callable, options);
843
856
  }
844
- export async function untilChanges(idempotencyAlias, context, callable, options) {
857
+ export async function untilChanges(idempotencyAlias, context, callable, { equals, schema, }) {
845
858
  const iteration = getLoopIteration();
846
859
  if (iteration === undefined) {
847
860
  throw new Error("Waiting for changes must be done _within_ a control loop");
848
861
  }
849
- if (options.equals === undefined) {
862
+ if (equals === undefined) {
850
863
  // TODO: don't make `equals` required, instead use one of the
851
864
  // various libraries that does deep equality.
852
865
  throw new Error("Missing 'equals' option");
853
866
  }
854
- const { equals, ...optionsWithoutEquals } = options;
855
867
  let previous = null;
856
868
  if (iteration > 0) {
857
869
  // Get the previous memoized result!
858
870
  previous = (await untilPerWorkflow(`${idempotencyAlias} #${iteration - 1}`, context, (async () => {
859
871
  throw new Error(`Missing memoized value for '${idempotencyAlias}'`);
860
- }), optionsWithoutEquals));
872
+ }), { schema }));
861
873
  }
862
874
  // Wait until previous result does not equal current result.
863
875
  return (await untilPerWorkflow(`${idempotencyAlias} #${iteration}`, context, (async () => {
@@ -870,7 +882,7 @@ export async function untilChanges(idempotencyAlias, context, callable, options)
870
882
  return current;
871
883
  }
872
884
  return false;
873
- }), optionsWithoutEquals));
885
+ }), { schema }));
874
886
  }
875
887
  const launchSubprocessConsensus = (base64_args) => {
876
888
  // Create a child process via `fork` (which does not mean `fork` as
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "@bufbuild/protobuf": "1.3.2",
4
4
  "@bufbuild/protoplugin": "1.3.2",
5
5
  "@bufbuild/protoc-gen-es": "1.3.2",
6
- "@reboot-dev/reboot-api": "0.34.0",
6
+ "@reboot-dev/reboot-api": "0.35.0",
7
7
  "chalk": "^4.1.2",
8
8
  "node-addon-api": "^7.0.0",
9
9
  "node-gyp": ">=10.2.0",
@@ -15,11 +15,12 @@
15
15
  "@scarf/scarf": "1.4.0",
16
16
  "tsx": "^4.19.2",
17
17
  "zod": "^3.25.51",
18
- "toobusy-js": "^0.5.1"
18
+ "toobusy-js": "^0.5.1",
19
+ "@standard-schema/spec": "1.0.0"
19
20
  },
20
21
  "type": "module",
21
22
  "name": "@reboot-dev/reboot",
22
- "version": "0.34.0",
23
+ "version": "0.35.0",
23
24
  "description": "npm package for Reboot",
24
25
  "scripts": {
25
26
  "preinstall": "node preinstall.cjs",
package/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const REBOOT_VERSION = "0.34.0";
1
+ export declare const REBOOT_VERSION = "0.35.0";
package/version.js CHANGED
@@ -1 +1 @@
1
- export const REBOOT_VERSION = "0.34.0";
1
+ export const REBOOT_VERSION = "0.35.0";