@concavejs/runtime-cf-base 0.0.1-alpha.10
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/adapters/cf-websocket-adapter.d.ts +38 -0
- package/dist/adapters/cf-websocket-adapter.js +83 -0
- package/dist/durable-objects/blobstore-rpc.d.ts +13 -0
- package/dist/durable-objects/blobstore-rpc.js +27 -0
- package/dist/durable-objects/concave-do-base.d.ts +169 -0
- package/dist/durable-objects/concave-do-base.js +466 -0
- package/dist/durable-objects/docstore-rpc.d.ts +46 -0
- package/dist/durable-objects/docstore-rpc.js +63 -0
- package/dist/durable-objects/scheduler-manager.d.ts +19 -0
- package/dist/durable-objects/scheduler-manager.js +53 -0
- package/dist/durable-objects/sync-notifier.d.ts +16 -0
- package/dist/durable-objects/sync-notifier.js +38 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.js +6 -0
- package/dist/http/dx-http.d.ts +43 -0
- package/dist/http/dx-http.js +327 -0
- package/dist/http/http-api.d.ts +38 -0
- package/dist/http/http-api.js +399 -0
- package/dist/http/index.d.ts +7 -0
- package/dist/http/index.js +7 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +27 -0
- package/dist/internal.d.ts +4 -0
- package/dist/internal.js +4 -0
- package/dist/routing/instance.d.ts +25 -0
- package/dist/routing/instance.js +101 -0
- package/dist/routing/sync-topology.d.ts +40 -0
- package/dist/routing/sync-topology.js +669 -0
- package/dist/rpc/blobstore-proxy.d.ts +11 -0
- package/dist/rpc/blobstore-proxy.js +28 -0
- package/dist/rpc/docstore-proxy.d.ts +11 -0
- package/dist/rpc/docstore-proxy.js +73 -0
- package/dist/rpc/index.d.ts +2 -0
- package/dist/rpc/index.js +2 -0
- package/dist/sync/cf-websocket-adapter.d.ts +15 -0
- package/dist/sync/cf-websocket-adapter.js +22 -0
- package/dist/sync/concave-do-udf-executor.d.ts +46 -0
- package/dist/sync/concave-do-udf-executor.js +75 -0
- package/dist/sync/index.d.ts +2 -0
- package/dist/sync/index.js +2 -0
- package/dist/udf/executor/do-client-executor.d.ts +14 -0
- package/dist/udf/executor/do-client-executor.js +58 -0
- package/dist/udf/executor/index.d.ts +8 -0
- package/dist/udf/executor/index.js +8 -0
- package/dist/udf/executor/inline-executor.d.ts +13 -0
- package/dist/udf/executor/inline-executor.js +25 -0
- package/dist/udf/executor/isolated-executor.d.ts +24 -0
- package/dist/udf/executor/isolated-executor.js +31 -0
- package/dist/udf/executor/shim-content.d.ts +1 -0
- package/dist/udf/executor/shim-content.js +3 -0
- package/dist/worker/create-concave-worker.d.ts +79 -0
- package/dist/worker/create-concave-worker.js +196 -0
- package/dist/worker/index.d.ts +6 -0
- package/dist/worker/index.js +6 -0
- package/dist/worker/udf-worker.d.ts +25 -0
- package/dist/worker/udf-worker.js +63 -0
- package/package.json +99 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a DO stub as a BlobStore.
|
|
3
|
+
* Blobstore methods are prefixed with "blobstore" on the DO to avoid collisions.
|
|
4
|
+
*/
|
|
5
|
+
export function createBlobStoreProxy(stub) {
|
|
6
|
+
return createBlobStoreProxyInternal(stub, (...args) => args);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Wraps a SyscallGateway service binding as a BlobStore.
|
|
10
|
+
* Prepends projectId and instance to each call for multi-tenant routing.
|
|
11
|
+
*/
|
|
12
|
+
export function createGatewayBlobStoreProxy(gateway, projectId, instance) {
|
|
13
|
+
return createBlobStoreProxyInternal(gateway, (...args) => [projectId, instance, ...args]);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Internal helper that creates a BlobStore proxy with configurable argument transformation.
|
|
17
|
+
*/
|
|
18
|
+
function createBlobStoreProxyInternal(target, transformArgs) {
|
|
19
|
+
return {
|
|
20
|
+
async store(blob, options) {
|
|
21
|
+
const buffer = blob instanceof Blob ? await blob.arrayBuffer() : blob;
|
|
22
|
+
return target.blobstoreStore(...transformArgs(buffer, options));
|
|
23
|
+
},
|
|
24
|
+
get: (id) => target.blobstoreGet(...transformArgs(id)),
|
|
25
|
+
delete: (id) => target.blobstoreDelete(...transformArgs(id)),
|
|
26
|
+
getUrl: (id) => target.blobstoreGetUrl(...transformArgs(id)),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DocStore } from "@concavejs/core/docstore";
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a DO stub as a DocStore.
|
|
4
|
+
* Generator methods are converted from arrays back to async generators.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createDocStoreProxy(stub: any): DocStore;
|
|
7
|
+
/**
|
|
8
|
+
* Wraps a SyscallGateway service binding as a DocStore.
|
|
9
|
+
* Prepends projectId and instance to each call for multi-tenant routing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createGatewayDocStoreProxy(gateway: any, projectId: string, instance: string): DocStore;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { TimestampOracle } from "@concavejs/core/utils";
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a DO stub as a DocStore.
|
|
4
|
+
* Generator methods are converted from arrays back to async generators.
|
|
5
|
+
*/
|
|
6
|
+
export function createDocStoreProxy(stub) {
|
|
7
|
+
return createDocStoreProxyInternal(stub, (...args) => args);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Wraps a SyscallGateway service binding as a DocStore.
|
|
11
|
+
* Prepends projectId and instance to each call for multi-tenant routing.
|
|
12
|
+
*/
|
|
13
|
+
export function createGatewayDocStoreProxy(gateway, projectId, instance) {
|
|
14
|
+
return createDocStoreProxyInternal(gateway, (...args) => [projectId, instance, ...args]);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Internal helper that creates a DocStore proxy with configurable argument transformation.
|
|
18
|
+
*/
|
|
19
|
+
function createDocStoreProxyInternal(target, transformArgs) {
|
|
20
|
+
// Use a real TimestampOracle to guarantee monotonic, unique timestamps.
|
|
21
|
+
// The DO-side oracle cannot be accessed via RPC, so each proxy gets its own.
|
|
22
|
+
const oracle = new TimestampOracle();
|
|
23
|
+
return new Proxy({}, {
|
|
24
|
+
get(_, prop) {
|
|
25
|
+
// Convert array results back to async generators
|
|
26
|
+
if (prop === "index_scan") {
|
|
27
|
+
return async function* (...args) {
|
|
28
|
+
const results = await target.index_scan(...transformArgs(...args));
|
|
29
|
+
for (const item of results) {
|
|
30
|
+
yield item;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (prop === "load_documents") {
|
|
35
|
+
return async function* (...args) {
|
|
36
|
+
const results = await target.load_documents(...transformArgs(...args));
|
|
37
|
+
for (const item of results) {
|
|
38
|
+
yield item;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// Convert array results back to Map for previous_revisions
|
|
43
|
+
if (prop === "previous_revisions") {
|
|
44
|
+
return async function (...args) {
|
|
45
|
+
const result = await target.previous_revisions(...transformArgs(...args));
|
|
46
|
+
return new Map(result);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (prop === "previous_revisions_of_documents") {
|
|
50
|
+
return async function (...args) {
|
|
51
|
+
const result = await target.previous_revisions_of_documents(...transformArgs(...args));
|
|
52
|
+
return new Map(result);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Provide a local TimestampOracle (DO-side oracle cannot be accessed via RPC)
|
|
56
|
+
if (prop === "timestampOracle") {
|
|
57
|
+
return oracle;
|
|
58
|
+
}
|
|
59
|
+
// No-op close
|
|
60
|
+
if (prop === "close") {
|
|
61
|
+
return async () => { };
|
|
62
|
+
}
|
|
63
|
+
// Bind methods to target with transformed args.
|
|
64
|
+
// Use direct invocation (target[prop](...)) instead of .call() because
|
|
65
|
+
// Cloudflare RPC stubs intercept property access - .call() would be
|
|
66
|
+
// interpreted as an RPC method name rather than Function.prototype.call.
|
|
67
|
+
if (typeof target[prop] === "function") {
|
|
68
|
+
return (...args) => target[prop](...transformArgs(...args));
|
|
69
|
+
}
|
|
70
|
+
return target[prop];
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare WebSocket adapter for the platform-agnostic sync protocol.
|
|
3
|
+
* This adapter wraps a Cloudflare Worker WebSocket to implement the SyncWebSocket interface.
|
|
4
|
+
*/
|
|
5
|
+
import type { SyncWebSocket } from "@concavejs/core/sync";
|
|
6
|
+
/**
|
|
7
|
+
* WebSocket wrapper to adapt CF WebSocket to platform-agnostic interface
|
|
8
|
+
*/
|
|
9
|
+
export declare class CFWebSocketAdapter implements SyncWebSocket {
|
|
10
|
+
private ws;
|
|
11
|
+
constructor(ws: WebSocket);
|
|
12
|
+
send(data: string): void;
|
|
13
|
+
close(code?: number, reason?: string): void;
|
|
14
|
+
get readyState(): number;
|
|
15
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloudflare WebSocket adapter for the platform-agnostic sync protocol.
|
|
3
|
+
* This adapter wraps a Cloudflare Worker WebSocket to implement the SyncWebSocket interface.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* WebSocket wrapper to adapt CF WebSocket to platform-agnostic interface
|
|
7
|
+
*/
|
|
8
|
+
export class CFWebSocketAdapter {
|
|
9
|
+
ws;
|
|
10
|
+
constructor(ws) {
|
|
11
|
+
this.ws = ws;
|
|
12
|
+
}
|
|
13
|
+
send(data) {
|
|
14
|
+
this.ws.send(data);
|
|
15
|
+
}
|
|
16
|
+
close(code, reason) {
|
|
17
|
+
this.ws.close(code, reason);
|
|
18
|
+
}
|
|
19
|
+
get readyState() {
|
|
20
|
+
return this.ws.readyState;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UDF executor that delegates to ConcaveDO via stub.
|
|
3
|
+
* Shared between runtime-cf and runtime-cloud.
|
|
4
|
+
*/
|
|
5
|
+
import type { SyncUdfExecutor, AuthContext } from "@concavejs/core/sync";
|
|
6
|
+
import type { JSONValue } from "convex/values";
|
|
7
|
+
import type { SerializedKeyRange } from "@concavejs/core/queryengine";
|
|
8
|
+
import type { UdfResult } from "@concavejs/core/udf";
|
|
9
|
+
type MinimalDOStub = {
|
|
10
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* UDF executor that delegates to ConcaveDO
|
|
14
|
+
*/
|
|
15
|
+
export declare class ConcaveDOUdfExecutor implements SyncUdfExecutor {
|
|
16
|
+
private readonly getConcaveStub;
|
|
17
|
+
private readonly projectId?;
|
|
18
|
+
constructor(getConcaveStub: () => MinimalDOStub, projectId?: string | undefined);
|
|
19
|
+
private createAdapter;
|
|
20
|
+
executeQuery(path: string, args: Record<string, any>, auth: AuthContext, componentPath?: string): Promise<{
|
|
21
|
+
result: JSONValue;
|
|
22
|
+
readRanges?: SerializedKeyRange[];
|
|
23
|
+
logLines?: string[];
|
|
24
|
+
trace?: UdfResult["trace"];
|
|
25
|
+
snapshotTimestamp?: bigint;
|
|
26
|
+
}>;
|
|
27
|
+
executeMutation(path: string, args: Record<string, any>, auth: AuthContext, componentPath?: string): Promise<{
|
|
28
|
+
result: JSONValue;
|
|
29
|
+
writtenRanges?: SerializedKeyRange[];
|
|
30
|
+
writtenTables?: string[];
|
|
31
|
+
logLines?: string[];
|
|
32
|
+
trace?: UdfResult["trace"];
|
|
33
|
+
commitTimestamp?: bigint;
|
|
34
|
+
snapshotTimestamp?: bigint;
|
|
35
|
+
}>;
|
|
36
|
+
executeAction(path: string, args: Record<string, any>, auth: AuthContext, componentPath?: string): Promise<{
|
|
37
|
+
result: JSONValue;
|
|
38
|
+
writtenRanges?: SerializedKeyRange[];
|
|
39
|
+
writtenTables?: string[];
|
|
40
|
+
logLines?: string[];
|
|
41
|
+
trace?: UdfResult["trace"];
|
|
42
|
+
commitTimestamp?: bigint;
|
|
43
|
+
snapshotTimestamp?: bigint;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UDF executor that delegates to ConcaveDO via stub.
|
|
3
|
+
* Shared between runtime-cf and runtime-cloud.
|
|
4
|
+
*/
|
|
5
|
+
import { createClientAdapter } from "@concavejs/core/udf/execution-adapter";
|
|
6
|
+
import { writtenTablesFromRanges } from "@concavejs/core/utils";
|
|
7
|
+
import { ConcaveStubExecutor } from "../udf/executor/do-client-executor";
|
|
8
|
+
/**
|
|
9
|
+
* UDF executor that delegates to ConcaveDO
|
|
10
|
+
*/
|
|
11
|
+
export class ConcaveDOUdfExecutor {
|
|
12
|
+
getConcaveStub;
|
|
13
|
+
projectId;
|
|
14
|
+
constructor(getConcaveStub, projectId) {
|
|
15
|
+
this.getConcaveStub = getConcaveStub;
|
|
16
|
+
this.projectId = projectId;
|
|
17
|
+
}
|
|
18
|
+
createAdapter() {
|
|
19
|
+
const stub = this.getConcaveStub();
|
|
20
|
+
// Create a wrapper stub that adds the projectId header to all requests
|
|
21
|
+
const wrappedStub = {
|
|
22
|
+
fetch: async (input, init) => {
|
|
23
|
+
const headers = new Headers(init?.headers);
|
|
24
|
+
if (this.projectId) {
|
|
25
|
+
headers.set("X-Concave-Project-Id", this.projectId);
|
|
26
|
+
}
|
|
27
|
+
return stub.fetch(input, {
|
|
28
|
+
...init,
|
|
29
|
+
headers,
|
|
30
|
+
});
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
// Cast to any to satisfy ConcaveStubExecutor which expects full DurableObjectStub
|
|
34
|
+
// We only use the fetch method, so this is safe
|
|
35
|
+
const executor = new ConcaveStubExecutor(wrappedStub);
|
|
36
|
+
return createClientAdapter(executor);
|
|
37
|
+
}
|
|
38
|
+
async executeQuery(path, args, auth, componentPath) {
|
|
39
|
+
const adapter = this.createAdapter();
|
|
40
|
+
const result = await adapter.executeUdf(path, args, "query", auth, componentPath);
|
|
41
|
+
return {
|
|
42
|
+
result: result.result,
|
|
43
|
+
readRanges: result.readRanges,
|
|
44
|
+
logLines: result.logLines,
|
|
45
|
+
trace: result.trace,
|
|
46
|
+
snapshotTimestamp: result.snapshotTimestamp,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async executeMutation(path, args, auth, componentPath) {
|
|
50
|
+
const adapter = this.createAdapter();
|
|
51
|
+
const result = await adapter.executeUdf(path, args, "mutation", auth, componentPath);
|
|
52
|
+
return {
|
|
53
|
+
result: result.result,
|
|
54
|
+
writtenRanges: result.writtenRanges,
|
|
55
|
+
writtenTables: result.writtenRanges ? writtenTablesFromRanges(result.writtenRanges) : undefined,
|
|
56
|
+
logLines: result.logLines,
|
|
57
|
+
trace: result.trace,
|
|
58
|
+
commitTimestamp: result.commitTimestamp,
|
|
59
|
+
snapshotTimestamp: result.snapshotTimestamp,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async executeAction(path, args, auth, componentPath) {
|
|
63
|
+
const adapter = this.createAdapter();
|
|
64
|
+
const result = await adapter.executeUdf(path, args, "action", auth, componentPath);
|
|
65
|
+
return {
|
|
66
|
+
result: result.result,
|
|
67
|
+
writtenRanges: result.writtenRanges,
|
|
68
|
+
writtenTables: result.writtenRanges ? writtenTablesFromRanges(result.writtenRanges) : undefined,
|
|
69
|
+
logLines: result.logLines,
|
|
70
|
+
trace: result.trace,
|
|
71
|
+
commitTimestamp: result.commitTimestamp,
|
|
72
|
+
snapshotTimestamp: result.snapshotTimestamp,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { UserIdentityAttributes } from "convex/server";
|
|
2
|
+
import type { DurableObjectStub } from "@cloudflare/workers-types";
|
|
3
|
+
import type { UdfExec, UdfResult } from "@concavejs/core/udf";
|
|
4
|
+
import type { AuthContext } from "@concavejs/core/sync/protocol-handler";
|
|
5
|
+
/**
|
|
6
|
+
* Durable Object stub executor that bridges HTTP API requests to ConcaveDO.
|
|
7
|
+
* Converts Convex values to JSON-safe payloads and forwards auth/context metadata.
|
|
8
|
+
*/
|
|
9
|
+
export declare class ConcaveStubExecutor implements UdfExec {
|
|
10
|
+
private readonly stub;
|
|
11
|
+
constructor(stub: DurableObjectStub);
|
|
12
|
+
execute(path: string, args: Record<string, any>, type: "query" | "mutation" | "action", auth?: AuthContext | UserIdentityAttributes, componentPath?: string, requestId?: string, snapshotTimestamp?: bigint): Promise<UdfResult>;
|
|
13
|
+
executeHttp(request: Request): Promise<Response>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { convexToJson } from "convex/values";
|
|
2
|
+
/**
|
|
3
|
+
* Durable Object stub executor that bridges HTTP API requests to ConcaveDO.
|
|
4
|
+
* Converts Convex values to JSON-safe payloads and forwards auth/context metadata.
|
|
5
|
+
*/
|
|
6
|
+
export class ConcaveStubExecutor {
|
|
7
|
+
stub;
|
|
8
|
+
constructor(stub) {
|
|
9
|
+
this.stub = stub;
|
|
10
|
+
}
|
|
11
|
+
async execute(path, args, type, auth, componentPath, requestId, snapshotTimestamp) {
|
|
12
|
+
const payload = {
|
|
13
|
+
path,
|
|
14
|
+
args: convexToJson(args),
|
|
15
|
+
type,
|
|
16
|
+
auth,
|
|
17
|
+
componentPath,
|
|
18
|
+
caller: "client",
|
|
19
|
+
requestId,
|
|
20
|
+
snapshotTimestamp: snapshotTimestamp?.toString(),
|
|
21
|
+
};
|
|
22
|
+
const response = await this.stub.fetch("http://do/execute", {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify(payload),
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const errorText = await response.text();
|
|
29
|
+
// Try to parse JSON error from ConcaveDO (e.g., { error: "message" })
|
|
30
|
+
let errorMessage = errorText;
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(errorText);
|
|
33
|
+
if (parsed?.error) {
|
|
34
|
+
errorMessage = parsed.error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Not JSON, use raw text
|
|
39
|
+
}
|
|
40
|
+
// Strip "UDF execution failed: " prefix from shim errors to expose original message
|
|
41
|
+
const udfPrefix = "UDF execution failed: ";
|
|
42
|
+
if (errorMessage.startsWith(udfPrefix)) {
|
|
43
|
+
errorMessage = errorMessage.slice(udfPrefix.length);
|
|
44
|
+
}
|
|
45
|
+
throw new Error(errorMessage);
|
|
46
|
+
}
|
|
47
|
+
const result = (await response.json());
|
|
48
|
+
const normalized = {
|
|
49
|
+
...result,
|
|
50
|
+
commitTimestamp: result.commitTimestamp ? BigInt(result.commitTimestamp) : undefined,
|
|
51
|
+
snapshotTimestamp: result.snapshotTimestamp ? BigInt(result.snapshotTimestamp) : undefined,
|
|
52
|
+
};
|
|
53
|
+
return normalized;
|
|
54
|
+
}
|
|
55
|
+
async executeHttp(request) {
|
|
56
|
+
return this.stub.fetch(request);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DocStore } from "@concavejs/core/docstore";
|
|
2
|
+
import type { BlobStore } from "@concavejs/core/abstractions";
|
|
3
|
+
import { InlineUdfExecutor } from "@concavejs/core/udf";
|
|
4
|
+
export declare class UdfExecInline extends InlineUdfExecutor {
|
|
5
|
+
/**
|
|
6
|
+
* Create an inline UDF executor.
|
|
7
|
+
*
|
|
8
|
+
* @param docstore - Document store for data storage
|
|
9
|
+
* @param blobstoreOrBucket - Either a BlobStore or an R2Bucket
|
|
10
|
+
* @param r2PublicUrl - Public URL for R2 (only used if blobstoreOrBucket is an R2Bucket)
|
|
11
|
+
*/
|
|
12
|
+
constructor(docstore: DocStore, blobstoreOrBucket?: BlobStore | R2Bucket, r2PublicUrl?: string);
|
|
13
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { InlineUdfExecutor } from "@concavejs/core/udf";
|
|
2
|
+
import { R2BlobStore } from "@concavejs/blobstore-cf-r2";
|
|
3
|
+
export class UdfExecInline extends InlineUdfExecutor {
|
|
4
|
+
/**
|
|
5
|
+
* Create an inline UDF executor.
|
|
6
|
+
*
|
|
7
|
+
* @param docstore - Document store for data storage
|
|
8
|
+
* @param blobstoreOrBucket - Either a BlobStore or an R2Bucket
|
|
9
|
+
* @param r2PublicUrl - Public URL for R2 (only used if blobstoreOrBucket is an R2Bucket)
|
|
10
|
+
*/
|
|
11
|
+
constructor(docstore, blobstoreOrBucket, r2PublicUrl) {
|
|
12
|
+
let blobstore;
|
|
13
|
+
if (blobstoreOrBucket) {
|
|
14
|
+
// Check if it's already a BlobStore (has store method)
|
|
15
|
+
if (typeof blobstoreOrBucket.store === "function") {
|
|
16
|
+
blobstore = blobstoreOrBucket;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
// It's an R2Bucket, wrap it
|
|
20
|
+
blobstore = new R2BlobStore(blobstoreOrBucket, r2PublicUrl);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
super({ docstore, blobstore, logger: console });
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { UdfExec, UdfResult } from "@concavejs/core/udf";
|
|
2
|
+
import type { UdfExecutorRpc } from "../../worker/udf-worker";
|
|
3
|
+
export interface UdfExecIsolatedOptions {
|
|
4
|
+
/** The RPC stub for the UDF worker */
|
|
5
|
+
stub: UdfExecutorRpc;
|
|
6
|
+
/** Instance name for syscall routing (default: "singleton") */
|
|
7
|
+
instance?: string;
|
|
8
|
+
/** Project ID for syscall routing (default: "default") */
|
|
9
|
+
projectId?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Executes a UDF in an isolated worker via RPC.
|
|
13
|
+
* This class acts as an RPC client.
|
|
14
|
+
*
|
|
15
|
+
* Supports passing instance context for proper syscall routing through the DO.
|
|
16
|
+
*/
|
|
17
|
+
export declare class UdfExecIsolated implements UdfExec {
|
|
18
|
+
private rpc;
|
|
19
|
+
private instance;
|
|
20
|
+
private projectId;
|
|
21
|
+
constructor(stubOrOptions: UdfExecutorRpc | UdfExecIsolatedOptions);
|
|
22
|
+
execute(path: string, args: Record<string, any>, type: "query" | "mutation" | "action", auth?: any, componentPath?: string, requestId?: string, snapshotTimestamp?: bigint): Promise<UdfResult>;
|
|
23
|
+
executeHttp(request: Request, auth?: any, requestId?: string): Promise<Response>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executes a UDF in an isolated worker via RPC.
|
|
3
|
+
* This class acts as an RPC client.
|
|
4
|
+
*
|
|
5
|
+
* Supports passing instance context for proper syscall routing through the DO.
|
|
6
|
+
*/
|
|
7
|
+
export class UdfExecIsolated {
|
|
8
|
+
rpc;
|
|
9
|
+
instance;
|
|
10
|
+
projectId;
|
|
11
|
+
constructor(stubOrOptions) {
|
|
12
|
+
if ("stub" in stubOrOptions) {
|
|
13
|
+
this.rpc = stubOrOptions.stub;
|
|
14
|
+
this.instance = stubOrOptions.instance ?? "singleton";
|
|
15
|
+
this.projectId = stubOrOptions.projectId ?? "default";
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
// Backwards compatibility: just the stub
|
|
19
|
+
this.rpc = stubOrOptions;
|
|
20
|
+
this.instance = "singleton";
|
|
21
|
+
this.projectId = "default";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async execute(path, args, type, auth, componentPath, requestId, snapshotTimestamp) {
|
|
25
|
+
// Pass instance context for syscall routing
|
|
26
|
+
return this.rpc.execute(path, args, type, auth, componentPath, requestId, snapshotTimestamp, this.instance, this.projectId);
|
|
27
|
+
}
|
|
28
|
+
async executeHttp(request, auth, requestId) {
|
|
29
|
+
return this.rpc.executeHttp(request, auth, requestId, this.instance, this.projectId);
|
|
30
|
+
}
|
|
31
|
+
}
|