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