@dxos/functions 0.8.4-main.5acf9ea → 0.8.4-main.5ea62a8
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 +54 -38
- package/dist/lib/browser/bundler/index.mjs.map +3 -3
- package/dist/lib/browser/chunk-7NQ77AIQ.mjs +618 -0
- package/dist/lib/browser/chunk-7NQ77AIQ.mjs.map +7 -0
- package/dist/lib/browser/edge/index.mjs +20 -8
- package/dist/lib/browser/edge/index.mjs.map +3 -3
- package/dist/lib/browser/index.mjs +141 -77
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +68 -5
- package/dist/lib/browser/testing/index.mjs.map +3 -3
- package/dist/lib/node-esm/bundler/index.mjs +54 -38
- package/dist/lib/node-esm/bundler/index.mjs.map +3 -3
- package/dist/lib/node-esm/chunk-KCGC6QQT.mjs +620 -0
- package/dist/lib/node-esm/chunk-KCGC6QQT.mjs.map +7 -0
- package/dist/lib/node-esm/edge/index.mjs +20 -8
- package/dist/lib/node-esm/edge/index.mjs.map +3 -3
- package/dist/lib/node-esm/index.mjs +141 -77
- 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 +68 -5
- package/dist/lib/node-esm/testing/index.mjs.map +3 -3
- package/dist/types/src/bundler/bundler.d.ts +11 -12
- package/dist/types/src/bundler/bundler.d.ts.map +1 -1
- package/dist/types/src/edge/functions.d.ts +3 -2
- package/dist/types/src/edge/functions.d.ts.map +1 -1
- package/dist/types/src/errors.d.ts +10 -8
- package/dist/types/src/errors.d.ts.map +1 -1
- package/dist/types/src/examples/fib.d.ts +7 -0
- package/dist/types/src/examples/fib.d.ts.map +1 -0
- package/dist/types/src/examples/reply.d.ts +3 -0
- package/dist/types/src/examples/reply.d.ts.map +1 -0
- package/dist/types/src/examples/sleep.d.ts +5 -0
- package/dist/types/src/examples/sleep.d.ts.map +1 -0
- package/dist/types/src/executor/executor.d.ts +4 -1
- package/dist/types/src/executor/executor.d.ts.map +1 -1
- package/dist/types/src/handler.d.ts +10 -7
- package/dist/types/src/handler.d.ts.map +1 -1
- package/dist/types/src/schema.d.ts +7 -2
- package/dist/types/src/schema.d.ts.map +1 -1
- package/dist/types/src/services/credentials.d.ts +15 -3
- package/dist/types/src/services/credentials.d.ts.map +1 -1
- package/dist/types/src/services/database.d.ts +74 -6
- package/dist/types/src/services/database.d.ts.map +1 -1
- package/dist/types/src/services/event-logger.d.ts +1 -1
- package/dist/types/src/services/event-logger.d.ts.map +1 -1
- package/dist/types/src/services/local-function-execution.d.ts +2 -1
- package/dist/types/src/services/local-function-execution.d.ts.map +1 -1
- package/dist/types/src/services/queues.d.ts +18 -5
- package/dist/types/src/services/queues.d.ts.map +1 -1
- package/dist/types/src/services/remote-function-execution-service.d.ts.map +1 -1
- package/dist/types/src/services/service-container.d.ts +1 -1
- package/dist/types/src/services/service-container.d.ts.map +1 -1
- package/dist/types/src/services/service-registry.d.ts.map +1 -1
- package/dist/types/src/services/tracing.d.ts +33 -3
- package/dist/types/src/services/tracing.d.ts.map +1 -1
- package/dist/types/src/testing/layer.d.ts +6 -2
- package/dist/types/src/testing/layer.d.ts.map +1 -1
- package/dist/types/src/testing/logger.d.ts.map +1 -1
- package/dist/types/src/testing/persist-database.test.d.ts +2 -0
- package/dist/types/src/testing/persist-database.test.d.ts.map +1 -0
- 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 +34 -8
- package/dist/types/src/trace.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +141 -224
- package/dist/types/src/types.d.ts.map +1 -1
- package/dist/types/src/url.d.ts +10 -6
- package/dist/types/src/url.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -39
- package/src/bundler/bundler.test.ts +8 -9
- package/src/bundler/bundler.ts +32 -33
- package/src/edge/functions.ts +8 -5
- package/src/examples/fib.ts +30 -0
- package/src/examples/reply.ts +18 -0
- package/src/examples/sleep.ts +22 -0
- package/src/executor/executor.ts +9 -9
- package/src/handler.ts +12 -10
- package/src/schema.ts +11 -0
- package/src/services/credentials.ts +78 -5
- package/src/services/database.ts +114 -18
- package/src/services/event-logger.ts +2 -2
- package/src/services/local-function-execution.ts +20 -13
- package/src/services/queues.ts +29 -10
- package/src/services/remote-function-execution-service.ts +2 -22
- package/src/services/service-container.ts +4 -3
- package/src/services/service-registry.ts +1 -1
- package/src/services/tracing.ts +95 -5
- package/src/testing/layer.ts +69 -3
- package/src/testing/logger.ts +1 -1
- package/src/testing/persist-database.test.ts +87 -0
- package/src/testing/services.ts +2 -1
- package/src/trace.ts +5 -7
- package/src/types.ts +17 -25
- package/src/url.ts +13 -10
- package/dist/lib/browser/chunk-6PTFLPCO.mjs +0 -462
- package/dist/lib/browser/chunk-6PTFLPCO.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-NYJ2TSXO.mjs +0 -464
- package/dist/lib/node-esm/chunk-NYJ2TSXO.mjs.map +0 -7
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from '@effect/vitest';
|
|
6
|
+
import { Effect } from 'effect';
|
|
7
|
+
|
|
8
|
+
import { Filter, Obj, Query, Type } from '@dxos/echo';
|
|
9
|
+
import { DataType } from '@dxos/schema';
|
|
10
|
+
|
|
11
|
+
import { DatabaseService } from '../services';
|
|
12
|
+
|
|
13
|
+
import { TestDatabaseLayer, testStoragePath } from './layer';
|
|
14
|
+
|
|
15
|
+
describe('TestDatabaseLayer', { timeout: 600_000 }, () => {
|
|
16
|
+
it.effect(
|
|
17
|
+
'persist database to disk',
|
|
18
|
+
Effect.fnUntraced(function* ({ expect: _ }) {
|
|
19
|
+
const DbLayer = TestDatabaseLayer({
|
|
20
|
+
storagePath: testStoragePath({ name: `feed-test-${Date.now()}` }),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
yield* Effect.gen(function* () {
|
|
24
|
+
yield* DatabaseService.add(Obj.make(Type.Expando, { label: 'test' }));
|
|
25
|
+
yield* DatabaseService.flush({ indexes: true });
|
|
26
|
+
}).pipe(Effect.provide(DbLayer));
|
|
27
|
+
|
|
28
|
+
yield* Effect.gen(function* () {
|
|
29
|
+
const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.everything()));
|
|
30
|
+
expect(objects[0]?.label).toEqual('test');
|
|
31
|
+
}).pipe(Effect.provide(DbLayer));
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
it.effect(
|
|
36
|
+
'reload database -- save index before restart',
|
|
37
|
+
Effect.fnUntraced(function* ({ expect: _ }) {
|
|
38
|
+
const NUM_OBJECTS = 500;
|
|
39
|
+
const DbLayer = TestDatabaseLayer({
|
|
40
|
+
types: [DataType.Person],
|
|
41
|
+
storagePath: testStoragePath({ name: `reload-test-${Date.now()}` }),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
yield* Effect.gen(function* () {
|
|
45
|
+
for (let i = 0; i < NUM_OBJECTS; i++) {
|
|
46
|
+
yield* DatabaseService.add(Obj.make(DataType.Person, { nickname: `Person ${i}` }));
|
|
47
|
+
}
|
|
48
|
+
yield* DatabaseService.flush({ indexes: true });
|
|
49
|
+
}).pipe(Effect.provide(DbLayer));
|
|
50
|
+
|
|
51
|
+
yield* Effect.gen(function* () {
|
|
52
|
+
const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
|
|
53
|
+
expect(objects.length).toEqual(NUM_OBJECTS);
|
|
54
|
+
}).pipe(Effect.provide(DbLayer));
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
it.effect.skip(
|
|
59
|
+
'reload database -- save index before restart [manual]',
|
|
60
|
+
Effect.fnUntraced(
|
|
61
|
+
function* ({ expect: _ }) {
|
|
62
|
+
const NUM_OBJECTS = 500;
|
|
63
|
+
|
|
64
|
+
{
|
|
65
|
+
const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
|
|
66
|
+
console.log({ count: objects.length });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < NUM_OBJECTS; i++) {
|
|
70
|
+
yield* DatabaseService.add(Obj.make(DataType.Person, { nickname: `Person ${i}` }));
|
|
71
|
+
}
|
|
72
|
+
yield* DatabaseService.flush({ indexes: true });
|
|
73
|
+
|
|
74
|
+
{
|
|
75
|
+
const { objects } = yield* DatabaseService.runQuery(Query.select(Filter.type(DataType.Person)));
|
|
76
|
+
console.log({ count: objects.length });
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
Effect.provide(
|
|
80
|
+
TestDatabaseLayer({
|
|
81
|
+
types: [DataType.Person],
|
|
82
|
+
storagePath: testStoragePath({ name: `reload-test` }),
|
|
83
|
+
}),
|
|
84
|
+
),
|
|
85
|
+
),
|
|
86
|
+
);
|
|
87
|
+
});
|
package/src/testing/services.ts
CHANGED
|
@@ -9,15 +9,16 @@ import type { EchoDatabase, QueueFactory } from '@dxos/echo-db';
|
|
|
9
9
|
import { assertArgument } from '@dxos/invariant';
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
type ComputeEventLogger,
|
|
12
13
|
ConfiguredCredentialsService,
|
|
13
14
|
type CredentialsService,
|
|
14
15
|
DatabaseService,
|
|
15
|
-
type ComputeEventLogger,
|
|
16
16
|
QueueService,
|
|
17
17
|
ServiceContainer,
|
|
18
18
|
type ServiceCredential,
|
|
19
19
|
type TracingService,
|
|
20
20
|
} from '../services';
|
|
21
|
+
|
|
21
22
|
import { consoleLogger, noopLogger } from './logger';
|
|
22
23
|
|
|
23
24
|
// TODO(burdon): Factor out.
|
package/src/trace.ts
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { Schema } from 'effect';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { type Ref, Type } from '@dxos/echo';
|
|
8
8
|
import { Queue } from '@dxos/echo-db';
|
|
9
9
|
import { ObjectId } from '@dxos/echo-schema';
|
|
10
10
|
import { log } from '@dxos/log';
|
|
11
11
|
|
|
12
|
-
import { FunctionTrigger
|
|
12
|
+
import { FunctionTrigger } from './types';
|
|
13
13
|
|
|
14
14
|
export enum InvocationOutcome {
|
|
15
15
|
SUCCESS = 'success',
|
|
@@ -101,10 +101,8 @@ export const TraceEvent = Schema.Struct({
|
|
|
101
101
|
// TODO(burdon): Need enum/numeric result (not string).
|
|
102
102
|
outcome: Schema.String,
|
|
103
103
|
truncated: Schema.Boolean,
|
|
104
|
-
/**
|
|
105
|
-
|
|
106
|
-
*/
|
|
107
|
-
ingestionTimestampMs: Schema.Number,
|
|
104
|
+
/** Time when the event was persisted. */
|
|
105
|
+
ingestionTimestamp: Schema.Number,
|
|
108
106
|
logs: Schema.Array(TraceEventLog),
|
|
109
107
|
exceptions: Schema.Array(TraceEventException),
|
|
110
108
|
}).pipe(Type.Obj({ typename: 'dxos.org/type/TraceEvent', version: '0.1.0' }));
|
|
@@ -123,7 +121,7 @@ export type InvocationSpan = {
|
|
|
123
121
|
durationMs: number;
|
|
124
122
|
invocationTraceQueue: Ref.Ref<Queue>;
|
|
125
123
|
invocationTarget: Ref.Ref<Type.Expando>;
|
|
126
|
-
trigger?: Ref.Ref<
|
|
124
|
+
trigger?: Ref.Ref<FunctionTrigger>;
|
|
127
125
|
exception?: TraceEventException;
|
|
128
126
|
};
|
|
129
127
|
|
package/src/types.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { Schema, SchemaAST } from 'effect';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { Type } from '@dxos/echo';
|
|
8
|
+
import { Expando, OptionsAnnotationId, RawObject, Ref } from '@dxos/echo-schema';
|
|
8
9
|
import { DXN } from '@dxos/keys';
|
|
9
10
|
|
|
10
11
|
import { FunctionType } from './schema';
|
|
@@ -14,13 +15,8 @@ import { FunctionType } from './schema';
|
|
|
14
15
|
* Every spec has a type field of type TriggerKind that we can use to understand which type we're working with.
|
|
15
16
|
* https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions
|
|
16
17
|
*/
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
Webhook = 'webhook',
|
|
20
|
-
Subscription = 'subscription',
|
|
21
|
-
Email = 'email',
|
|
22
|
-
Queue = 'queue',
|
|
23
|
-
}
|
|
18
|
+
export const TriggerKinds = ['timer', 'webhook', 'subscription', 'email', 'queue'] as const;
|
|
19
|
+
export type TriggerKind = (typeof TriggerKinds)[number];
|
|
24
20
|
|
|
25
21
|
const kindLiteralAnnotations = { title: 'Kind' };
|
|
26
22
|
|
|
@@ -28,7 +24,7 @@ const kindLiteralAnnotations = { title: 'Kind' };
|
|
|
28
24
|
* Cron timer.
|
|
29
25
|
*/
|
|
30
26
|
const TimerTriggerSchema = Schema.Struct({
|
|
31
|
-
kind: Schema.Literal(
|
|
27
|
+
kind: Schema.Literal('timer').annotations(kindLiteralAnnotations),
|
|
32
28
|
cron: Schema.String.annotations({
|
|
33
29
|
title: 'Cron',
|
|
34
30
|
[SchemaAST.ExamplesAnnotationId]: ['0 0 * * *'],
|
|
@@ -37,12 +33,12 @@ const TimerTriggerSchema = Schema.Struct({
|
|
|
37
33
|
export type TimerTrigger = Schema.Schema.Type<typeof TimerTriggerSchema>;
|
|
38
34
|
|
|
39
35
|
const EmailTriggerSchema = Schema.Struct({
|
|
40
|
-
kind: Schema.Literal(
|
|
36
|
+
kind: Schema.Literal('email').annotations(kindLiteralAnnotations),
|
|
41
37
|
}).pipe(Schema.mutable);
|
|
42
38
|
export type EmailTrigger = Schema.Schema.Type<typeof EmailTriggerSchema>;
|
|
43
39
|
|
|
44
40
|
const QueueTriggerSchema = Schema.Struct({
|
|
45
|
-
kind: Schema.Literal(
|
|
41
|
+
kind: Schema.Literal('queue').annotations(kindLiteralAnnotations),
|
|
46
42
|
queue: DXN.Schema,
|
|
47
43
|
}).pipe(Schema.mutable);
|
|
48
44
|
export type QueueTrigger = Schema.Schema.Type<typeof QueueTriggerSchema>;
|
|
@@ -51,7 +47,7 @@ export type QueueTrigger = Schema.Schema.Type<typeof QueueTriggerSchema>;
|
|
|
51
47
|
* Webhook.
|
|
52
48
|
*/
|
|
53
49
|
const WebhookTriggerSchema = Schema.Struct({
|
|
54
|
-
kind: Schema.Literal(
|
|
50
|
+
kind: Schema.Literal('webhook').annotations(kindLiteralAnnotations),
|
|
55
51
|
method: Schema.optional(
|
|
56
52
|
Schema.String.annotations({
|
|
57
53
|
title: 'Method',
|
|
@@ -76,7 +72,7 @@ const QuerySchema = Schema.Struct({
|
|
|
76
72
|
* Subscription.
|
|
77
73
|
*/
|
|
78
74
|
const SubscriptionTriggerSchema = Schema.Struct({
|
|
79
|
-
kind: Schema.Literal(
|
|
75
|
+
kind: Schema.Literal('subscription').annotations(kindLiteralAnnotations),
|
|
80
76
|
// TODO(burdon): Define query DSL (from ECHO). Reconcile with Table.Query.
|
|
81
77
|
filter: QuerySchema,
|
|
82
78
|
options: Schema.optional(
|
|
@@ -155,7 +151,7 @@ export type TimerTriggerOutput = Schema.Schema.Type<typeof TimerTriggerOutput>;
|
|
|
155
151
|
* Function is invoked with the `payload` passed as input data.
|
|
156
152
|
* The event that triggers the function is available in the function context.
|
|
157
153
|
*/
|
|
158
|
-
export const
|
|
154
|
+
export const FunctionTrigger = Schema.Struct({
|
|
159
155
|
/**
|
|
160
156
|
* Function or workflow to invoke.
|
|
161
157
|
*/
|
|
@@ -185,17 +181,13 @@ export const FunctionTriggerSchema = Schema.Struct({
|
|
|
185
181
|
* }
|
|
186
182
|
*/
|
|
187
183
|
input: Schema.optional(Schema.mutable(Schema.Record({ key: Schema.String, value: Schema.Any }))),
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
export class FunctionTrigger extends TypedObject({
|
|
196
|
-
typename: 'dxos.org/type/FunctionTrigger',
|
|
197
|
-
version: '0.2.0',
|
|
198
|
-
})(FunctionTriggerSchema.fields) {}
|
|
184
|
+
}).pipe(
|
|
185
|
+
Type.Obj({
|
|
186
|
+
typename: 'dxos.org/type/FunctionTrigger',
|
|
187
|
+
version: '0.2.0',
|
|
188
|
+
}),
|
|
189
|
+
);
|
|
190
|
+
export type FunctionTrigger = Schema.Schema.Type<typeof FunctionTrigger>;
|
|
199
191
|
|
|
200
192
|
// TODO(wittjosiah): Remove?
|
|
201
193
|
|
package/src/url.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type ObjectMeta } from '@dxos/echo-schema';
|
|
|
6
6
|
import { type SpaceId } from '@dxos/keys';
|
|
7
7
|
|
|
8
8
|
// TODO: use URL scheme for source?
|
|
9
|
-
const FUNCTIONS_META_KEY = 'dxos.org/service/function';
|
|
9
|
+
export const FUNCTIONS_META_KEY = 'dxos.org/service/function';
|
|
10
10
|
|
|
11
11
|
export const FUNCTIONS_PRESET_META_KEY = 'dxos.org/service/function-preset';
|
|
12
12
|
|
|
@@ -14,32 +14,35 @@ const isSecure = (protocol: string) => {
|
|
|
14
14
|
return protocol === 'https:' || protocol === 'wss:';
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* NOTE: functionId is backend ID, not ECHO object id.
|
|
19
|
+
*/
|
|
20
|
+
export const getUserFunctionIdInMetadata = (meta: ObjectMeta) => {
|
|
18
21
|
return meta.keys.find((key) => key.source === FUNCTIONS_META_KEY)?.id;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
/**
|
|
25
|
+
* NOTE: functionId is backend ID, not ECHO object id.
|
|
26
|
+
*/
|
|
27
|
+
export const setUserFunctionIdInMetadata = (meta: ObjectMeta, functionId: string) => {
|
|
22
28
|
const key = meta.keys.find((key) => key.source === FUNCTIONS_META_KEY);
|
|
23
29
|
if (key) {
|
|
24
|
-
if (key.id !==
|
|
30
|
+
if (key.id !== functionId) {
|
|
25
31
|
throw new Error('Metadata mismatch');
|
|
26
32
|
}
|
|
27
33
|
} else {
|
|
28
|
-
meta.keys.push({ source: FUNCTIONS_META_KEY, id:
|
|
34
|
+
meta.keys.push({ source: FUNCTIONS_META_KEY, id: functionId });
|
|
29
35
|
}
|
|
30
36
|
};
|
|
31
37
|
|
|
32
38
|
/**
|
|
33
39
|
* NOTE: functionId is backend ID, not ECHO object id.
|
|
34
40
|
*/
|
|
35
|
-
export const
|
|
36
|
-
|
|
37
|
-
export const getInvocationUrl = (functionUrl: string, edgeUrl: string, options: InvocationOptions = {}) => {
|
|
41
|
+
export const getInvocationUrl = (functionId: string, edgeUrl: string, options: InvocationOptions = {}) => {
|
|
38
42
|
const baseUrl = new URL('functions/', edgeUrl);
|
|
39
43
|
|
|
40
44
|
// Leading slashes cause the URL to be treated as an absolute path.
|
|
41
|
-
const
|
|
42
|
-
const url = new URL(`./${relativeUrl}`, baseUrl.toString());
|
|
45
|
+
const url = new URL(`./${functionId}`, baseUrl.toString());
|
|
43
46
|
options.spaceId && url.searchParams.set('spaceId', options.spaceId);
|
|
44
47
|
options.subjectId && url.searchParams.set('subjectId', options.subjectId);
|
|
45
48
|
url.protocol = isSecure(url.protocol) ? 'https' : 'http';
|