@dxos/functions 0.8.4-main.72ec0f3 → 0.8.4-main.7ace549

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.
@@ -45,11 +45,12 @@ import { assertArgument, failedInvariant } from "@dxos/invariant";
45
45
  var Function_exports = {};
46
46
  __export(Function_exports, {
47
47
  Function: () => Function,
48
- make: () => make2
48
+ make: () => make2,
49
+ setFrom: () => setFrom
49
50
  });
50
51
  import * as Schema2 from "effect/Schema";
51
- import { Obj as Obj2, Type as Type2 } from "@dxos/echo";
52
- import { JsonSchemaType, LabelAnnotation as LabelAnnotation2, Ref as Ref2 } from "@dxos/echo/internal";
52
+ import { Annotation as Annotation2, JsonSchema, Obj as Obj2, Type as Type2 } from "@dxos/echo";
53
+ import { SystemTypeAnnotation } from "@dxos/echo/internal";
53
54
 
54
55
  // src/types/Script.ts
55
56
  var Script_exports = {};
@@ -58,20 +59,20 @@ __export(Script_exports, {
58
59
  make: () => make
59
60
  });
60
61
  import * as Schema from "effect/Schema";
61
- import { Obj, Ref, Type } from "@dxos/echo";
62
- import { FormAnnotation, LabelAnnotation } from "@dxos/echo/internal";
62
+ import { Annotation, Obj, Ref, Type } from "@dxos/echo";
63
+ import { FormInputAnnotation } from "@dxos/echo/internal";
63
64
  import { Text } from "@dxos/schema";
64
65
  var Script = Schema.Struct({
65
66
  name: Schema.String.pipe(Schema.optional),
66
67
  description: Schema.String.pipe(Schema.optional),
67
68
  // TODO(burdon): Change to hash of deployed content.
68
69
  // Whether source has changed since last deploy.
69
- changed: Schema.Boolean.pipe(FormAnnotation.set(false), Schema.optional),
70
- source: Type.Ref(Text.Text).pipe(FormAnnotation.set(false))
70
+ changed: Schema.Boolean.pipe(FormInputAnnotation.set(false), Schema.optional),
71
+ source: Type.Ref(Text.Text).pipe(FormInputAnnotation.set(false))
71
72
  }).pipe(Type.Obj({
72
73
  typename: "dxos.org/type/Script",
73
74
  version: "0.1.0"
74
- }), LabelAnnotation.set([
75
+ }), Annotation.LabelAnnotation.set([
75
76
  "name"
76
77
  ]));
