@codenotch/process 0.0.0-dev
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/README.md +51 -0
- package/dist/activity.mjs +14 -0
- package/dist/template.mjs +21 -0
- package/dist/types/activity/index.d.ts +52 -0
- package/dist/types/lib/bindings.d.ts +48 -0
- package/dist/types/lib/canonical-json.d.ts +10 -0
- package/dist/types/lib/collections.d.ts +12 -0
- package/dist/types/lib/connectors.d.ts +299 -0
- package/dist/types/lib/context.d.ts +307 -0
- package/dist/types/lib/credits.d.ts +71 -0
- package/dist/types/lib/decimal.d.ts +72 -0
- package/dist/types/lib/duration.d.ts +40 -0
- package/dist/types/lib/encoding.d.ts +27 -0
- package/dist/types/lib/errors.d.ts +57 -0
- package/dist/types/lib/hash.d.ts +18 -0
- package/dist/types/lib/index.d.ts +25 -0
- package/dist/types/lib/instant.d.ts +41 -0
- package/dist/types/lib/meters.d.ts +61 -0
- package/dist/types/lib/registry.d.ts +131 -0
- package/dist/types/lib/renderings.d.ts +75 -0
- package/dist/types/lib/subscriptions.d.ts +61 -0
- package/dist/types/lib/types.d.ts +89 -0
- package/dist/types/lib/urls.d.ts +36 -0
- package/dist/types/lib/userTasks.d.ts +119 -0
- package/dist/types/lib/validators.d.ts +22 -0
- package/dist/types/lib/webPush.d.ts +30 -0
- package/dist/types/template/index.d.ts +17 -0
- package/dist/types/testing/api.d.ts +175 -0
- package/dist/types/testing/index.d.ts +2 -0
- package/dist/types/testing/main.d.ts +1 -0
- package/dist/types/testing/stdlib.d.ts +79 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# @codenotch/process
|
|
2
|
+
|
|
3
|
+
The standard library and type surface of Codenotch script processes.
|
|
4
|
+
|
|
5
|
+
Script processes execute **on the server only**: the engine embeds this package's
|
|
6
|
+
compiled runtime and serves it to `require('@codenotch/process')` inside the V8 workflow
|
|
7
|
+
sandbox. What the package distributes to process authors is the **type declarations**
|
|
8
|
+
(`dist/types`) — there is no client-side execution, and the runtime never ships in a
|
|
9
|
+
process bundle (the deploy bundler treats the package as external).
|
|
10
|
+
|
|
11
|
+
## Layout
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/lib the public library: process()/triggers, ctx (Context), errors,
|
|
15
|
+
Instant, Duration, Decimal, encodings, url, canonicalJson, is, hash.
|
|
16
|
+
Pure TypeScript; talks to the engine only through the EngineBindings
|
|
17
|
+
seam (bindings.ts). dist/types is emitted from here.
|
|
18
|
+
src/runtime the wire-protocol layer: sandbox hardening, the command channel over
|
|
19
|
+
the __host adapter, and the engine entry points (__start, __deliver,
|
|
20
|
+
__cancelDeliver, __deliverChildEvent, __processMetadataJson,
|
|
21
|
+
__concurrencyKey). Engine-internal — never part of the public types.
|
|
22
|
+
src/activity the '@codenotch/process/activity' entry: activity() and the activity-side
|
|
23
|
+
types. Ships as runtime JS (dist/activity.mjs) — the deploy bundler
|
|
24
|
+
inlines it into each activity bundle (activities run on Node).
|
|
25
|
+
src/testing the '@codenotch/process/testing' entry: the process-test facade
|
|
26
|
+
(test/expect/env — see doc/reference/process-tests.md). Its bundle
|
|
27
|
+
(dist/test-prelude.js) is the engine's V8 test-host prelude; the entry
|
|
28
|
+
distributes types only, like the root.
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Build
|
|
32
|
+
|
|
33
|
+
`node build.mjs` — type-checks, emits `dist/types` and bundles the three runtimes:
|
|
34
|
+
`src/runtime/prelude.ts` → `dist/prelude.js` (IIFE), `src/activity/index.ts` →
|
|
35
|
+
`dist/activity.mjs`, `src/testing/main.ts` → `dist/test-prelude.js` (IIFE). Output files
|
|
36
|
+
are rewritten only when content changed. The `Echino.Services.Framework.Processes`
|
|
37
|
+
csproj runs this automatically when sources changed and embeds `dist/prelude.js`
|
|
38
|
+
(`ScriptEngine.WorkflowPrelude.js`) and `dist/test-prelude.js`
|
|
39
|
+
(`ScriptEngine.TestPrelude.js`), so the engine and the types can never drift.
|
|
40
|
+
|
|
41
|
+
`dist/` is committed: a .NET-only checkout builds without running npm as long as the
|
|
42
|
+
TypeScript sources are untouched.
|
|
43
|
+
|
|
44
|
+
## Rules (doc/reference/process-stdlib.md holds the user-facing docs)
|
|
45
|
+
|
|
46
|
+
- Every `ctx` method and library function is documented (JSDoc here, reference doc there)
|
|
47
|
+
and covered by an example-grade fixture in
|
|
48
|
+
`test/Echino.Services.Framework.Processes.Test/testSchemas/StdlibTests`.
|
|
49
|
+
- Strong typing first, dynamic as fallback (`ctx.call(handle)` over `ctx.call<In, Out>('name')`).
|
|
50
|
+
- The library layer stays pure: anything touching the world goes through the bindings
|
|
51
|
+
seam and is journaled by the engine.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/activity/index.ts
|
|
2
|
+
function activity(first, second) {
|
|
3
|
+
const impl = typeof first === "function" ? first : second;
|
|
4
|
+
const defaults = typeof first === "function" ? {} : first;
|
|
5
|
+
if (typeof impl !== "function")
|
|
6
|
+
throw new Error("activity() requires the implementation function (io, args) => result");
|
|
7
|
+
return Object.assign(
|
|
8
|
+
(io, args) => impl(io, args),
|
|
9
|
+
{ __codenotchActivity: true, __options: defaults ?? {} }
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
activity
|
|
14
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/template/index.ts
|
|
2
|
+
var declare = (kind, render, page) => Object.freeze(page === void 0 ? { __codenotchTemplate: true, kind, render } : { __codenotchTemplate: true, kind, page, render });
|
|
3
|
+
var template = Object.freeze({
|
|
4
|
+
/** Declares an email template: render(data) returns { subject, html, text? }. */
|
|
5
|
+
email: (render) => declare("email", render),
|
|
6
|
+
/**
|
|
7
|
+
* Declares a pdf template: render(data) returns { html } (print CSS; Chromium paged
|
|
8
|
+
* media — @page margin boxes, counter(page/pages) — works natively). The optional
|
|
9
|
+
* first argument sets the page: template.pdf({ format: 'A4' }, render).
|
|
10
|
+
*/
|
|
11
|
+
pdf: ((pageOrRender, render) => {
|
|
12
|
+
if (typeof pageOrRender === "function")
|
|
13
|
+
return declare("pdf", pageOrRender);
|
|
14
|
+
if (typeof render !== "function")
|
|
15
|
+
throw new Error("template.pdf requires a render function");
|
|
16
|
+
return declare("pdf", render, pageOrRender);
|
|
17
|
+
})
|
|
18
|
+
});
|
|
19
|
+
export {
|
|
20
|
+
template
|
|
21
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Activity, DurationLike, RetryPolicy } from '../lib/types';
|
|
2
|
+
export type ActivityLogger = {
|
|
3
|
+
debug(message: string, data?: unknown): void;
|
|
4
|
+
info(message: string, data?: unknown): void;
|
|
5
|
+
warn(message: string, data?: unknown): void;
|
|
6
|
+
error(message: string, data?: unknown): void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Resolves to the real AbortSignal when the consumer's environment declares it
|
|
10
|
+
* (activities type-check with node types); a minimal structural shape otherwise
|
|
11
|
+
* (this package itself compiles against pure ES2022).
|
|
12
|
+
*/
|
|
13
|
+
export type ActivityAbortSignal = typeof globalThis extends {
|
|
14
|
+
AbortSignal: {
|
|
15
|
+
prototype: infer T;
|
|
16
|
+
};
|
|
17
|
+
} ? T : {
|
|
18
|
+
readonly aborted: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** The activity-side services handed to every invocation. */
|
|
21
|
+
export type ActivityIo = {
|
|
22
|
+
log: ActivityLogger;
|
|
23
|
+
/** Stable across retries of one journaled execution — pass to providers that dedupe. */
|
|
24
|
+
idempotencyKey: string;
|
|
25
|
+
/** Aborts when the invocation's timeout elapses; long I/O should honor it. */
|
|
26
|
+
signal: ActivityAbortSignal;
|
|
27
|
+
project: string;
|
|
28
|
+
/** Base URL + auth header/token for calling back into the platform APIs. */
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
token: string;
|
|
31
|
+
tokenHeader: string;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Reserved for enforced defaults (a later milestone extracts them into the deploy
|
|
35
|
+
* metadata); v1 enforces the options given at the ctx.activity call site.
|
|
36
|
+
*/
|
|
37
|
+
export type ActivityDefaults = {
|
|
38
|
+
retry?: RetryPolicy;
|
|
39
|
+
timeout?: DurationLike;
|
|
40
|
+
};
|
|
41
|
+
export type ActivityImpl<In, Out> = (io: ActivityIo, args: In) => Out | PromiseLike<Out>;
|
|
42
|
+
/**
|
|
43
|
+
* The defined activity: directly callable on the Node side (unit tests), and a
|
|
44
|
+
* typed Activity handle from workflow code (via the bundler's reference stub).
|
|
45
|
+
*/
|
|
46
|
+
export type ActivityHandle<In, Out> = ActivityImpl<In, Out> & Activity<In, Out>;
|
|
47
|
+
/**
|
|
48
|
+
* Declares an activity. Export the result from a *.activity.ts module; workflow
|
|
49
|
+
* code imports it and passes it to ctx.activity for a fully typed invocation.
|
|
50
|
+
*/
|
|
51
|
+
export declare function activity<In, Out>(impl: ActivityImpl<In, Out>): ActivityHandle<In, Out>;
|
|
52
|
+
export declare function activity<In, Out>(defaults: ActivityDefaults, impl: ActivityImpl<In, Out>): ActivityHandle<In, Out>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** @internal Hooks the library attaches to one emitted command's outcome. */
|
|
2
|
+
export interface CommandAwaiterHooks {
|
|
3
|
+
/** Called synchronously when the outcome is delivered (ok=false carries the serialized error). */
|
|
4
|
+
settle(ok: boolean, value: unknown): void;
|
|
5
|
+
/**
|
|
6
|
+
* Present → the command is a PARK (timer/signal/child await): instance cancellation
|
|
7
|
+
* rejects it. Absent → an in-flight effect (activity): its outcome still settles so
|
|
8
|
+
* the compensation chain stays complete.
|
|
9
|
+
*/
|
|
10
|
+
cancel?(reason: string | null): void;
|
|
11
|
+
/** Present on child calls: a declared event the callee sent. */
|
|
12
|
+
childEvent?(eventId: string, payload: unknown): void;
|
|
13
|
+
}
|
|
14
|
+
/** @internal What the wire-protocol layer provides to the library. */
|
|
15
|
+
export interface EngineBindings {
|
|
16
|
+
/** Emits a command and returns its emission index. */
|
|
17
|
+
emit(kind: string, args?: unknown): number;
|
|
18
|
+
/** Registers the outcome hooks of an emitted command. */
|
|
19
|
+
awaitOutcome(commandIndex: number, hooks: CommandAwaiterHooks): void;
|
|
20
|
+
/** True once the instance received a cancellation. */
|
|
21
|
+
isCancelled(): boolean;
|
|
22
|
+
cancelReason(): string | null;
|
|
23
|
+
/** Whether the command at the index is beyond the journaled history (live). */
|
|
24
|
+
isLive(commandIndex: number): boolean;
|
|
25
|
+
/** Journals the result of a live ctx.run closure. */
|
|
26
|
+
sideEffectResult(commandIndex: number, resultJson: string | null): void;
|
|
27
|
+
/** Toggles the real clock/randomness (inside a live ctx.run closure only). */
|
|
28
|
+
setRealTime(on: boolean): void;
|
|
29
|
+
log(level: string, message: string, dataJson: string | null): void;
|
|
30
|
+
/** Deterministic journal time (ms since epoch). */
|
|
31
|
+
nowMs(): number;
|
|
32
|
+
/** Deterministic seeded random in [0,1). */
|
|
33
|
+
nextRandom(): number;
|
|
34
|
+
/** Deterministic uuid derived from the seeded PRNG. */
|
|
35
|
+
nextUuid(): string;
|
|
36
|
+
patched(marker: string): boolean;
|
|
37
|
+
continueAsNew(inputJson: string | null): void;
|
|
38
|
+
/** SHA-256 over base64 bytes, result base64. Pure function — safe outside the journal. */
|
|
39
|
+
hashSha256(dataBase64: string): string;
|
|
40
|
+
/** HMAC-SHA-256 over base64 key/data, result base64. */
|
|
41
|
+
hashHmacSha256(keyBase64: string, dataBase64: string): string;
|
|
42
|
+
/** Constant-time byte equality over base64 inputs. */
|
|
43
|
+
timingSafeEqual(aBase64: string, bBase64: string): boolean;
|
|
44
|
+
}
|
|
45
|
+
/** @internal Called once by the runtime prelude before any process code runs. */
|
|
46
|
+
export declare const setEngineBindings: (value: EngineBindings) => void;
|
|
47
|
+
/** @internal The active bindings; throws outside the server sandbox. */
|
|
48
|
+
export declare const engine: () => EngineBindings;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Serializable } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Canonical JSON: object keys sorted, no whitespace, stable across runs — the right
|
|
4
|
+
* form for anything derived from an object's content (concurrency keys, dedupe keys,
|
|
5
|
+
* hashes). Plain JSON.stringify is insertion-order dependent and must not feed a key.
|
|
6
|
+
*
|
|
7
|
+
* Follows JSON.stringify semantics otherwise: toJSON is honored, undefined properties
|
|
8
|
+
* drop, undefined array elements render as null. Circular references throw.
|
|
9
|
+
*/
|
|
10
|
+
export declare const canonicalJson: (value: Serializable) => string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits items into consecutive chunks of `size` (the last chunk may be shorter).
|
|
3
|
+
* The natural partner of ctx.map for paging work:
|
|
4
|
+
* `for (const page of chunk(ids, 100)) await ctx.map(page, { concurrency: 5 }, …)`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const chunk: <T>(items: readonly T[], size: number) => T[][];
|
|
7
|
+
/**
|
|
8
|
+
* The items with duplicates removed, judged by the given key; the FIRST occurrence of
|
|
9
|
+
* each key wins and the original order is kept. (For primitives, `[...new Set(items)]`
|
|
10
|
+
* already does the job.)
|
|
11
|
+
*/
|
|
12
|
+
export declare const uniqueBy: <T>(items: readonly T[], key: (item: T) => unknown) => T[];
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { Instant } from './instant';
|
|
2
|
+
import type { ActivityOptions } from './context';
|
|
3
|
+
import type { DurationLike, Json, RetryPolicy } from './types';
|
|
4
|
+
/** The connector kinds a manifest parameter can declare. */
|
|
5
|
+
export type ConnectorKind = 'payment' | 'email' | 'sms' | 'chat' | 'database' | 'objectStorage' | 'fileTransfer' | 'llm';
|
|
6
|
+
/**
|
|
7
|
+
* The inbound event types per connector kind, for the kinds that have an event source.
|
|
8
|
+
* Payment events are provider-neutral (normalized by the adapters); chat events pass the
|
|
9
|
+
* provider's own type through ('message' is the common one — Slack also delivers
|
|
10
|
+
* 'app_mention', 'reaction_added', …), so the chat union stays open.
|
|
11
|
+
*/
|
|
12
|
+
export interface ConnectorKindEvents {
|
|
13
|
+
payment: 'checkout.completed' | 'payment.succeeded' | 'payment.failed' | 'refund.succeeded' | 'refund.failed' | 'chargeback.opened' | 'chargeback.closed' | 'other';
|
|
14
|
+
chat: 'message' | (string & {});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The project's connector bindings (manifest parameter name → kind) — augmented via
|
|
18
|
+
* declaration merging by the generated connectors.d.ts so binding names and their event
|
|
19
|
+
* types autocomplete in connectorEvent(...). Plain strings are always accepted too.
|
|
20
|
+
*
|
|
21
|
+
* declare module '@codenotch/process' {
|
|
22
|
+
* interface ProjectConnectors { payments: 'payment'; teamChat: 'chat' }
|
|
23
|
+
* }
|
|
24
|
+
*/
|
|
25
|
+
export interface ProjectConnectors {
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The project's binding names of one kind — what ctx.payment(…) & friends accept. With a
|
|
29
|
+
* generated connectors.d.ts the right bindings autocomplete; any string stays accepted.
|
|
30
|
+
*/
|
|
31
|
+
export type ConnectorBindingOf<K extends ConnectorKind> = ({
|
|
32
|
+
[B in keyof ProjectConnectors]: ProjectConnectors[B] extends K ? B : never;
|
|
33
|
+
}[keyof ProjectConnectors] & string) | (string & {});
|
|
34
|
+
/**
|
|
35
|
+
* Metered calls (the sends, llm.generate) are counted by the framework and attributed to the
|
|
36
|
+
* user who started the process; set meterUser to attribute the usage to someone else — e.g.
|
|
37
|
+
* a webhook-triggered process has no starting user but knows whose email it sends.
|
|
38
|
+
*/
|
|
39
|
+
export interface MeterAttribution {
|
|
40
|
+
meterUser?: string;
|
|
41
|
+
}
|
|
42
|
+
/** One email attachment. A string content is UTF-8 text; pass bytes for binary files. */
|
|
43
|
+
export interface EmailAttachment {
|
|
44
|
+
fileName: string;
|
|
45
|
+
/** MIME type; default application/octet-stream. */
|
|
46
|
+
contentType?: string;
|
|
47
|
+
content: string | Uint8Array;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Attach a stored rendering by reference — pass a ctx.render.pdf result directly. The
|
|
51
|
+
* server resolves the bytes at send time; they never travel through the process.
|
|
52
|
+
*/
|
|
53
|
+
export interface RenderingAttachment {
|
|
54
|
+
renderingId: string;
|
|
55
|
+
/** Override the rendering's stored file name. */
|
|
56
|
+
fileName?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface EmailMessage {
|
|
59
|
+
to: string | string[];
|
|
60
|
+
cc?: string | string[];
|
|
61
|
+
bcc?: string | string[];
|
|
62
|
+
subject: string;
|
|
63
|
+
/** Plain-text body. At least one of text and html is required. */
|
|
64
|
+
text?: string;
|
|
65
|
+
/** HTML body. */
|
|
66
|
+
html?: string;
|
|
67
|
+
replyTo?: string;
|
|
68
|
+
/** Override the connector's default sender address (providers may refuse foreign senders). */
|
|
69
|
+
from?: string;
|
|
70
|
+
fromName?: string;
|
|
71
|
+
/** Requires the 'attachments' capability. */
|
|
72
|
+
attachments?: (EmailAttachment | RenderingAttachment)[];
|
|
73
|
+
}
|
|
74
|
+
export interface EmailHandle {
|
|
75
|
+
/**
|
|
76
|
+
* Send one email. At-least-once and NOT retried by default (a retry could deliver the
|
|
77
|
+
* message twice) — pass opts.retry to opt in for idempotent content.
|
|
78
|
+
*/
|
|
79
|
+
send(message: EmailMessage, opts?: ActivityOptions & MeterAttribution): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export interface SmsMessage {
|
|
82
|
+
/** The recipient in E.164 form (+41791234567). */
|
|
83
|
+
to: string;
|
|
84
|
+
text: string;
|
|
85
|
+
/** Alphanumeric sender override. Requires the 'senderId' capability. */
|
|
86
|
+
senderId?: string;
|
|
87
|
+
}
|
|
88
|
+
export interface SmsHandle {
|
|
89
|
+
/** Send one SMS. At-least-once and NOT retried by default — pass opts.retry to opt in. */
|
|
90
|
+
send(message: SmsMessage, opts?: ActivityOptions & MeterAttribution): Promise<void>;
|
|
91
|
+
}
|
|
92
|
+
export interface ChatMessage {
|
|
93
|
+
text: string;
|
|
94
|
+
/** Post somewhere other than the connector's configured channel. Requires the 'channelOverride' capability. */
|
|
95
|
+
channel?: string;
|
|
96
|
+
}
|
|
97
|
+
export interface ChatHandle {
|
|
98
|
+
/** Post one message to the connected chat channel. At-least-once and NOT retried by default. */
|
|
99
|
+
send(message: string | ChatMessage, opts?: ActivityOptions & MeterAttribution): Promise<void>;
|
|
100
|
+
}
|
|
101
|
+
export interface ObjectStorageItem {
|
|
102
|
+
key: string;
|
|
103
|
+
/** Bytes. */
|
|
104
|
+
size: number;
|
|
105
|
+
modified?: Instant;
|
|
106
|
+
}
|
|
107
|
+
export interface ObjectStorageHandle {
|
|
108
|
+
/** Store an object: a string is written as UTF-8 text, bytes as-is. Overwrites. */
|
|
109
|
+
put(key: string, body: string | Uint8Array, opts?: {
|
|
110
|
+
contentType?: string;
|
|
111
|
+
} & ActivityOptions): Promise<void>;
|
|
112
|
+
/** Read an object's bytes. */
|
|
113
|
+
get(key: string, opts: {
|
|
114
|
+
binary: true;
|
|
115
|
+
} & ActivityOptions): Promise<Uint8Array>;
|
|
116
|
+
/** Read an object as UTF-8 text (a non-text object fails with objectStorage.binaryContent). */
|
|
117
|
+
get(key: string, opts?: {
|
|
118
|
+
binary?: false;
|
|
119
|
+
} & ActivityOptions): Promise<string>;
|
|
120
|
+
/** The objects under a key prefix ('' = everything). The whole listing is journaled — keep prefixes narrow. */
|
|
121
|
+
list(prefix?: string, opts?: ActivityOptions): Promise<ObjectStorageItem[]>;
|
|
122
|
+
exists(key: string, opts?: ActivityOptions): Promise<boolean>;
|
|
123
|
+
/** Idempotent: deleting a missing key succeeds. */
|
|
124
|
+
delete(key: string, opts?: ActivityOptions): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* A presigned direct-download URL — the way to hand big objects to users without
|
|
127
|
+
* moving the bytes through the workflow. Requires the 'presignedUrls' capability.
|
|
128
|
+
*/
|
|
129
|
+
downloadUrl(key: string, validity: DurationLike, opts?: ActivityOptions): Promise<string>;
|
|
130
|
+
}
|
|
131
|
+
export interface FileTransferItem {
|
|
132
|
+
name: string;
|
|
133
|
+
/** Path relative to the connector's root. */
|
|
134
|
+
path: string;
|
|
135
|
+
isDirectory: boolean;
|
|
136
|
+
/** Bytes. */
|
|
137
|
+
size: number;
|
|
138
|
+
modified?: Instant;
|
|
139
|
+
}
|
|
140
|
+
export interface FileTransferHandle {
|
|
141
|
+
/** Write a remote file: a string as UTF-8 text, bytes as-is. Overwrites. */
|
|
142
|
+
upload(path: string, body: string | Uint8Array, opts?: ActivityOptions): Promise<void>;
|
|
143
|
+
/** Read a remote file's bytes. */
|
|
144
|
+
download(path: string, opts: {
|
|
145
|
+
binary: true;
|
|
146
|
+
} & ActivityOptions): Promise<Uint8Array>;
|
|
147
|
+
/** Read a remote file as UTF-8 text (a binary file fails with fileTransfer.binaryContent). */
|
|
148
|
+
download(path: string, opts?: {
|
|
149
|
+
binary?: false;
|
|
150
|
+
} & ActivityOptions): Promise<string>;
|
|
151
|
+
/** The entries of a directory ('' = the connector's root), non-recursive. */
|
|
152
|
+
list(directory?: string, opts?: ActivityOptions): Promise<FileTransferItem[]>;
|
|
153
|
+
exists(path: string, opts?: ActivityOptions): Promise<boolean>;
|
|
154
|
+
delete(path: string, opts?: ActivityOptions): Promise<void>;
|
|
155
|
+
}
|
|
156
|
+
export interface CheckoutRequest {
|
|
157
|
+
/** Amount as a positive integer in the currency's smallest unit (4990 = CHF 49.90). */
|
|
158
|
+
amountMinor: number;
|
|
159
|
+
/** ISO 4217 code ('chf', 'eur', 'usd'). */
|
|
160
|
+
currency: string;
|
|
161
|
+
/** What the buyer sees on the provider's payment page. */
|
|
162
|
+
productName: string;
|
|
163
|
+
/** Your own reference (order id) — carried to the provider, echoed in events, idempotency basis. */
|
|
164
|
+
reference: string;
|
|
165
|
+
/** Where the provider redirects the buyer after paying. */
|
|
166
|
+
successUrl: string;
|
|
167
|
+
/** Where the provider redirects a buyer who backs out. */
|
|
168
|
+
cancelUrl: string;
|
|
169
|
+
/** Keep the payment method for later off-session charges. Requires the 'savedPaymentMethods' capability. */
|
|
170
|
+
savePaymentMethod?: boolean;
|
|
171
|
+
/** The provider's customer id from an earlier checkout, to attach this payment to it. */
|
|
172
|
+
customerRef?: string;
|
|
173
|
+
/** Prefills the provider's payment page. */
|
|
174
|
+
customerEmail?: string;
|
|
175
|
+
metadata?: Record<string, string>;
|
|
176
|
+
}
|
|
177
|
+
export interface CheckoutSession {
|
|
178
|
+
/** The provider-hosted payment page. Hand it to the buyer (respond redirect, link, …). */
|
|
179
|
+
redirectUrl: string;
|
|
180
|
+
/** The provider's reference for this payment — what get() polls. */
|
|
181
|
+
paymentRef: string;
|
|
182
|
+
}
|
|
183
|
+
export type PaymentStatus = 'pending' | 'paid' | 'canceled' | 'refunded' | 'partiallyRefunded' | 'unknown';
|
|
184
|
+
export interface PaymentState {
|
|
185
|
+
status: PaymentStatus;
|
|
186
|
+
amountMinor: number;
|
|
187
|
+
currency: string;
|
|
188
|
+
refundedMinor: number;
|
|
189
|
+
/** The reference the checkout carried. */
|
|
190
|
+
reference?: string;
|
|
191
|
+
customerRef?: string;
|
|
192
|
+
/** Present after a savePaymentMethod checkout succeeded — the token chargeSavedMethod uses. */
|
|
193
|
+
savedMethodRef?: string;
|
|
194
|
+
}
|
|
195
|
+
export interface RefundResult {
|
|
196
|
+
/** 'accepted' is a normal outcome: refunds are asynchronous by contract. */
|
|
197
|
+
outcome: 'accepted' | 'succeeded' | 'refused';
|
|
198
|
+
refundRef?: string;
|
|
199
|
+
error?: string;
|
|
200
|
+
}
|
|
201
|
+
export interface ChargeRequest {
|
|
202
|
+
customerRef: string;
|
|
203
|
+
savedMethodRef: string;
|
|
204
|
+
/** Positive integer in the currency's smallest unit. */
|
|
205
|
+
amountMinor: number;
|
|
206
|
+
currency: string;
|
|
207
|
+
reference: string;
|
|
208
|
+
}
|
|
209
|
+
export interface ChargeResult {
|
|
210
|
+
/** 'authenticationRequired' (European SCA) is a normal outcome, not an error. */
|
|
211
|
+
outcome: 'succeeded' | 'pending' | 'authenticationRequired' | 'failed';
|
|
212
|
+
paymentRef?: string;
|
|
213
|
+
error?: string;
|
|
214
|
+
}
|
|
215
|
+
export interface PaymentHandle {
|
|
216
|
+
/**
|
|
217
|
+
* Create a hosted checkout: the buyer pays on the provider's page, never on one the
|
|
218
|
+
* framework renders. Idempotent per reference with providers that support it. The
|
|
219
|
+
* outcome arrives out-of-band — poll get() (durably: in a ctx.wait loop) for it.
|
|
220
|
+
*/
|
|
221
|
+
checkout(request: CheckoutRequest, opts?: ActivityOptions): Promise<CheckoutSession>;
|
|
222
|
+
/** The authoritative payment state, polled from the provider. */
|
|
223
|
+
get(paymentRef: string, opts?: ActivityOptions): Promise<PaymentState>;
|
|
224
|
+
/**
|
|
225
|
+
* Refund a payment — fully, or partially with amountMinor (requires the
|
|
226
|
+
* 'partialRefunds' capability). Idempotent per execution.
|
|
227
|
+
*/
|
|
228
|
+
refund(paymentRef: string, opts?: {
|
|
229
|
+
amountMinor?: number;
|
|
230
|
+
} & ActivityOptions): Promise<RefundResult>;
|
|
231
|
+
/**
|
|
232
|
+
* Charge a saved payment method off-session (renewals). Requires the
|
|
233
|
+
* 'savedPaymentMethods' capability. Idempotent per execution.
|
|
234
|
+
*/
|
|
235
|
+
chargeSavedMethod(request: ChargeRequest, opts?: ActivityOptions): Promise<ChargeResult>;
|
|
236
|
+
}
|
|
237
|
+
export interface LlmMessage {
|
|
238
|
+
role: 'user' | 'assistant';
|
|
239
|
+
content: string;
|
|
240
|
+
}
|
|
241
|
+
export interface LlmUsage {
|
|
242
|
+
inputTokens: number;
|
|
243
|
+
outputTokens: number;
|
|
244
|
+
}
|
|
245
|
+
export type LlmStopReason = 'end' | 'maxTokens' | 'refusal';
|
|
246
|
+
export interface LlmRequest {
|
|
247
|
+
/** One user message — the simple form. Exactly one of prompt and messages. */
|
|
248
|
+
prompt?: string;
|
|
249
|
+
/** The full conversation, for multi-turn flows the process assembles itself. */
|
|
250
|
+
messages?: LlmMessage[];
|
|
251
|
+
system?: string;
|
|
252
|
+
/**
|
|
253
|
+
* JSON Schema the answer must conform to. The result then carries `data`, validated —
|
|
254
|
+
* or the call fails with llm.invalidJson, never mangled output. Present when
|
|
255
|
+
* stopReason is 'end' (a refusal or truncation has no data to validate).
|
|
256
|
+
*/
|
|
257
|
+
schema?: Json;
|
|
258
|
+
/** Overrides the connector's default model; checked against its allow-list. */
|
|
259
|
+
model?: string;
|
|
260
|
+
/** Output ceiling; the connector's maxOutputTokens setting caps it loudly. */
|
|
261
|
+
maxTokens?: number;
|
|
262
|
+
/** 0–2. Omit for the model's default. */
|
|
263
|
+
temperature?: number;
|
|
264
|
+
}
|
|
265
|
+
export interface LlmResult {
|
|
266
|
+
/** The model's output text (for schema calls: the JSON text). */
|
|
267
|
+
text: string;
|
|
268
|
+
/** The model that answered. */
|
|
269
|
+
model: string;
|
|
270
|
+
/** 'refusal' (the provider's safety layer declined) is a result to branch on, not an error. */
|
|
271
|
+
stopReason: LlmStopReason;
|
|
272
|
+
/** Journaled with the result — the numbers usage metering consumes. */
|
|
273
|
+
usage: LlmUsage;
|
|
274
|
+
}
|
|
275
|
+
export interface LlmHandle {
|
|
276
|
+
/**
|
|
277
|
+
* One model call, executed host-side as a journaled activity: it runs once and every
|
|
278
|
+
* replay returns the recording — the activity boundary is exactly what makes a
|
|
279
|
+
* non-deterministic model safe in deterministic workflow code.
|
|
280
|
+
*/
|
|
281
|
+
generate<T = Json>(request: LlmRequest & {
|
|
282
|
+
schema: Json;
|
|
283
|
+
}, opts?: ActivityOptions & MeterAttribution): Promise<LlmResult & {
|
|
284
|
+
data?: T;
|
|
285
|
+
}>;
|
|
286
|
+
generate(request: LlmRequest, opts?: ActivityOptions & MeterAttribution): Promise<LlmResult>;
|
|
287
|
+
}
|
|
288
|
+
/** @internal How the handles reach the activity channel — bound by createContext. */
|
|
289
|
+
export type ConnectorCall = <T>(name: string, input: Record<string, unknown>, opts: ActivityOptions | undefined, defaultRetry?: RetryPolicy) => Promise<T>;
|
|
290
|
+
/** @internal All six handle factories over one call binding. */
|
|
291
|
+
export declare const createConnectorHandles: (call: ConnectorCall, getMeterUser?: () => string | null) => {
|
|
292
|
+
email: (bindingName?: string) => EmailHandle;
|
|
293
|
+
sms: (bindingName?: string) => SmsHandle;
|
|
294
|
+
chat: (bindingName?: string) => ChatHandle;
|
|
295
|
+
objectStorage: (bindingName?: string) => ObjectStorageHandle;
|
|
296
|
+
fileTransfer: (bindingName?: string) => FileTransferHandle;
|
|
297
|
+
payment: (bindingName?: string) => PaymentHandle;
|
|
298
|
+
llm: (bindingName?: string) => LlmHandle;
|
|
299
|
+
};
|