@dxos/functions 0.8.4-main.a4bbb77 → 0.8.4-main.ae835ea
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/dist/lib/browser/bundler/index.mjs +16 -25
- package/dist/lib/browser/bundler/index.mjs.map +3 -3
- package/dist/lib/browser/chunk-M6EXIREF.mjs +610 -0
- package/dist/lib/browser/chunk-M6EXIREF.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +957 -977
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +8 -6
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/bundler/index.mjs +16 -25
- package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-P3IATZMZ.mjs +612 -0
- package/dist/lib/node-esm/chunk-P3IATZMZ.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +957 -977
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs +8 -6
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/bundler/bundler.d.ts.map +1 -1
- package/dist/types/src/e2e/deploy.test.d.ts +2 -0
- package/dist/types/src/e2e/deploy.test.d.ts.map +1 -0
- package/dist/types/src/example/fib.d.ts.map +1 -0
- package/dist/types/src/example/forex-effect.d.ts +3 -0
- package/dist/types/src/example/forex-effect.d.ts.map +1 -0
- package/dist/types/src/example/index.d.ts +12 -0
- package/dist/types/src/example/index.d.ts.map +1 -0
- package/dist/types/src/example/reply.d.ts.map +1 -0
- package/dist/types/src/example/sleep.d.ts.map +1 -0
- package/dist/types/src/executor/executor.d.ts.map +1 -1
- package/dist/types/src/handler.d.ts +20 -24
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +4 -5
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/services/credentials.d.ts +6 -2
- package/dist/types/src/services/credentials.d.ts.map +1 -1
- package/dist/types/src/services/database.d.ts +6 -2
- package/dist/types/src/services/database.d.ts.map +1 -1
- package/dist/types/src/services/event-logger.d.ts +4 -1
- package/dist/types/src/services/event-logger.d.ts.map +1 -1
- package/dist/types/src/services/function-invocation-service.d.ts +5 -3
- package/dist/types/src/services/function-invocation-service.d.ts.map +1 -1
- package/dist/types/src/services/local-function-execution.d.ts +5 -3
- package/dist/types/src/services/local-function-execution.d.ts.map +1 -1
- package/dist/types/src/services/queues.d.ts +3 -1
- package/dist/types/src/services/queues.d.ts.map +1 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts +3 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -1
- package/dist/types/src/services/service-container.d.ts +2 -1
- package/dist/types/src/services/service-container.d.ts.map +1 -1
- package/dist/types/src/services/service-registry.d.ts +3 -1
- package/dist/types/src/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/services/tracing.d.ts +4 -2
- package/dist/types/src/services/tracing.d.ts.map +1 -1
- package/dist/types/src/testing/layer.d.ts +3 -2
- package/dist/types/src/testing/layer.d.ts.map +1 -1
- package/dist/types/src/testing/logger.d.ts +1 -1
- package/dist/types/src/testing/logger.d.ts.map +1 -1
- package/dist/types/src/testing/services.d.ts +1 -1
- package/dist/types/src/testing/services.d.ts.map +1 -1
- package/dist/types/src/trace.d.ts +4 -4
- package/dist/types/src/trace.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -2
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/triggers/input-builder.d.ts +2 -2
- package/dist/types/src/triggers/input-builder.d.ts.map +1 -1
- package/dist/types/src/triggers/invocation-tracer.d.ts +5 -3
- package/dist/types/src/triggers/invocation-tracer.d.ts.map +1 -1
- package/dist/types/src/triggers/trigger-dispatcher.d.ts +10 -6
- package/dist/types/src/triggers/trigger-dispatcher.d.ts.map +1 -1
- package/dist/types/src/triggers/trigger-state-store.d.ts +5 -4
- package/dist/types/src/triggers/trigger-state-store.d.ts.map +1 -1
- package/dist/types/src/types/Function.d.ts +47 -0
- package/dist/types/src/types/Function.d.ts.map +1 -0
- package/dist/types/src/types/Script.d.ts +28 -0
- package/dist/types/src/types/Script.d.ts.map +1 -0
- package/dist/types/src/types/Trigger.d.ts +139 -0
- package/dist/types/src/types/Trigger.d.ts.map +1 -0
- package/dist/types/src/types/TriggerEvent.d.ts +44 -0
- package/dist/types/src/types/TriggerEvent.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +5 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/url.d.ts +1 -1
- package/dist/types/src/url.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +24 -36
- package/src/bundler/bundler.ts +7 -3
- package/src/e2e/deploy.test.ts +69 -0
- package/src/{examples → example}/fib.ts +2 -1
- package/src/example/forex-effect.ts +40 -0
- package/src/example/index.ts +13 -0
- package/src/{examples → example}/reply.ts +3 -1
- package/src/{examples → example}/sleep.ts +2 -1
- package/src/executor/executor.ts +2 -1
- package/src/handler.ts +23 -19
- package/src/index.ts +4 -5
- package/src/services/credentials.ts +7 -2
- package/src/services/database.ts +6 -2
- package/src/services/event-logger.ts +4 -1
- package/src/services/function-invocation-service.test.ts +3 -1
- package/src/services/function-invocation-service.ts +5 -3
- package/src/services/local-function-execution.ts +10 -7
- package/src/services/queues.ts +3 -1
- package/src/services/remote-function-execution-service.ts +3 -1
- package/src/services/service-container.ts +2 -1
- package/src/services/service-registry.test.ts +4 -1
- package/src/services/service-registry.ts +7 -3
- package/src/services/tracing.ts +4 -2
- package/src/testing/layer.ts +6 -4
- package/src/testing/logger.ts +2 -1
- package/src/testing/persist-database.test.ts +1 -1
- package/src/testing/services.ts +1 -1
- package/src/trace.ts +5 -5
- package/src/translations.ts +2 -2
- package/src/triggers/input-builder.ts +2 -2
- package/src/triggers/invocation-tracer.ts +5 -3
- package/src/triggers/trigger-dispatcher.test.ts +57 -44
- package/src/triggers/trigger-dispatcher.ts +26 -27
- package/src/triggers/trigger-state-store.ts +6 -5
- package/src/{schema.ts → types/Function.ts} +9 -26
- package/src/types/Script.ts +33 -0
- package/src/types/Trigger.ts +139 -0
- package/src/types/TriggerEvent.ts +62 -0
- package/src/types/index.ts +8 -0
- package/src/url.ts +1 -1
- package/dist/lib/browser/chunk-C2Z7LCJ2.mjs +0 -649
- package/dist/lib/browser/chunk-C2Z7LCJ2.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-AH3AZM2U.mjs +0 -651
- package/dist/lib/node-esm/chunk-AH3AZM2U.mjs.map +0 -7
- package/dist/types/src/examples/fib.d.ts.map +0 -1
- package/dist/types/src/examples/index.d.ts +0 -4
- package/dist/types/src/examples/index.d.ts.map +0 -1
- package/dist/types/src/examples/reply.d.ts.map +0 -1
- package/dist/types/src/examples/sleep.d.ts.map +0 -1
- package/dist/types/src/schema.d.ts +0 -43
- package/dist/types/src/schema.d.ts.map +0 -1
- package/dist/types/src/types.d.ts +0 -221
- package/dist/types/src/types.d.ts.map +0 -1
- package/src/examples/index.ts +0 -7
- package/src/types.ts +0 -214
- /package/dist/types/src/{examples → example}/fib.d.ts +0 -0
- /package/dist/types/src/{examples → example}/reply.d.ts +0 -0
- /package/dist/types/src/{examples → example}/sleep.d.ts +0 -0
package/src/testing/layer.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
8
|
+
import type * as Schema from 'effect/Schema';
|
|
7
9
|
|
|
8
10
|
import type { EchoDatabaseImpl, QueueFactory } from '@dxos/echo-db';
|
|
9
11
|
import { EchoTestBuilder } from '@dxos/echo-db/testing';
|
|
10
12
|
import type { EchoHostIndexingConfig } from '@dxos/echo-pipeline';
|
|
11
|
-
import {
|
|
13
|
+
import { acquireReleaseResource } from '@dxos/effect';
|
|
12
14
|
import { PublicKey } from '@dxos/keys';
|
|
13
15
|
import type { LevelDB } from '@dxos/kv-store';
|
|
14
16
|
import { createTestLevel } from '@dxos/kv-store/testing';
|
|
@@ -16,7 +18,7 @@ import { log } from '@dxos/log';
|
|
|
16
18
|
|
|
17
19
|
import { DatabaseService, QueueService } from '../services';
|
|
18
20
|
|
|
19
|
-
const testBuilder =
|
|
21
|
+
const testBuilder = acquireReleaseResource(() => new EchoTestBuilder());
|
|
20
22
|
|
|
21
23
|
export const testStoragePath = ({ name = PublicKey.random().toHex() }: { name?: string }) => {
|
|
22
24
|
return `/tmp/dxos-${name}`;
|
package/src/testing/logger.ts
CHANGED
package/src/testing/services.ts
CHANGED
package/src/trace.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Schema from 'effect/Schema';
|
|
6
6
|
|
|
7
7
|
import { type Ref, Type } from '@dxos/echo';
|
|
8
|
+
import { ObjectId } from '@dxos/echo/internal';
|
|
8
9
|
import { Queue } from '@dxos/echo-db';
|
|
9
|
-
import { ObjectId } from '@dxos/echo-schema';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
|
|
12
|
-
import {
|
|
12
|
+
import { Trigger } from './types';
|
|
13
13
|
|
|
14
14
|
export enum InvocationOutcome {
|
|
15
15
|
SUCCESS = 'success',
|
|
@@ -61,7 +61,7 @@ export const InvocationTraceStartEvent = Schema.Struct({
|
|
|
61
61
|
/**
|
|
62
62
|
* Present for automatic invocations.
|
|
63
63
|
*/
|
|
64
|
-
trigger: Schema.optional(Type.Ref(
|
|
64
|
+
trigger: Schema.optional(Type.Ref(Trigger.Trigger)),
|
|
65
65
|
}).pipe(Type.Obj({ typename: 'dxos.org/type/InvocationTraceStart', version: '0.1.0' }));
|
|
66
66
|
|
|
67
67
|
export type InvocationTraceStartEvent = Schema.Schema.Type<typeof InvocationTraceStartEvent>;
|
|
@@ -121,7 +121,7 @@ export type InvocationSpan = {
|
|
|
121
121
|
input: object;
|
|
122
122
|
invocationTraceQueue?: Ref.Ref<Queue>;
|
|
123
123
|
invocationTarget?: Ref.Ref<Type.Expando>;
|
|
124
|
-
trigger?: Ref.Ref<
|
|
124
|
+
trigger?: Ref.Ref<Trigger.Trigger>;
|
|
125
125
|
exception?: TraceEventException;
|
|
126
126
|
};
|
|
127
127
|
|
package/src/translations.ts
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Resource } from 'i18next';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Script } from './types';
|
|
8
8
|
|
|
9
9
|
export const translations = [
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
|
-
[
|
|
12
|
+
[Script.Script.typename]: {
|
|
13
13
|
'typename label': 'Script',
|
|
14
14
|
'typename label_zero': 'Scripts',
|
|
15
15
|
'typename label_one': 'Script',
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Trigger, type TriggerEvent } from '../types';
|
|
6
6
|
|
|
7
|
-
export const createInvocationPayload = (trigger:
|
|
7
|
+
export const createInvocationPayload = (trigger: Trigger.Trigger, event: TriggerEvent.TriggerEvent): any => {
|
|
8
8
|
if (!trigger.input) {
|
|
9
9
|
return event;
|
|
10
10
|
}
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Context from 'effect/Context';
|
|
6
|
+
import * as Effect from 'effect/Effect';
|
|
7
|
+
import * as Layer from 'effect/Layer';
|
|
6
8
|
|
|
7
9
|
import { Obj, Ref } from '@dxos/echo';
|
|
8
10
|
import { type Queue } from '@dxos/echo-db';
|
|
@@ -15,14 +17,14 @@ import {
|
|
|
15
17
|
InvocationTraceEventType,
|
|
16
18
|
InvocationTraceStartEvent,
|
|
17
19
|
} from '../trace';
|
|
18
|
-
import type {
|
|
20
|
+
import type { Trigger } from '../types';
|
|
19
21
|
|
|
20
22
|
export type FunctionInvocationPayload = {
|
|
21
23
|
data?: any;
|
|
22
24
|
inputNodeId?: string;
|
|
23
25
|
trigger?: {
|
|
24
26
|
id: string;
|
|
25
|
-
kind:
|
|
27
|
+
kind: Trigger.Kind;
|
|
26
28
|
};
|
|
27
29
|
};
|
|
28
30
|
|
|
@@ -2,18 +2,21 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as FetchHttpClient from '@effect/platform/FetchHttpClient';
|
|
6
6
|
import { describe, it } from '@effect/vitest';
|
|
7
|
-
import
|
|
7
|
+
import * as Duration from 'effect/Duration';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import * as Exit from 'effect/Exit';
|
|
10
|
+
import * as Fn from 'effect/Function';
|
|
11
|
+
import * as Layer from 'effect/Layer';
|
|
8
12
|
|
|
9
13
|
import { AiService } from '@dxos/ai';
|
|
10
14
|
import { Filter, Obj, Query, Ref } from '@dxos/echo';
|
|
11
15
|
import { invariant } from '@dxos/invariant';
|
|
12
16
|
import { DataType } from '@dxos/schema';
|
|
13
17
|
|
|
14
|
-
import {
|
|
18
|
+
import { Example } from '../example';
|
|
15
19
|
import { serializeFunction } from '../handler';
|
|
16
|
-
import { FunctionType } from '../schema';
|
|
17
20
|
import {
|
|
18
21
|
ComputeEventLogger,
|
|
19
22
|
CredentialsService,
|
|
@@ -23,25 +26,25 @@ import {
|
|
|
23
26
|
TracingService,
|
|
24
27
|
} from '../services';
|
|
25
28
|
import { TestDatabaseLayer } from '../testing';
|
|
26
|
-
import {
|
|
29
|
+
import { Function, Trigger } from '../types';
|
|
27
30
|
|
|
28
31
|
import { InvocationTracer } from './invocation-tracer';
|
|
29
32
|
import { TriggerDispatcher } from './trigger-dispatcher';
|
|
30
33
|
import { TriggerStateStore } from './trigger-state-store';
|
|
31
34
|
|
|
32
|
-
const TestLayer = pipe(
|
|
35
|
+
const TestLayer = Fn.pipe(
|
|
33
36
|
Layer.mergeAll(ComputeEventLogger.layerFromTracing, InvocationTracer.layerTest, TriggerStateStore.layerMemory),
|
|
34
37
|
Layer.provideMerge(
|
|
35
38
|
Layer.mergeAll(
|
|
36
39
|
AiService.notAvailable,
|
|
37
40
|
CredentialsService.layerConfig([]),
|
|
38
|
-
FunctionInvocationService.layerTestMocked({ functions: [reply] }).pipe(
|
|
41
|
+
FunctionInvocationService.layerTestMocked({ functions: [Example.reply] }).pipe(
|
|
39
42
|
Layer.provideMerge(ComputeEventLogger.layerFromTracing),
|
|
40
43
|
Layer.provideMerge(TracingService.layerLogInfo()),
|
|
41
44
|
),
|
|
42
45
|
FetchHttpClient.layer,
|
|
43
46
|
TestDatabaseLayer({
|
|
44
|
-
types: [
|
|
47
|
+
types: [Function.Function, Trigger.Trigger, DataType.Person, DataType.Task],
|
|
45
48
|
}),
|
|
46
49
|
),
|
|
47
50
|
),
|
|
@@ -76,9 +79,9 @@ describe('TriggerDispatcher', () => {
|
|
|
76
79
|
it.effect(
|
|
77
80
|
'should manually invoke trigger',
|
|
78
81
|
Effect.fnUntraced(function* ({ expect }) {
|
|
79
|
-
const functionObj = serializeFunction(reply);
|
|
82
|
+
const functionObj = serializeFunction(Example.reply);
|
|
80
83
|
yield* DatabaseService.add(functionObj);
|
|
81
|
-
const trigger =
|
|
84
|
+
const trigger = Trigger.make({
|
|
82
85
|
function: Ref.make(functionObj),
|
|
83
86
|
enabled: true,
|
|
84
87
|
spec: {
|
|
@@ -102,9 +105,9 @@ describe('TriggerDispatcher', () => {
|
|
|
102
105
|
it.effect(
|
|
103
106
|
'should invoke scheduled timer triggers',
|
|
104
107
|
Effect.fnUntraced(function* ({ expect }) {
|
|
105
|
-
const functionObj = serializeFunction(reply);
|
|
108
|
+
const functionObj = serializeFunction(Example.reply);
|
|
106
109
|
yield* DatabaseService.add(functionObj);
|
|
107
|
-
const trigger =
|
|
110
|
+
const trigger = Trigger.make({
|
|
108
111
|
function: Ref.make(functionObj),
|
|
109
112
|
enabled: true,
|
|
110
113
|
spec: {
|
|
@@ -131,10 +134,10 @@ describe('TriggerDispatcher', () => {
|
|
|
131
134
|
it.effect(
|
|
132
135
|
'should handle disabled triggers',
|
|
133
136
|
Effect.fnUntraced(function* ({ expect }) {
|
|
134
|
-
const functionObj = serializeFunction(reply);
|
|
137
|
+
const functionObj = serializeFunction(Example.reply);
|
|
135
138
|
yield* DatabaseService.add(functionObj);
|
|
136
139
|
|
|
137
|
-
const enabledTrigger =
|
|
140
|
+
const enabledTrigger = Trigger.make({
|
|
138
141
|
function: Ref.make(functionObj),
|
|
139
142
|
enabled: true,
|
|
140
143
|
spec: {
|
|
@@ -143,7 +146,7 @@ describe('TriggerDispatcher', () => {
|
|
|
143
146
|
},
|
|
144
147
|
});
|
|
145
148
|
|
|
146
|
-
const disabledTrigger =
|
|
149
|
+
const disabledTrigger = Trigger.make({
|
|
147
150
|
function: Ref.make(functionObj),
|
|
148
151
|
enabled: false,
|
|
149
152
|
spec: {
|
|
@@ -172,11 +175,11 @@ describe('TriggerDispatcher', () => {
|
|
|
172
175
|
it.effect(
|
|
173
176
|
'cron triggers are invoked periodically on schedule',
|
|
174
177
|
Effect.fnUntraced(function* ({ expect }) {
|
|
175
|
-
const functionObj = serializeFunction(reply);
|
|
178
|
+
const functionObj = serializeFunction(Example.reply);
|
|
176
179
|
yield* DatabaseService.add(functionObj);
|
|
177
180
|
|
|
178
181
|
// cron every 5 minutes
|
|
179
|
-
const trigger =
|
|
182
|
+
const trigger = Trigger.make({
|
|
180
183
|
function: Ref.make(functionObj),
|
|
181
184
|
enabled: true,
|
|
182
185
|
spec: {
|
|
@@ -223,9 +226,9 @@ describe('TriggerDispatcher', () => {
|
|
|
223
226
|
// Initially no triggers in database
|
|
224
227
|
|
|
225
228
|
// Add a trigger dynamically
|
|
226
|
-
const functionObj = serializeFunction(reply);
|
|
229
|
+
const functionObj = serializeFunction(Example.reply);
|
|
227
230
|
yield* DatabaseService.add(functionObj);
|
|
228
|
-
const trigger =
|
|
231
|
+
const trigger = Trigger.make({
|
|
229
232
|
function: Ref.make(functionObj),
|
|
230
233
|
enabled: true,
|
|
231
234
|
spec: {
|
|
@@ -246,7 +249,7 @@ describe('TriggerDispatcher', () => {
|
|
|
246
249
|
it.effect(
|
|
247
250
|
'should support Effect cron expressions',
|
|
248
251
|
Effect.fnUntraced(function* ({ expect }) {
|
|
249
|
-
const functionObj = serializeFunction(reply);
|
|
252
|
+
const functionObj = serializeFunction(Example.reply);
|
|
250
253
|
yield* DatabaseService.add(functionObj);
|
|
251
254
|
|
|
252
255
|
const validPatterns = [
|
|
@@ -261,7 +264,7 @@ describe('TriggerDispatcher', () => {
|
|
|
261
264
|
|
|
262
265
|
// Test that valid patterns can be invoked
|
|
263
266
|
for (const cron of validPatterns) {
|
|
264
|
-
const trigger =
|
|
267
|
+
const trigger = Trigger.make({
|
|
265
268
|
function: Ref.make(functionObj),
|
|
266
269
|
enabled: true,
|
|
267
270
|
spec: {
|
|
@@ -280,11 +283,11 @@ describe('TriggerDispatcher', () => {
|
|
|
280
283
|
it.effect(
|
|
281
284
|
'should handle invalid cron expressions gracefully',
|
|
282
285
|
Effect.fnUntraced(function* ({ expect }) {
|
|
283
|
-
const functionObj = serializeFunction(reply);
|
|
286
|
+
const functionObj = serializeFunction(Example.reply);
|
|
284
287
|
yield* DatabaseService.add(functionObj);
|
|
285
288
|
|
|
286
289
|
// Test with an invalid pattern
|
|
287
|
-
const trigger =
|
|
290
|
+
const trigger = Trigger.make({
|
|
288
291
|
function: Ref.make(functionObj),
|
|
289
292
|
enabled: true,
|
|
290
293
|
spec: {
|
|
@@ -323,9 +326,9 @@ describe('TriggerDispatcher', () => {
|
|
|
323
326
|
'should invoke scheduled queue triggers',
|
|
324
327
|
Effect.fnUntraced(function* ({ expect }) {
|
|
325
328
|
const queue = yield* QueueService.createQueue();
|
|
326
|
-
const functionObj = serializeFunction(reply);
|
|
329
|
+
const functionObj = serializeFunction(Example.reply);
|
|
327
330
|
yield* DatabaseService.add(functionObj);
|
|
328
|
-
const trigger =
|
|
331
|
+
const trigger = Trigger.make({
|
|
329
332
|
function: Ref.make(functionObj),
|
|
330
333
|
enabled: true,
|
|
331
334
|
spec: {
|
|
@@ -352,9 +355,9 @@ describe('TriggerDispatcher', () => {
|
|
|
352
355
|
'triggers are invoked one by one',
|
|
353
356
|
Effect.fnUntraced(function* ({ expect }) {
|
|
354
357
|
const queue = yield* QueueService.createQueue();
|
|
355
|
-
const functionObj = serializeFunction(reply);
|
|
358
|
+
const functionObj = serializeFunction(Example.reply);
|
|
356
359
|
yield* DatabaseService.add(functionObj);
|
|
357
|
-
const trigger =
|
|
360
|
+
const trigger = Trigger.make({
|
|
358
361
|
function: Ref.make(functionObj),
|
|
359
362
|
enabled: true,
|
|
360
363
|
spec: {
|
|
@@ -399,9 +402,9 @@ describe('TriggerDispatcher', () => {
|
|
|
399
402
|
'builds input from pattern',
|
|
400
403
|
Effect.fnUntraced(function* ({ expect }) {
|
|
401
404
|
const queue = yield* QueueService.createQueue();
|
|
402
|
-
const functionObj = serializeFunction(reply);
|
|
405
|
+
const functionObj = serializeFunction(Example.reply);
|
|
403
406
|
yield* DatabaseService.add(functionObj);
|
|
404
|
-
const trigger =
|
|
407
|
+
const trigger = Trigger.make({
|
|
405
408
|
function: Ref.make(functionObj),
|
|
406
409
|
enabled: true,
|
|
407
410
|
spec: {
|
|
@@ -442,16 +445,18 @@ describe('TriggerDispatcher', () => {
|
|
|
442
445
|
it.effect(
|
|
443
446
|
'should invoke triggers on object creation',
|
|
444
447
|
Effect.fnUntraced(function* ({ expect }) {
|
|
445
|
-
const functionObj = serializeFunction(reply);
|
|
448
|
+
const functionObj = serializeFunction(Example.reply);
|
|
446
449
|
yield* DatabaseService.add(functionObj);
|
|
447
450
|
|
|
448
451
|
// Create a subscription trigger that watches for DataType.Person objects
|
|
449
|
-
const trigger =
|
|
452
|
+
const trigger = Trigger.make({
|
|
450
453
|
function: Ref.make(functionObj),
|
|
451
454
|
enabled: true,
|
|
452
455
|
spec: {
|
|
453
456
|
kind: 'subscription',
|
|
454
|
-
query:
|
|
457
|
+
query: {
|
|
458
|
+
ast: Query.select(Filter.type(DataType.Person)).ast,
|
|
459
|
+
},
|
|
455
460
|
},
|
|
456
461
|
});
|
|
457
462
|
yield* DatabaseService.add(trigger);
|
|
@@ -478,7 +483,7 @@ describe('TriggerDispatcher', () => {
|
|
|
478
483
|
it.effect(
|
|
479
484
|
'should invoke triggers on object updates',
|
|
480
485
|
Effect.fnUntraced(function* ({ expect }) {
|
|
481
|
-
const functionObj = serializeFunction(reply);
|
|
486
|
+
const functionObj = serializeFunction(Example.reply);
|
|
482
487
|
yield* DatabaseService.add(functionObj);
|
|
483
488
|
|
|
484
489
|
// Create a person object first
|
|
@@ -488,12 +493,14 @@ describe('TriggerDispatcher', () => {
|
|
|
488
493
|
yield* DatabaseService.add(person);
|
|
489
494
|
|
|
490
495
|
// Create a subscription trigger
|
|
491
|
-
const trigger =
|
|
496
|
+
const trigger = Trigger.make({
|
|
492
497
|
function: Ref.make(functionObj),
|
|
493
498
|
enabled: true,
|
|
494
499
|
spec: {
|
|
495
500
|
kind: 'subscription',
|
|
496
|
-
query:
|
|
501
|
+
query: {
|
|
502
|
+
ast: Query.select(Filter.type(DataType.Person)).ast,
|
|
503
|
+
},
|
|
497
504
|
},
|
|
498
505
|
});
|
|
499
506
|
yield* DatabaseService.add(trigger);
|
|
@@ -520,16 +527,18 @@ describe('TriggerDispatcher', () => {
|
|
|
520
527
|
it.effect(
|
|
521
528
|
'should not invoke triggers for unchanged objects',
|
|
522
529
|
Effect.fnUntraced(function* ({ expect }) {
|
|
523
|
-
const functionObj = serializeFunction(reply);
|
|
530
|
+
const functionObj = serializeFunction(Example.reply);
|
|
524
531
|
yield* DatabaseService.add(functionObj);
|
|
525
532
|
|
|
526
533
|
// Create a subscription trigger first
|
|
527
|
-
const trigger =
|
|
534
|
+
const trigger = Trigger.make({
|
|
528
535
|
function: Ref.make(functionObj),
|
|
529
536
|
enabled: true,
|
|
530
537
|
spec: {
|
|
531
538
|
kind: 'subscription',
|
|
532
|
-
query:
|
|
539
|
+
query: {
|
|
540
|
+
ast: Query.select(Filter.type(DataType.Person)).ast,
|
|
541
|
+
},
|
|
533
542
|
},
|
|
534
543
|
});
|
|
535
544
|
yield* DatabaseService.add(trigger);
|
|
@@ -568,16 +577,18 @@ describe('TriggerDispatcher', () => {
|
|
|
568
577
|
it.effect(
|
|
569
578
|
'should handle multiple object types with filters',
|
|
570
579
|
Effect.fnUntraced(function* ({ expect }) {
|
|
571
|
-
const functionObj = serializeFunction(reply);
|
|
580
|
+
const functionObj = serializeFunction(Example.reply);
|
|
572
581
|
yield* DatabaseService.add(functionObj);
|
|
573
582
|
|
|
574
583
|
// Create a subscription trigger that only watches for DataType.Task objects
|
|
575
|
-
const trigger =
|
|
584
|
+
const trigger = Trigger.make({
|
|
576
585
|
function: Ref.make(functionObj),
|
|
577
586
|
enabled: true,
|
|
578
587
|
spec: {
|
|
579
588
|
kind: 'subscription',
|
|
580
|
-
query:
|
|
589
|
+
query: {
|
|
590
|
+
ast: Query.select(Filter.type(DataType.Task)).ast,
|
|
591
|
+
},
|
|
581
592
|
},
|
|
582
593
|
});
|
|
583
594
|
yield* DatabaseService.add(trigger);
|
|
@@ -610,7 +621,7 @@ describe('TriggerDispatcher', () => {
|
|
|
610
621
|
it.effect(
|
|
611
622
|
'should pass correct event data to function',
|
|
612
623
|
Effect.fnUntraced(function* ({ expect }) {
|
|
613
|
-
const functionObj = serializeFunction(reply);
|
|
624
|
+
const functionObj = serializeFunction(Example.reply);
|
|
614
625
|
yield* DatabaseService.add(functionObj);
|
|
615
626
|
|
|
616
627
|
const person = Obj.make(DataType.Person, {
|
|
@@ -619,12 +630,14 @@ describe('TriggerDispatcher', () => {
|
|
|
619
630
|
yield* DatabaseService.add(person);
|
|
620
631
|
|
|
621
632
|
// Create a subscription trigger with input pattern
|
|
622
|
-
const trigger =
|
|
633
|
+
const trigger = Trigger.make({
|
|
623
634
|
function: Ref.make(functionObj),
|
|
624
635
|
enabled: true,
|
|
625
636
|
spec: {
|
|
626
637
|
kind: 'subscription',
|
|
627
|
-
query:
|
|
638
|
+
query: {
|
|
639
|
+
ast: Query.select(Filter.type(DataType.Person)).ast,
|
|
640
|
+
},
|
|
628
641
|
},
|
|
629
642
|
input: {
|
|
630
643
|
objectId: '{{event.changedObjectId}}',
|
|
@@ -2,7 +2,18 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import * as Cause from 'effect/Cause';
|
|
6
|
+
import * as Context from 'effect/Context';
|
|
7
|
+
import * as Cron from 'effect/Cron';
|
|
8
|
+
import * as Duration from 'effect/Duration';
|
|
9
|
+
import * as Effect from 'effect/Effect';
|
|
10
|
+
import * as Either from 'effect/Either';
|
|
11
|
+
import * as Exit from 'effect/Exit';
|
|
12
|
+
import * as Fiber from 'effect/Fiber';
|
|
13
|
+
import * as Layer from 'effect/Layer';
|
|
14
|
+
import * as Option from 'effect/Option';
|
|
15
|
+
import * as Record from 'effect/Record';
|
|
16
|
+
import * as Schedule from 'effect/Schedule';
|
|
6
17
|
|
|
7
18
|
import { DXN, Filter, Obj, Query } from '@dxos/echo';
|
|
8
19
|
import { causeToError } from '@dxos/effect';
|
|
@@ -11,7 +22,6 @@ import { log } from '@dxos/log';
|
|
|
11
22
|
import { KEY_QUEUE_POSITION } from '@dxos/protocols';
|
|
12
23
|
|
|
13
24
|
import { deserializeFunction } from '../handler';
|
|
14
|
-
import { FunctionType } from '../schema';
|
|
15
25
|
import {
|
|
16
26
|
ComputeEventLogger,
|
|
17
27
|
DatabaseService,
|
|
@@ -19,15 +29,7 @@ import {
|
|
|
19
29
|
QueueService,
|
|
20
30
|
TracingService,
|
|
21
31
|
} from '../services';
|
|
22
|
-
import {
|
|
23
|
-
type EventType,
|
|
24
|
-
FunctionTrigger,
|
|
25
|
-
type QueueTriggerOutput,
|
|
26
|
-
type SubscriptionTriggerOutput,
|
|
27
|
-
type TimerTrigger,
|
|
28
|
-
type TimerTriggerOutput,
|
|
29
|
-
type TriggerKind,
|
|
30
|
-
} from '../types';
|
|
32
|
+
import { Function, Trigger, type TriggerEvent } from '../types';
|
|
31
33
|
|
|
32
34
|
import { createInvocationPayload } from './input-builder';
|
|
33
35
|
import { InvocationTracer } from './invocation-tracer';
|
|
@@ -57,8 +59,8 @@ export interface TriggerDispatcherOptions {
|
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export interface InvokeTriggerOptions {
|
|
60
|
-
trigger:
|
|
61
|
-
event:
|
|
62
|
+
trigger: Trigger.Trigger;
|
|
63
|
+
event: TriggerEvent.TriggerEvent;
|
|
62
64
|
}
|
|
63
65
|
export interface TriggerExecutionResult {
|
|
64
66
|
triggerId: string;
|
|
@@ -69,7 +71,7 @@ export interface TriggerExecutionResult {
|
|
|
69
71
|
* Cront trigger runtime state.
|
|
70
72
|
*/
|
|
71
73
|
interface ScheduledTrigger {
|
|
72
|
-
trigger:
|
|
74
|
+
trigger: Trigger.Trigger;
|
|
73
75
|
cron: Cron.Cron;
|
|
74
76
|
nextExecution: Date;
|
|
75
77
|
}
|
|
@@ -117,7 +119,7 @@ export class TriggerDispatcher extends Context.Tag('@dxos/functions/TriggerDispa
|
|
|
117
119
|
* Invoke all scheduled triggers who are due.
|
|
118
120
|
*/
|
|
119
121
|
invokeScheduledTriggers(opts?: {
|
|
120
|
-
kinds?:
|
|
122
|
+
kinds?: Trigger.Kind[];
|
|
121
123
|
}): Effect.Effect<TriggerExecutionResult[], never, TriggerDispatcherServices>;
|
|
122
124
|
|
|
123
125
|
/**
|
|
@@ -238,7 +240,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
238
240
|
|
|
239
241
|
// Resolve the function
|
|
240
242
|
const serialiedFunction = yield* DatabaseService.load(trigger.function!).pipe(Effect.orDie);
|
|
241
|
-
invariant(Obj.instanceOf(
|
|
243
|
+
invariant(Obj.instanceOf(Function.Function, serialiedFunction));
|
|
242
244
|
const functionDef = deserializeFunction(serialiedFunction);
|
|
243
245
|
|
|
244
246
|
// Prepare input data
|
|
@@ -288,7 +290,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
288
290
|
{
|
|
289
291
|
yield* this.refreshTriggers();
|
|
290
292
|
const now = this.getCurrentTime();
|
|
291
|
-
const triggersToInvoke:
|
|
293
|
+
const triggersToInvoke: Trigger.Trigger[] = [];
|
|
292
294
|
|
|
293
295
|
for (const [triggerId, scheduledTrigger] of this._scheduledTriggers.entries()) {
|
|
294
296
|
if (scheduledTrigger.nextExecution <= now) {
|
|
@@ -306,7 +308,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
306
308
|
(trigger) =>
|
|
307
309
|
this.invokeTrigger({
|
|
308
310
|
trigger,
|
|
309
|
-
event: { tick: now.getTime() } satisfies
|
|
311
|
+
event: { tick: now.getTime() } satisfies TriggerEvent.TimerEvent,
|
|
310
312
|
}),
|
|
311
313
|
{ concurrency: 1 },
|
|
312
314
|
)),
|
|
@@ -339,7 +341,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
339
341
|
queue: spec.queue,
|
|
340
342
|
item: object,
|
|
341
343
|
cursor: objectPos,
|
|
342
|
-
} satisfies
|
|
344
|
+
} satisfies TriggerEvent.QueueEvent,
|
|
343
345
|
}),
|
|
344
346
|
);
|
|
345
347
|
|
|
@@ -362,7 +364,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
362
364
|
continue;
|
|
363
365
|
}
|
|
364
366
|
|
|
365
|
-
const { objects } = yield* DatabaseService.runQuery(Query.fromAst(spec.query));
|
|
367
|
+
const { objects } = yield* DatabaseService.runQuery(Query.fromAst(spec.query.ast));
|
|
366
368
|
|
|
367
369
|
const state: TriggerState = yield* TriggerStateStore.getState(trigger.id).pipe(
|
|
368
370
|
Effect.catchTag('TRIGGER_STATE_NOT_FOUND', () =>
|
|
@@ -403,7 +405,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
403
405
|
subject: db.ref(Obj.getDXN(object)),
|
|
404
406
|
|
|
405
407
|
changedObjectId: object.id,
|
|
406
|
-
} satisfies
|
|
408
|
+
} satisfies TriggerEvent.SubscriptionEvent,
|
|
407
409
|
}),
|
|
408
410
|
);
|
|
409
411
|
(state.state.processedVersions as any)[object.id] = Obj.encodeVersion(currentVersion);
|
|
@@ -462,7 +464,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
462
464
|
// Add or update triggers
|
|
463
465
|
for (const trigger of triggers) {
|
|
464
466
|
if (trigger.spec?.kind === 'timer' && trigger.enabled) {
|
|
465
|
-
const timerSpec = trigger.spec as
|
|
467
|
+
const timerSpec = trigger.spec as Trigger.TimerSpec;
|
|
466
468
|
|
|
467
469
|
// Parse cron expression using Effect's Cron module
|
|
468
470
|
const cronEither = Cron.parse(timerSpec.cron);
|
|
@@ -499,7 +501,7 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
499
501
|
|
|
500
502
|
private _fetchTriggers = () =>
|
|
501
503
|
Effect.gen(this, function* () {
|
|
502
|
-
const { objects } = yield* DatabaseService.runQuery(Filter.type(
|
|
504
|
+
const { objects } = yield* DatabaseService.runQuery(Filter.type(Trigger.Trigger));
|
|
503
505
|
return objects;
|
|
504
506
|
}).pipe(Effect.withSpan('TriggerDispatcher.fetchTriggers'));
|
|
505
507
|
|
|
@@ -508,14 +510,11 @@ class TriggerDispatcherImpl implements Context.Tag.Service<TriggerDispatcher> {
|
|
|
508
510
|
yield* this.invokeScheduledTriggers();
|
|
509
511
|
}).pipe(Effect.repeat(Schedule.fixed(this.livePollInterval)), Effect.asVoid);
|
|
510
512
|
|
|
511
|
-
private _prepareInputData = (trigger:
|
|
513
|
+
private _prepareInputData = (trigger: Trigger.Trigger, event: TriggerEvent.TriggerEvent): any => {
|
|
512
514
|
return createInvocationPayload(trigger, event);
|
|
513
515
|
};
|
|
514
516
|
}
|
|
515
517
|
|
|
516
|
-
// Re-exports
|
|
517
|
-
export { FunctionTrigger, type TimerTrigger } from '../types';
|
|
518
|
-
|
|
519
518
|
/**
|
|
520
519
|
* Key for the current queue cursor for queue triggers.
|
|
521
520
|
*/
|
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
5
|
+
import * as KeyValueStore from '@effect/platform/KeyValueStore';
|
|
6
|
+
import * as Context from 'effect/Context';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import * as Layer from 'effect/Layer';
|
|
9
|
+
import * as Option from 'effect/Option';
|
|
10
|
+
import * as Schema from 'effect/Schema';
|
|
10
11
|
|
|
11
12
|
import { ObjectId } from '@dxos/keys';
|
|
12
13
|
|