77
78
  var make = ({ source = "", ...props } = {}) => Obj.make(Script, {
@@ -91,7 +92,6 @@ var Function = Schema2.Struct({
91
92
  key: Schema2.optional(Schema2.String).annotations({
92
93
  description: "Unique registration key for the blueprint"
93
94
  }),
94
- // TODO(burdon): Rename to id/uri?
95
95
  name: Schema2.NonEmptyString,
96
96
  version: Schema2.String,
97
97
  description: Schema2.optional(Schema2.String),
@@ -101,9 +101,9 @@ var Function = Schema2.Struct({
101
101
  updated: Schema2.optional(Schema2.String),
102
102
  // Reference to a source script if it exists within ECHO.
103
103
  // TODO(burdon): Don't ref ScriptType directly (core).
104
- source: Schema2.optional(Ref2(Script)),
105
- inputSchema: Schema2.optional(JsonSchemaType),
106
- outputSchema: Schema2.optional(JsonSchemaType),
104
+ source: Schema2.optional(Type2.Ref(Script)),
105
+ inputSchema: Schema2.optional(JsonSchema.JsonSchema),
106
+ outputSchema: Schema2.optional(JsonSchema.JsonSchema),
107
107
  /**
108
108
  * List of required services.
109
109
  * Match the Context.Tag keys of the FunctionServices variants.
@@ -114,10 +114,20 @@ var Function = Schema2.Struct({
114
114
  }).pipe(Type2.Obj({
115
115
  typename: "dxos.org/type/Function",
116
116
  version: "0.1.0"
117
- }), LabelAnnotation2.set([
117
+ }), Annotation2.LabelAnnotation.set([
118
118
  "name"
119
- ]));
119
+ ]), SystemTypeAnnotation.set(true));
120
120
  var make2 = (props) => Obj2.make(Function, props);
121
+ var setFrom = (target, source) => {
122
+ target.key = source.key ?? target.key;
123
+ target.name = source.name ?? target.name;
124
+ target.version = source.version;
125
+ target.description = source.description;
126
+ target.updated = source.updated;
127
+ target.inputSchema = source.inputSchema ? JSON.parse(JSON.stringify(source.inputSchema)) : void 0;
128
+ target.outputSchema = source.outputSchema ? JSON.parse(JSON.stringify(source.outputSchema)) : void 0;
129
+ Obj2.getMeta(target).keys = JSON.parse(JSON.stringify(Obj2.getMeta(source).keys));
130
+ };
121
131
 
122
132
  // src/types/Trigger.ts
123
133
  var Trigger_exports = {};
@@ -135,7 +145,7 @@ __export(Trigger_exports, {
135
145
  import * as Schema3 from "effect/Schema";
136
146
  import * as SchemaAST from "effect/SchemaAST";
137
147
  import { Obj as Obj3, QueryAST, Type as Type3 } from "@dxos/echo";
138
- import { Expando, OptionsAnnotationId, Ref as Ref3 } from "@dxos/echo/internal";
148
+ import { OptionsAnnotationId, SystemTypeAnnotation as SystemTypeAnnotation2 } from "@dxos/echo/internal";
139
149
  import { DXN } from "@dxos/keys";
140
150
  var Kinds = [
141
151
  "email",
@@ -206,7 +216,7 @@ var Trigger_ = Schema3.Struct({
206
216
  * Function or workflow to invoke.
207
217
  */
208
218
  // TODO(dmaretskyi): Can be a Ref(FunctionType) or Ref(ComputeGraphType).
209
- function: Schema3.optional(Ref3(Expando).annotations({
219
+ function: Schema3.optional(Type3.Ref(Type3.Expando).annotations({
210
220
  title: "Function"
211
221
  })),
212
222
  /**
@@ -239,7 +249,7 @@ var Trigger_ = Schema3.Struct({
239
249
  }).pipe(Type3.Obj({
240
250
  typename: "dxos.org/type/Trigger",
241
251
  version: "0.1.0"
242
- }));
252
+ }), SystemTypeAnnotation2.set(true));
243
253
  var Trigger = Trigger_;
244
254
  var make3 = (props) => Obj3.make(Trigger, props);
245
255
 
@@ -316,7 +326,7 @@ var setUserFunctionIdInMetadata = (meta, functionId) => {
316
326
 
317
327
  // src/sdk.ts
318
328
  var typeId = Symbol.for("@dxos/functions/FunctionDefinition");
319
- var defineFunction = ({ key, name, description, inputSchema, outputSchema = Schema5.Any, handler, services }) => {
329
+ var defineFunction = ({ key, name, description, inputSchema, outputSchema = Schema5.Any, handler, types, services }) => {
320
330
  if (!Schema5.isSchema(inputSchema)) {
321
331
  throw new Error("Input schema must be a valid schema");
322
332
  }
@@ -357,6 +367,7 @@ var defineFunction = ({ key, name, description, inputSchema, outputSchema = Sche
357
367
  inputSchema,
358
368
  outputSchema,
359
369
  handler: handlerWithSpan,
370
+ types: types ?? [],
360
371
  services: !services ? [] : getServiceKeys(services)
361
372
  };
362
373
  };
@@ -411,6 +422,7 @@ var deserializeFunction = (functionObj) => {
411
422
  handler: () => {
412
423
  },
413
424
  services: functionObj.services ?? [],
425
+ types: [],
414
426
  meta: {
415
427
  deployedFunctionId: getUserFunctionIdInMetadata(Obj5.getMeta(functionObj))
416
428
  }
@@ -790,11 +802,76 @@ import * as Layer5 from "effect/Layer";
790
802
  import * as Schema10 from "effect/Schema";
791
803
  import * as SchemaAST2 from "effect/SchemaAST";
792
804
  import { AiService } from "@dxos/ai";
805
+ import { LifecycleState, Resource } from "@dxos/context";
793
806
  import { Type as Type7 } from "@dxos/echo";
794
807
  import { EchoClient } from "@dxos/echo-db";
795
- import { acquireReleaseResource } from "@dxos/effect";
796
- import { failedInvariant as failedInvariant2, invariant as invariant2 } from "@dxos/invariant";
808
+ import { assertState, failedInvariant as failedInvariant2, invariant as invariant2 } from "@dxos/invariant";
797
809
  import { PublicKey } from "@dxos/keys";
810
+ function _ts_add_disposable_resource(env, value2, async) {
811
+ if (value2 !== null && value2 !== void 0) {
812
+ if (typeof value2 !== "object" && typeof value2 !== "function") throw new TypeError("Object expected.");
813
+ var dispose, inner;
814
+ if (async) {
815
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
816
+ dispose = value2[Symbol.asyncDispose];
817
+ }
818
+ if (dispose === void 0) {
819
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
820
+ dispose = value2[Symbol.dispose];
821
+ if (async) inner = dispose;
822
+ }
823
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
824
+ if (inner) dispose = function() {
825
+ try {
826
+ inner.call(this);
827
+ } catch (e) {
828
+ return Promise.reject(e);
829
+ }
830
+ };
831
+ env.stack.push({
832
+ value: value2,
833
+ dispose,
834
+ async
835
+ });
836
+ } else if (async) {
837
+ env.stack.push({
838
+ async: true
839
+ });
840
+ }
841
+ return value2;
842
+ }
843
+ function _ts_dispose_resources(env) {
844
+ var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function(error, suppressed, message) {
845
+ var e = new Error(message);
846
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
847
+ };
848
+ return (_ts_dispose_resources = function _ts_dispose_resources2(env2) {
849
+ function fail(e) {
850
+ env2.error = env2.hasError ? new _SuppressedError(e, env2.error, "An error was suppressed during disposal.") : e;
851
+ env2.hasError = true;
852
+ }
853
+ var r, s = 0;
854
+ function next() {
855
+ while (r = env2.stack.pop()) {
856
+ try {
857
+ if (!r.async && s === 1) return s = 0, env2.stack.push(r), Promise.resolve().then(next);
858
+ if (r.dispose) {
859
+ var result = r.dispose.call(r.value);
860
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) {
861
+ fail(e);
862
+ return next();
863
+ });
864
+ } else s |= 1;
865
+ } catch (e) {
866
+ fail(e);
867
+ }
868
+ }
869
+ if (s === 1) return env2.hasError ? Promise.reject(env2.error) : Promise.resolve();
870
+ if (env2.hasError) throw env2.error;
871
+ }
872
+ return next();
873
+ })(env);
874
+ }
798
875
  var __dxlog_file2 = "/__w/dxos/dxos/packages/core/functions/src/protocol/protocol.ts";
799
876
  var wrapFunctionHandler = (func) => {
800
877
  if (!FunctionDefinition.isFunction(func)) {
@@ -816,75 +893,101 @@ var wrapFunctionHandler = (func) => {
816
893
  });
817
894
  }
818
895
  try {
819
- if (!SchemaAST2.isAnyKeyword(func.inputSchema.ast)) {
820
- Schema10.validateSync(func.inputSchema)(data);
821
- }
822
- let result = await func.handler({
823
- // TODO(dmaretskyi): Fix the types.
824
- context,
825
- data
826
- });
827
- if (Effect10.isEffect(result)) {
828
- result = await Effect10.runPromise(result.pipe(Effect10.orDie, Effect10.provide(createServiceLayer(context))));
829
- }
830
- if (func.outputSchema && !SchemaAST2.isAnyKeyword(func.outputSchema.ast)) {
831
- Schema10.validateSync(func.outputSchema)(result);
832
- }
833
- return result;
834
- } catch (error) {
835
- if (FunctionError.is(error)) {
836
- throw error;
837
- } else {
838
- throw new FunctionError({
839
- cause: error,
840
- context: {
841
- func: func.key
896
+ const env = {
897
+ stack: [],
898
+ error: void 0,
899
+ hasError: false
900
+ };
901
+ try {
902
+ if (!SchemaAST2.isAnyKeyword(func.inputSchema.ast)) {
903
+ try {
904
+ Schema10.validateSync(func.inputSchema)(data);
905
+ } catch (error) {
906
+ throw new FunctionError({
907
+ message: "Invalid input schema",
908
+ cause: error
909
+ });
842
910
  }
911
+ }
912
+ const funcContext = _ts_add_disposable_resource(env, await new FunctionContext(context).open(), true);
913
+ if (func.types.length > 0) {
914
+ invariant2(funcContext.db, "Database is required for functions with types", {
915
+ F: __dxlog_file2,
916
+ L: 63,
917
+ S: void 0,
918
+ A: [
919
+ "funcContext.db",
920
+ "'Database is required for functions with types'"
921
+ ]
922
+ });
923
+ funcContext.db.graph.schemaRegistry.addSchema(func.types);
924
+ }
925
+ let result = await func.handler({
926
+ // TODO(dmaretskyi): Fix the types.
927
+ context,
928
+ data
843
929
  });
930
+ if (Effect10.isEffect(result)) {
931
+ result = await Effect10.runPromise(result.pipe(Effect10.orDie, Effect10.provide(funcContext.createLayer())));
932
+ }
933
+ if (func.outputSchema && !SchemaAST2.isAnyKeyword(func.outputSchema.ast)) {
934
+ Schema10.validateSync(func.outputSchema)(result);
935
+ }
936
+ return result;
937
+ } catch (e) {
938
+ env.error = e;
939
+ env.hasError = true;
940
+ } finally {
941
+ const result = _ts_dispose_resources(env);
942
+ if (result) await result;
844
943
  }
944
+ } catch (error) {
945
+ throw error;
845
946
  }
846
947
  }
847
948
  };
848
949
  };
849
- var createServiceLayer = (context) => {
850
- return Layer5.unwrapScoped(Effect10.gen(function* () {
851
- let client;
950
+ var FunctionContext = class extends Resource {
951
+ context;
952
+ client;
953
+ db;
954
+ queues;
955
+ constructor(context) {
956
+ super();
957
+ this.context = context;
852
958
  if (context.services.dataService && context.services.queryService) {
853
- client = yield* acquireReleaseResource(() => {
854
- invariant2(context.services.dataService && context.services.queryService, void 0, {
855
- F: __dxlog_file2,
856
- L: 99,
857
- S: this,
858
- A: [
859
- "context.services.dataService && context.services.queryService",
860
- ""
861
- ]
862
- });
863
- return new EchoClient().connectToService({
864
- dataService: context.services.dataService,
865
- queryService: context.services.queryService,
866
- queueService: context.services.queueService
867
- });
959
+ this.client = new EchoClient().connectToService({
960
+ dataService: context.services.dataService,
961
+ queryService: context.services.queryService,
962
+ queueService: context.services.queueService
868
963
  });
869
964
  }
870
- const db = client && context.spaceId ? yield* acquireReleaseResource(() => client.constructDatabase({
871
- spaceId: context.spaceId ?? failedInvariant2(),
872
- spaceKey: PublicKey.fromHex(context.spaceKey ?? failedInvariant2("spaceKey missing in context")),
965
+ }
966
+ async _open() {
967
+ await this.client?.open();
968
+ this.db = this.client && this.context.spaceId ? this.client.constructDatabase({
969
+ spaceId: this.context.spaceId ?? failedInvariant2(),
970
+ spaceKey: PublicKey.fromHex(this.context.spaceKey ?? failedInvariant2("spaceKey missing in context")),
873
971
  reactiveSchemaQuery: false
874
- })) : void 0;
875
- if (db) {
876
- console.log("Setting space root", context.spaceRootUrl);
877
- yield* Effect10.promise(() => db.setSpaceRoot(context.spaceRootUrl ?? failedInvariant2("spaceRootUrl missing in context")));
878
- }
879
- const queues = client && context.spaceId ? client.constructQueueFactory(context.spaceId) : void 0;
880
- const dbLayer = db ? DatabaseService2.layer(db) : DatabaseService2.notAvailable;
881
- const queuesLayer = queues ? QueueService.layer(queues) : QueueService.notAvailable;
972
+ }) : void 0;
973
+ await this.db?.setSpaceRoot(this.context.spaceRootUrl ?? failedInvariant2("spaceRootUrl missing in context"));
974
+ await this.db?.open();
975
+ this.queues = this.client && this.context.spaceId ? this.client.constructQueueFactory(this.context.spaceId) : void 0;
976
+ }
977
+ async _close() {
978
+ await this.db?.close();
979
+ await this.client?.close();
980
+ }
981
+ createLayer() {
982
+ assertState(this._lifecycleState === LifecycleState.OPEN, "FunctionContext is not open");
983
+ const dbLayer = this.db ? DatabaseService2.layer(this.db) : DatabaseService2.notAvailable;
984
+ const queuesLayer = this.queues ? QueueService.layer(this.queues) : QueueService.notAvailable;
882
985
  const credentials = dbLayer ? CredentialsService.layerFromDatabase().pipe(Layer5.provide(dbLayer)) : CredentialsService.configuredLayer([]);
883
986
  const functionInvocationService = MockedFunctionInvocationService;
884
987
  const aiService = AiService.notAvailable;
885
988
  const tracing = TracingService.layerNoop;
886
989
  return Layer5.mergeAll(dbLayer, queuesLayer, credentials, functionInvocationService, aiService, tracing);
887
- }));
990
+ }
888
991
  };
889
992
  var MockedFunctionInvocationService = Layer5.succeed(FunctionInvocationService, {
890
993
  invokeFunction: () => Effect10.die("Calling functions from functions is not implemented yet.")