@kici-dev/sdk 0.5.0 → 0.6.1
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/agent-cloud-init.d.ts +66 -0
- package/dist/agent-cloud-init.js +128 -0
- package/dist/api-types.d.ts +26 -0
- package/dist/api-types.js +20 -1
- package/dist/context.d.ts +21 -0
- package/dist/filter.test-d.d.ts +2 -0
- package/dist/filter.test-d.js +30 -0
- package/dist/git-types.d.ts +162 -0
- package/dist/git-types.js +32 -0
- package/dist/idempotent.js +3 -2
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -4
- package/dist/invoke.d.ts +29 -0
- package/dist/invoke.js +27 -0
- package/dist/job-outputs.test-d.js +32 -18
- package/dist/job.js +93 -1
- package/dist/needs-context.d.ts +31 -2
- package/dist/needs-context.js +3 -1
- package/dist/testing/step-context.js +3 -1
- package/dist/types.d.ts +72 -2
- package/package.json +4 -3
- package/sbom.spdx.json +40 -35
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Pass a claim code (ClaimCodeCredentials) so the token never
|
|
3
|
+
* transits cloud-init. Removed at v1.0.0.
|
|
4
|
+
*/
|
|
5
|
+
export interface CloudInitCredentials {
|
|
6
|
+
agentToken: string;
|
|
7
|
+
agentId: string;
|
|
8
|
+
orchestratorUrl: string;
|
|
9
|
+
labels: string[];
|
|
10
|
+
}
|
|
11
|
+
/** Preferred: the agent self-claims from a single-use code; the token is minted in-instance. */
|
|
12
|
+
export interface ClaimCodeCredentials {
|
|
13
|
+
claimCode: string;
|
|
14
|
+
agentId: string;
|
|
15
|
+
orchestratorUrl: string;
|
|
16
|
+
labels: string[];
|
|
17
|
+
}
|
|
18
|
+
/** Either credential shape accepted by `buildAgentCloudInit`. */
|
|
19
|
+
export type AgentCloudInitCredentials = CloudInitCredentials | ClaimCodeCredentials;
|
|
20
|
+
/** How the agent binary is delivered onto the instance. */
|
|
21
|
+
export type AgentDeliveryMode = 'container' | 'payload';
|
|
22
|
+
/** How the rendered `user_data` string is encoded before it is returned. */
|
|
23
|
+
export type UserDataEncoding = 'raw' | 'base64';
|
|
24
|
+
/** A cloud-init `write_files` entry the caller adds. */
|
|
25
|
+
export interface CloudInitWriteFile {
|
|
26
|
+
path: string;
|
|
27
|
+
content: string;
|
|
28
|
+
permissions?: string;
|
|
29
|
+
owner?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface AgentCloudInitOptions {
|
|
32
|
+
/** Hard lifetime cap (minutes) after which the instance powers itself off (L2). */
|
|
33
|
+
maxLifetimeMinutes: number;
|
|
34
|
+
/** 'container' (docker run the published agent image) | 'payload' (fetch from orchestrator). */
|
|
35
|
+
deliveryMode?: AgentDeliveryMode;
|
|
36
|
+
/** Container image ref (container mode). */
|
|
37
|
+
agentImage?: string;
|
|
38
|
+
/** Escape hatch: fully override the agent-start command (ignores deliveryMode/agentImage). */
|
|
39
|
+
startCommand?: string;
|
|
40
|
+
/** apt/yum packages → cloud-init `packages:` (unioned with the base). */
|
|
41
|
+
packages?: string[];
|
|
42
|
+
/** Extra `write_files` entries (the reserved env-file path is rejected). */
|
|
43
|
+
writeFiles?: CloudInitWriteFile[];
|
|
44
|
+
/** runcmd lines injected BEFORE the agent starts. */
|
|
45
|
+
runcmdBefore?: string[];
|
|
46
|
+
/** runcmd lines injected AFTER the agent starts. */
|
|
47
|
+
runcmdAfter?: string[];
|
|
48
|
+
/** Extra env appended to the agent env file (keys validated, newline values rejected). */
|
|
49
|
+
agentEnv?: Record<string, string>;
|
|
50
|
+
/** Raw cloud-config YAML to merge everything into (users, ssh, apt, mounts, bootcmd, …). */
|
|
51
|
+
baseCloudConfig?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Encoding of the returned `user_data` string. `'raw'` (the default) returns
|
|
54
|
+
* the plain `#cloud-config` text — what Hetzner `user_data` expects. `'base64'`
|
|
55
|
+
* returns the same text base64-encoded, the form AWS EC2 `UserData` and Azure
|
|
56
|
+
* `customData` expect.
|
|
57
|
+
*/
|
|
58
|
+
userDataEncoding?: UserDataEncoding;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Build the cloud-config `user_data` string. In the token form the agent token
|
|
62
|
+
* appears only in the reserved env-file write entry (`0600`, root-only); the
|
|
63
|
+
* claim-code form keeps the token off the provisioning channel entirely.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildAgentCloudInit(creds: AgentCloudInitCredentials, options: AgentCloudInitOptions): string;
|
|
66
|
+
//# sourceMappingURL=agent-cloud-init.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { parse, stringify } from "yaml";
|
|
3
|
+
//#region src/agent-cloud-init.ts
|
|
4
|
+
/**
|
|
5
|
+
* Cloud-init `user_data` builder for a scaler-provisioned KiCI agent.
|
|
6
|
+
*
|
|
7
|
+
* Renders a `#cloud-config` that installs + starts the agent with the claimed
|
|
8
|
+
* ephemeral credentials, plus teardown layer L2 — an in-instance max-lifetime
|
|
9
|
+
* self-poweroff. The agent token is written ONLY into a root-only `0600` env
|
|
10
|
+
* file; it never appears in a comment, a process argument, or any other file.
|
|
11
|
+
*/
|
|
12
|
+
const AGENT_ENV_FILE = "/etc/kici-agent.env";
|
|
13
|
+
const DEFAULT_AGENT_IMAGE = "quay.io/kici-dev/kici-agent:latest";
|
|
14
|
+
/**
|
|
15
|
+
* The credential-specific env lines. The claim-code form emits a single-use
|
|
16
|
+
* code the agent exchanges for its own token in-instance; the token form emits
|
|
17
|
+
* the token directly (the ONLY place the token appears).
|
|
18
|
+
*/
|
|
19
|
+
function credentialEnvLines(creds) {
|
|
20
|
+
if ("claimCode" in creds) return [
|
|
21
|
+
`KICI_ORCHESTRATOR_URL=${creds.orchestratorUrl}`,
|
|
22
|
+
`KICI_SCALER_CLAIM_CODE=${creds.claimCode}`,
|
|
23
|
+
`KICI_AGENT_ID=${creds.agentId}`,
|
|
24
|
+
`KICI_LABELS=${creds.labels.join(",")}`
|
|
25
|
+
];
|
|
26
|
+
return [
|
|
27
|
+
`KICI_ORCHESTRATOR_URL=${creds.orchestratorUrl}`,
|
|
28
|
+
`KICI_AGENT_TOKEN=${creds.agentToken}`,
|
|
29
|
+
`KICI_AGENT_ID=${creds.agentId}`,
|
|
30
|
+
`KICI_LABELS=${creds.labels.join(",")}`
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
/** Render the agent env-file content (the ONLY place the token appears, in the token form). */
|
|
34
|
+
function renderEnvFileContent(creds, agentEnv) {
|
|
35
|
+
return `${[
|
|
36
|
+
...credentialEnvLines(creds),
|
|
37
|
+
"KICI_SCALER_MANAGED=1",
|
|
38
|
+
...Object.entries(agentEnv ?? {}).map(([k, v]) => `${k}=${v}`)
|
|
39
|
+
].join("\n")}\n`;
|
|
40
|
+
}
|
|
41
|
+
/** Dedupe a list preserving first-seen order. */
|
|
42
|
+
function dedupe(items) {
|
|
43
|
+
return [...new Set(items)];
|
|
44
|
+
}
|
|
45
|
+
/** POSIX env-name shape: a letter or underscore, then letters/digits/underscores. */
|
|
46
|
+
const ENV_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
47
|
+
/** Reject agentEnv keys that are not POSIX env names and values carrying a newline. */
|
|
48
|
+
function validateAgentEnv(agentEnv) {
|
|
49
|
+
for (const [key, value] of Object.entries(agentEnv ?? {})) {
|
|
50
|
+
if (!ENV_NAME_RE.test(key)) throw new Error(`buildAgentCloudInit: invalid agentEnv key "${key}" (must be a POSIX env name)`);
|
|
51
|
+
if (value.includes("\n")) throw new Error(`buildAgentCloudInit: agentEnv value for "${key}" must not contain a newline`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Reject any caller/base write_files entry targeting the reserved env-file path. */
|
|
55
|
+
function assertNoReservedWrite(writeFiles, where) {
|
|
56
|
+
for (const wf of writeFiles ?? []) if (wf.path === AGENT_ENV_FILE) throw new Error(`buildAgentCloudInit: ${where} may not write the reserved path ${AGENT_ENV_FILE}`);
|
|
57
|
+
}
|
|
58
|
+
/** Parse + shape-check a caller-supplied base cloud-config. */
|
|
59
|
+
function parseBase(baseCloudConfig) {
|
|
60
|
+
let parsed;
|
|
61
|
+
try {
|
|
62
|
+
parsed = parse(baseCloudConfig);
|
|
63
|
+
} catch (err) {
|
|
64
|
+
throw new Error(`buildAgentCloudInit: baseCloudConfig is not valid YAML: ${err.message}`);
|
|
65
|
+
}
|
|
66
|
+
if (parsed == null) return {};
|
|
67
|
+
if (typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("buildAgentCloudInit: baseCloudConfig must be a cloud-config mapping");
|
|
68
|
+
const base = parsed;
|
|
69
|
+
for (const key of [
|
|
70
|
+
"packages",
|
|
71
|
+
"runcmd",
|
|
72
|
+
"write_files"
|
|
73
|
+
]) if (base[key] !== void 0 && !Array.isArray(base[key])) throw new Error(`buildAgentCloudInit: baseCloudConfig.${key} must be a list`);
|
|
74
|
+
return base;
|
|
75
|
+
}
|
|
76
|
+
/** Render the command that starts the agent for the chosen delivery mode. */
|
|
77
|
+
function renderStartCommand(opts) {
|
|
78
|
+
if (opts.startCommand) return opts.startCommand;
|
|
79
|
+
if (opts.deliveryMode === "payload") return "/usr/local/bin/kici-agent-bootstrap";
|
|
80
|
+
const image = opts.agentImage ?? DEFAULT_AGENT_IMAGE;
|
|
81
|
+
return `docker run -d --restart=no --name kici-agent --network host --env-file ${AGENT_ENV_FILE} ${image}`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Build the cloud-config `user_data` string. In the token form the agent token
|
|
85
|
+
* appears only in the reserved env-file write entry (`0600`, root-only); the
|
|
86
|
+
* claim-code form keeps the token off the provisioning channel entirely.
|
|
87
|
+
*/
|
|
88
|
+
function buildAgentCloudInit(creds, options) {
|
|
89
|
+
validateAgentEnv(options.agentEnv);
|
|
90
|
+
assertNoReservedWrite(options.writeFiles, "writeFiles");
|
|
91
|
+
const cap = Math.max(1, Math.floor(options.maxLifetimeMinutes));
|
|
92
|
+
const base = options.baseCloudConfig ? parseBase(options.baseCloudConfig) : {};
|
|
93
|
+
assertNoReservedWrite(base.write_files, "baseCloudConfig");
|
|
94
|
+
const baseWriteFiles = base.write_files ?? [];
|
|
95
|
+
const baseRuncmd = base.runcmd ?? [];
|
|
96
|
+
const basePackages = base.packages ?? [];
|
|
97
|
+
const envFile = {
|
|
98
|
+
path: AGENT_ENV_FILE,
|
|
99
|
+
permissions: "0600",
|
|
100
|
+
owner: "root:root",
|
|
101
|
+
content: renderEnvFileContent(creds, options.agentEnv)
|
|
102
|
+
};
|
|
103
|
+
const pkgs = dedupe([...basePackages, ...options.packages ?? []]);
|
|
104
|
+
const model = {
|
|
105
|
+
...base,
|
|
106
|
+
write_files: [
|
|
107
|
+
...baseWriteFiles,
|
|
108
|
+
envFile,
|
|
109
|
+
...options.writeFiles ?? []
|
|
110
|
+
],
|
|
111
|
+
runcmd: [
|
|
112
|
+
...baseRuncmd,
|
|
113
|
+
...options.runcmdBefore ?? [],
|
|
114
|
+
`systemd-run --on-active=${cap}m --timer-property=AccuracySec=1s /sbin/poweroff`,
|
|
115
|
+
renderStartCommand(options),
|
|
116
|
+
...options.runcmdAfter ?? []
|
|
117
|
+
]
|
|
118
|
+
};
|
|
119
|
+
if (pkgs.length > 0) model.packages = pkgs;
|
|
120
|
+
else delete model.packages;
|
|
121
|
+
const cloudConfig = `#cloud-config\n${stringify(model, { lineWidth: 0 })}`;
|
|
122
|
+
if (options.userDataEncoding === "base64") return Buffer.from(cloudConfig, "utf8").toString("base64");
|
|
123
|
+
return cloudConfig;
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { buildAgentCloudInit };
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=agent-cloud-init.js.map
|
package/dist/api-types.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* 2. Register the handler in the orchestrator's AgentApiRegistry
|
|
10
10
|
*/
|
|
11
11
|
import { type OidcTokenResult } from '@kici-dev/engine/protocol/messages/oidc-token-relay';
|
|
12
|
+
import type { GitApi } from './git-types.js';
|
|
12
13
|
import type { HostInventoryEntry, InventorySelector } from '@kici-dev/engine';
|
|
13
14
|
export type { OidcTokenResult };
|
|
14
15
|
export type { HostInventoryEntry, InventorySelector };
|
|
@@ -136,6 +137,27 @@ export interface BootstrapApi {
|
|
|
136
137
|
restaged: boolean;
|
|
137
138
|
}>;
|
|
138
139
|
}
|
|
140
|
+
/** Credentials a provisioning workflow uses to boot a scaler-provisioned agent. */
|
|
141
|
+
export interface ClaimedAgentCredentials {
|
|
142
|
+
/** Single-use ephemeral agent token the provisioned instance registers with. */
|
|
143
|
+
agentToken: string;
|
|
144
|
+
/** Agent id the instance must register with (chosen by the scaler). */
|
|
145
|
+
agentId: string;
|
|
146
|
+
/** Orchestrator WS URL the instance connects back to. */
|
|
147
|
+
orchestratorUrl: string;
|
|
148
|
+
/** Labels the token authorizes. */
|
|
149
|
+
labels: string[];
|
|
150
|
+
}
|
|
151
|
+
export interface ScalerApi {
|
|
152
|
+
/**
|
|
153
|
+
* Exchange a single-use claim code — delivered on a `kici.scaler.scale-up`
|
|
154
|
+
* event to a provisioning workflow — for freshly minted ephemeral agent
|
|
155
|
+
* credentials. Boot a cloud instance whose agent registers with the returned
|
|
156
|
+
* `agentId` and `agentToken`, and the pending bound job runs on it. The token
|
|
157
|
+
* is minted lazily on this call and never appears in the persisted event log.
|
|
158
|
+
*/
|
|
159
|
+
claimAgentCredentials(claimCode: string): Promise<ClaimedAgentCredentials>;
|
|
160
|
+
}
|
|
139
161
|
export interface KiciApi {
|
|
140
162
|
/** Query orchestrator infrastructure (scalers, agents). */
|
|
141
163
|
infrastructure: InfrastructureApi;
|
|
@@ -143,10 +165,14 @@ export interface KiciApi {
|
|
|
143
165
|
inventory: InventoryApi;
|
|
144
166
|
/** Request short-lived OIDC ID tokens for the current job (build provenance). */
|
|
145
167
|
oidc: OidcApi;
|
|
168
|
+
/** Forge-typed git credentials for the current job. */
|
|
169
|
+
git: GitApi;
|
|
146
170
|
/** Host-lifecycle operations on the agent's own host (e.g. reboot). */
|
|
147
171
|
host: HostApi;
|
|
148
172
|
/** Fresh-box bootstrap bring-up (init-runner over SSH, pre-boot unlock). */
|
|
149
173
|
bootstrap: BootstrapApi;
|
|
174
|
+
/** Event-scaler provisioning: claim ephemeral agent credentials. */
|
|
175
|
+
scaler: ScalerApi;
|
|
150
176
|
}
|
|
151
177
|
/**
|
|
152
178
|
* Low-level transport function used to implement KiciApi.
|
package/dist/api-types.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
2
|
import { OIDC_TOKEN_REQUEST_METHOD } from "@kici-dev/engine/protocol/messages/oidc-token-relay";
|
|
3
|
+
import { GIT_CREDENTIAL_REQUEST_METHOD } from "@kici-dev/engine/protocol/messages/git-credential-relay";
|
|
3
4
|
//#region src/api-types.ts
|
|
4
5
|
/**
|
|
5
6
|
* Typed KiCI API available to workflows via ctx.kici.
|
|
@@ -37,6 +38,23 @@ function buildKiciApi(transport, jobCtx) {
|
|
|
37
38
|
audience: opts.audience
|
|
38
39
|
});
|
|
39
40
|
} },
|
|
41
|
+
git: { github: { getToken: (opts) => {
|
|
42
|
+
if (!jobCtx) return Promise.reject(/* @__PURE__ */ new Error("ctx.kici.git.github.getToken() is only available inside a running job step"));
|
|
43
|
+
if (opts.repositories.length === 0) return Promise.reject(/* @__PURE__ */ new Error("git.github.getToken requires at least one repository"));
|
|
44
|
+
return transport(GIT_CREDENTIAL_REQUEST_METHOD, {
|
|
45
|
+
jobId: jobCtx.jobId,
|
|
46
|
+
repositories: opts.repositories,
|
|
47
|
+
permissions: opts.permissions,
|
|
48
|
+
...opts.credential ? { credential: opts.credential } : {}
|
|
49
|
+
}).then((raw) => {
|
|
50
|
+
const r = raw;
|
|
51
|
+
return {
|
|
52
|
+
token: r.secret,
|
|
53
|
+
expiresAt: r.expiresAt,
|
|
54
|
+
granted: r.grant
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
} } },
|
|
40
58
|
host: { requestReboot: (opts) => transport("host.requestReboot", { ...opts?.deadlineMs !== void 0 ? { deadlineMs: opts.deadlineMs } : {} }) },
|
|
41
59
|
bootstrap: {
|
|
42
60
|
ensureInitRunner: (targetAgentId) => transport("kici.ensureInitRunner", { targetAgentId }),
|
|
@@ -46,7 +64,8 @@ function buildKiciApi(transport, jobCtx) {
|
|
|
46
64
|
}),
|
|
47
65
|
agentVersionStatus: (targetAgentId) => transport("kici.agentVersionStatus", { targetAgentId }),
|
|
48
66
|
restageAgent: (targetAgentId) => transport("kici.restageAgent", { targetAgentId })
|
|
49
|
-
}
|
|
67
|
+
},
|
|
68
|
+
scaler: { claimAgentCredentials: (claimCode) => transport("scaler.claim-credentials", { claimCode }) }
|
|
50
69
|
};
|
|
51
70
|
}
|
|
52
71
|
//#endregion
|
package/dist/context.d.ts
CHANGED
|
@@ -189,6 +189,27 @@ export interface StepContext<TInputs = Record<string, unknown>> {
|
|
|
189
189
|
* Defaults to false for backward compatibility.
|
|
190
190
|
*/
|
|
191
191
|
isTestRun: boolean;
|
|
192
|
+
/**
|
|
193
|
+
* The job's own checked-out repository.
|
|
194
|
+
*
|
|
195
|
+
* Present for every job that checks out (unlike `sourceRepo` / `workflowRepo`,
|
|
196
|
+
* which exist only for a global workflow). `withWrite` opens a write window
|
|
197
|
+
* for THIS repository, bounded by the repository and by the callback's
|
|
198
|
+
* duration — not by the step: steps running concurrently in the same job can
|
|
199
|
+
* push to the same repository while it is open, but cannot reach a different
|
|
200
|
+
* one. It throws before any git runs when the forge will not grant what was
|
|
201
|
+
* requested.
|
|
202
|
+
*/
|
|
203
|
+
repo?: {
|
|
204
|
+
identifier: string;
|
|
205
|
+
path: string;
|
|
206
|
+
ref?: string;
|
|
207
|
+
sha?: string;
|
|
208
|
+
withWrite(opts: {
|
|
209
|
+
permissions?: Record<string, string>;
|
|
210
|
+
credential?: string;
|
|
211
|
+
}, fn: () => Promise<void>): Promise<void>;
|
|
212
|
+
};
|
|
192
213
|
/**
|
|
193
214
|
* Workflow repo metadata -- only set for global workflows.
|
|
194
215
|
* The registering repo where the workflow code is defined.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { workflow } from "./workflow.js";
|
|
3
|
+
import { job } from "./job.js";
|
|
4
|
+
import { step } from "./step.js";
|
|
5
|
+
import { describe, expectTypeOf, it } from "vitest";
|
|
6
|
+
//#region src/filter.test-d.ts
|
|
7
|
+
const noop = job("noop", {
|
|
8
|
+
runsOn: "linux",
|
|
9
|
+
steps: [step("x", { run: async () => {} })]
|
|
10
|
+
});
|
|
11
|
+
describe("workflow filter — type level", () => {
|
|
12
|
+
it("rejects a non-function filter", () => {
|
|
13
|
+
workflow("org-ci", {
|
|
14
|
+
jobs: [noop],
|
|
15
|
+
filter: "yes"
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
it("accepts a function filter", () => {
|
|
19
|
+
const filter = ({ sourceRepo }) => sourceRepo.identifier !== "a/b";
|
|
20
|
+
const wf = workflow("org-ci", {
|
|
21
|
+
jobs: [noop],
|
|
22
|
+
filter
|
|
23
|
+
});
|
|
24
|
+
expectTypeOf(wf.filter).toEqualTypeOf();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
//#endregion
|
|
28
|
+
export {};
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=filter.test-d.js.map
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forge-typed git surface for workflow authors.
|
|
3
|
+
*
|
|
4
|
+
* The forge is a TYPE PARAMETER and nothing more. It is erased at runtime:
|
|
5
|
+
* `kici.git.clone<'github'>()` against a Forgejo source compiles cleanly, the
|
|
6
|
+
* requested permissions are ignored, and the result reports
|
|
7
|
+
* `granted: { scoped: false }`. It buys autocomplete and a compile error on a
|
|
8
|
+
* wrong-shaped permission object; it buys no safety. The runtime `granted`
|
|
9
|
+
* value is the only source of truth about what a credential can do.
|
|
10
|
+
*/
|
|
11
|
+
/** Forges that can back a git credential. Mirrors the engine's `ForgeName`. */
|
|
12
|
+
export type ForgeName = 'github' | 'gitlab' | 'bitbucket' | 'generic';
|
|
13
|
+
/**
|
|
14
|
+
* GitHub repository permissions.
|
|
15
|
+
*
|
|
16
|
+
* DELIBERATE CARVE-OUT from the enums-over-hardcoded-strings rule: the known
|
|
17
|
+
* keys below are typed so editors autocomplete them, but an index signature
|
|
18
|
+
* lets an unknown key through. GitHub adds permissions over time, and a closed
|
|
19
|
+
* enum would mean a permission shipped yesterday needs an SDK release — and the
|
|
20
|
+
* SDK is compat-protected and rides the single-version release train. Unknown
|
|
21
|
+
* keys are passed to GitHub verbatim for it to accept or reject.
|
|
22
|
+
*/
|
|
23
|
+
export interface GitHubPermissions {
|
|
24
|
+
contents?: 'read' | 'write';
|
|
25
|
+
metadata?: 'read';
|
|
26
|
+
workflows?: 'write';
|
|
27
|
+
actions?: 'read' | 'write';
|
|
28
|
+
pull_requests?: 'read' | 'write';
|
|
29
|
+
issues?: 'read' | 'write';
|
|
30
|
+
checks?: 'read' | 'write';
|
|
31
|
+
statuses?: 'read' | 'write';
|
|
32
|
+
deployments?: 'read' | 'write';
|
|
33
|
+
packages?: 'read' | 'write';
|
|
34
|
+
[permission: string]: string | undefined;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for a write elevation, shaped by the forge.
|
|
38
|
+
*
|
|
39
|
+
* `WriteOptions<'generic'>` carries no permission fields at all: a static
|
|
40
|
+
* credential has nothing to request, because an SSH key or PAT is read-write or
|
|
41
|
+
* it is not.
|
|
42
|
+
*/
|
|
43
|
+
export type WriteOptions<F extends ForgeName = 'github'> = F extends 'github' ? {
|
|
44
|
+
permissions: GitHubPermissions;
|
|
45
|
+
} : Record<never, never>;
|
|
46
|
+
/** What a credential turned out to be able to do. Never an echo of the request. */
|
|
47
|
+
export type GitGrant = {
|
|
48
|
+
scoped: false;
|
|
49
|
+
} | {
|
|
50
|
+
scoped: true;
|
|
51
|
+
permissions: Record<string, string>;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* One half of a credential field pair. Exactly one form is set: a qualified
|
|
55
|
+
* `<context>:<secret-name>` reference resolved from the secrets backend, or
|
|
56
|
+
* material supplied at runtime.
|
|
57
|
+
*
|
|
58
|
+
* The field NAME is the discriminator, following the convention `workflow.ts`
|
|
59
|
+
* already sets with `registries[].tokenSecret` and `isQualifiedSecretRef`.
|
|
60
|
+
*/
|
|
61
|
+
export type Sourced<Name extends string> = {
|
|
62
|
+
[K in `${Name}Secret`]: string;
|
|
63
|
+
} | {
|
|
64
|
+
[K in `${Name}Value`]: string;
|
|
65
|
+
};
|
|
66
|
+
/** Where credential material comes from, for each supported credential shape. */
|
|
67
|
+
export type GitCredentialRef = ({
|
|
68
|
+
kind: 'app';
|
|
69
|
+
} & Sourced<'appId'> & Sourced<'installationId'> & Sourced<'privateKey'>) | ({
|
|
70
|
+
kind: 'token';
|
|
71
|
+
user?: string;
|
|
72
|
+
} & Sourced<'token'>) | ({
|
|
73
|
+
kind: 'ssh';
|
|
74
|
+
} & Sourced<'privateKey'>);
|
|
75
|
+
/** Named credentials for a job. `default` is used when a call names none. */
|
|
76
|
+
export type GitCredentialMap = Record<string, GitCredentialRef>;
|
|
77
|
+
/**
|
|
78
|
+
* Resolve a call site's credential.
|
|
79
|
+
*
|
|
80
|
+
* Order: an explicit per-call value wins; otherwise `default` from the job map;
|
|
81
|
+
* otherwise undefined, which means the source credential — all a read needs.
|
|
82
|
+
*
|
|
83
|
+
* An unknown name THROWS rather than falling back to `default`: silently using
|
|
84
|
+
* a different credential than the author named is precisely the confusion this
|
|
85
|
+
* map exists to remove.
|
|
86
|
+
*/
|
|
87
|
+
export declare function resolveCredential(perCall: string | GitCredentialRef | undefined, map: GitCredentialMap | undefined): GitCredentialRef | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Every credential field names a secret. Catch the easy, silent mistake of
|
|
90
|
+
* pasting the credential itself — which would commit it to a git repository.
|
|
91
|
+
*/
|
|
92
|
+
export declare function assertSecretName(value: string, field: string, subject?: string): void;
|
|
93
|
+
/**
|
|
94
|
+
* Private-registry credentials for pulling a job's container image.
|
|
95
|
+
*
|
|
96
|
+
* Built from `Sourced<Name>` so "this field names a secret" has ONE spelling
|
|
97
|
+
* across the SDK — the same one `gitCredentials` uses. `username` may be a
|
|
98
|
+
* plain string (a registry username is not a secret); the token may not be.
|
|
99
|
+
*/
|
|
100
|
+
export type ContainerRegistryAuth = Sourced<'token'> & {
|
|
101
|
+
/** Plain registry username. Mutually exclusive with `usernameSecret`. */
|
|
102
|
+
username?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Registry host these credentials belong to (e.g. `reg.internal:5000`).
|
|
105
|
+
*
|
|
106
|
+
* Optional with `container.image`, where it is derived from the image
|
|
107
|
+
* reference. REQUIRED with `container.dockerfile`: the base image is named
|
|
108
|
+
* inside the Dockerfile, so there is nothing to derive it from.
|
|
109
|
+
*/
|
|
110
|
+
registry?: string;
|
|
111
|
+
} & Partial<Sourced<'username'>>;
|
|
112
|
+
/** A checked-out repository. The forge travels with the handle. */
|
|
113
|
+
export interface RepoHandle<F extends ForgeName = 'github'> {
|
|
114
|
+
/** `owner/repo`. */
|
|
115
|
+
identifier: string;
|
|
116
|
+
/** Absolute path to the working tree. */
|
|
117
|
+
path: string;
|
|
118
|
+
ref?: string;
|
|
119
|
+
sha?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Run `fn` with write credentials for THIS repository.
|
|
122
|
+
*
|
|
123
|
+
* The grant is scoped to this repository and to the duration of `fn` — NOT to
|
|
124
|
+
* the calling step. The agent runs one process per job and `parallel()` runs
|
|
125
|
+
* its children inside it, so a concurrent sibling step can push to the same
|
|
126
|
+
* repository while the grant is live. It cannot reach a different repository.
|
|
127
|
+
*
|
|
128
|
+
* Throws at entry — before any git runs — when the forge grants less than was
|
|
129
|
+
* requested, naming the missing permission.
|
|
130
|
+
*/
|
|
131
|
+
withWrite(opts: WriteOptions<F>, fn: () => Promise<void>): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
/** Result of an explicit token request. */
|
|
134
|
+
export interface GitTokenResult {
|
|
135
|
+
token: string;
|
|
136
|
+
expiresAt: string | null;
|
|
137
|
+
granted: GitGrant;
|
|
138
|
+
}
|
|
139
|
+
/** Forge-specific minting. Only minted shapes appear here; static ones have nothing to mint. */
|
|
140
|
+
export interface GitHubApi {
|
|
141
|
+
/**
|
|
142
|
+
* Mint a token as a VALUE, for the forge API, the `gh` CLI, or a third-party
|
|
143
|
+
* tool. Auto-masked in step logs; job-bound; throws outside a running step.
|
|
144
|
+
*
|
|
145
|
+
* For git operations prefer `handle.withWrite()`, which never puts a token in
|
|
146
|
+
* the step environment. `gh` does not read git credential helpers, which is
|
|
147
|
+
* why this exists.
|
|
148
|
+
*/
|
|
149
|
+
getToken(opts: {
|
|
150
|
+
repositories: string[];
|
|
151
|
+
permissions: GitHubPermissions;
|
|
152
|
+
/**
|
|
153
|
+
* Name an entry in the job's `gitCredentials` map. Omit to use `default`;
|
|
154
|
+
* omit both and the source credential applies.
|
|
155
|
+
*/
|
|
156
|
+
credential?: string;
|
|
157
|
+
}): Promise<GitTokenResult>;
|
|
158
|
+
}
|
|
159
|
+
export interface GitApi {
|
|
160
|
+
github: GitHubApi;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=git-types.d.ts.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
//#region src/git-types.ts
|
|
3
|
+
/**
|
|
4
|
+
* Resolve a call site's credential.
|
|
5
|
+
*
|
|
6
|
+
* Order: an explicit per-call value wins; otherwise `default` from the job map;
|
|
7
|
+
* otherwise undefined, which means the source credential — all a read needs.
|
|
8
|
+
*
|
|
9
|
+
* An unknown name THROWS rather than falling back to `default`: silently using
|
|
10
|
+
* a different credential than the author named is precisely the confusion this
|
|
11
|
+
* map exists to remove.
|
|
12
|
+
*/
|
|
13
|
+
function resolveCredential(perCall, map) {
|
|
14
|
+
if (perCall && typeof perCall === "object") return perCall;
|
|
15
|
+
if (typeof perCall === "string") {
|
|
16
|
+
const found = map?.[perCall];
|
|
17
|
+
if (!found) throw new Error(`Unknown git credential '${perCall}'. Declare it in the job's gitCredentials map. Known: ${Object.keys(map ?? {}).join(", ") || "(none)"}`);
|
|
18
|
+
return found;
|
|
19
|
+
}
|
|
20
|
+
return map?.default;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Every credential field names a secret. Catch the easy, silent mistake of
|
|
24
|
+
* pasting the credential itself — which would commit it to a git repository.
|
|
25
|
+
*/
|
|
26
|
+
function assertSecretName(value, field, subject = "git credential") {
|
|
27
|
+
if (value.startsWith("-----BEGIN") || /^gh[pousr]_/.test(value) || value.startsWith("github_pat_")) throw new Error(`${subject} '${field}' looks like the credential itself, not the name of a secret holding it. Store it with \`kici-admin secret set\` and name it here.`);
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { assertSecretName, resolveCredential };
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=git-types.js.map
|
package/dist/idempotent.js
CHANGED
|
@@ -83,7 +83,7 @@ function idempotentStep(name, opts) {
|
|
|
83
83
|
* lockfile change.
|
|
84
84
|
*/
|
|
85
85
|
function checkStep(name, options) {
|
|
86
|
-
|
|
86
|
+
const checkOptions = {
|
|
87
87
|
check: options.check,
|
|
88
88
|
summarize: options.summarize,
|
|
89
89
|
run: (ctx, drift) => options.apply(ctx, drift),
|
|
@@ -94,7 +94,8 @@ function checkStep(name, options) {
|
|
|
94
94
|
...options.retry !== void 0 && { retry: options.retry },
|
|
95
95
|
...options.cache !== void 0 && { cache: options.cache },
|
|
96
96
|
...options.rules !== void 0 && { rules: options.rules }
|
|
97
|
-
}
|
|
97
|
+
};
|
|
98
|
+
return step(name, checkOptions);
|
|
98
99
|
}
|
|
99
100
|
//#endregion
|
|
100
101
|
export { checkStep, idempotent, idempotentStep };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export { job } from './job.js';
|
|
|
3
3
|
export { workflow } from './workflow.js';
|
|
4
4
|
export { parallel, isParallelGroup, flattenStepInputs } from './parallel.js';
|
|
5
5
|
export type { ParallelGroup, ParallelOptions } from './parallel.js';
|
|
6
|
+
export { invokeSource } from './invoke.js';
|
|
7
|
+
export type { InvokeConfig } from './invoke.js';
|
|
6
8
|
export { normalizeApproval } from './approval.js';
|
|
7
9
|
export type { ApprovalConfig, ApprovalWhen, ApproverClause, NormalizedApproval, } from './approval.js';
|
|
8
10
|
export { pr, push, tag, comment, review, reviewComment, release, dispatch, create, delete as delete, status, workflowRun, fork, star, watch, webhook, kiciEvent, workflowComplete, workflowsFailedBatch, jobComplete, genericWebhook, schedule, lifecycle, defineDispatchInputs, } from './triggers/index.js';
|
|
@@ -21,7 +23,7 @@ export type { SourceLocation, OutputProxy, Step, StepOptions, StepOptionsBase, S
|
|
|
21
23
|
export { isDynamicJobFn, dynamicJob, getDynamicJobGroup, getDynamicJobNeeds, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, } from './types.js';
|
|
22
24
|
export type { TaggedDynamicJobFn, ResultAwareDynamicJobConfig, ResultAwareDynamicJobFn, DynamicJobNeed, NeedsWhen, NeedsWhenInput, } from './types.js';
|
|
23
25
|
export { buildNeedsContext } from './needs-context.js';
|
|
24
|
-
export type { UpstreamSnapshot, NeedsContext, NeedEntry, GroupNeedEntry } from './needs-context.js';
|
|
26
|
+
export type { UpstreamSnapshot, NeedsContext, NeedEntry, GroupNeedEntry, InvokeNeedEntry, InvokeResult, } from './needs-context.js';
|
|
25
27
|
export { CacheSpecSchema, normalizeCacheSpecs } from './cache-types.js';
|
|
26
28
|
export type { CacheSpec, CacheInput } from './cache-types.js';
|
|
27
29
|
export type { CacheRestoreResult, CacheApi } from './cache-types.js';
|
|
@@ -61,4 +63,9 @@ export type { WaitForHostAliveOptions, RestartHostOptions } from './host-restart
|
|
|
61
63
|
export { agentVersionConverge } from './fleet/agent-version-converge.js';
|
|
62
64
|
export type { AgentVersionConvergeOptions, AgentVersionDrift, } from './fleet/agent-version-converge.js';
|
|
63
65
|
export { z } from 'zod';
|
|
66
|
+
export { SCALER_EVENT_NAMES, ScaleDownReason, ScalerScaleUpPayload, ScalerScaleDownPayload, } from '@kici-dev/engine';
|
|
67
|
+
export { buildAgentCloudInit } from './agent-cloud-init.js';
|
|
68
|
+
export type { CloudInitCredentials, ClaimCodeCredentials, AgentCloudInitCredentials, AgentDeliveryMode, UserDataEncoding, CloudInitWriteFile, AgentCloudInitOptions, } from './agent-cloud-init.js';
|
|
69
|
+
export { assertSecretName } from './git-types.js';
|
|
70
|
+
export type { ForgeName, GitHubPermissions, WriteOptions, GitGrant, Sourced, ContainerRegistryAuth, GitCredentialRef, GitCredentialMap, RepoHandle, GitTokenResult, GitHubApi, GitApi, } from './git-types.js';
|
|
64
71
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import "./rolldown-runtime-ClRpJifh.js";
|
|
2
|
+
import { buildAgentCloudInit } from "./agent-cloud-init.js";
|
|
2
3
|
import { buildKiciApi } from "./api-types.js";
|
|
3
4
|
import { normalizeApproval } from "./approval.js";
|
|
4
5
|
import { ARTIFACT_NAME_MAX_LENGTH, ArtifactNameSchema } from "./artifacts-types.js";
|
|
@@ -8,15 +9,17 @@ import { DYNAMIC_GROUP_TAG, dynamicGroup, isDynamicGroupRef } from "./dynamic-gr
|
|
|
8
9
|
import { SecretNotFoundError } from "./errors.js";
|
|
9
10
|
import { ChangedFilesUnavailableError } from "./rules/changed-files.js";
|
|
10
11
|
import { createFilterContext } from "./filter-context.js";
|
|
11
|
-
import {
|
|
12
|
+
import { workflow } from "./workflow.js";
|
|
12
13
|
import { createJobOutputProxy, createSnapshotOutputProxy, createStepOutputProxy, getJobOutputsMap, getStepOutputsMap, getStepRefMap, resolveJobOutputs, resolveStepOutputs, setJobOutputsMap, setStepOutputsMap, setStepRefMap } from "./outputs.js";
|
|
14
|
+
import { assertSecretName } from "./git-types.js";
|
|
15
|
+
import { job } from "./job.js";
|
|
13
16
|
import { step } from "./step.js";
|
|
17
|
+
import { fixture } from "./fixture.js";
|
|
14
18
|
import { WaitForTimeoutError, waitFor, waitForStep } from "./wait-for.js";
|
|
15
19
|
import { restartHost, waitForHostAlive } from "./host-restart.js";
|
|
16
20
|
import { checkStep, idempotent, idempotentStep } from "./idempotent.js";
|
|
17
|
-
import { job } from "./job.js";
|
|
18
|
-
import { workflow } from "./workflow.js";
|
|
19
21
|
import { flattenStepInputs, isParallelGroup, parallel } from "./parallel.js";
|
|
22
|
+
import { invokeSource } from "./invoke.js";
|
|
20
23
|
import { pr } from "./triggers/pr.js";
|
|
21
24
|
import { push } from "./triggers/push.js";
|
|
22
25
|
import { tag } from "./triggers/tag.js";
|
|
@@ -60,5 +63,6 @@ import "./matrix/index.js";
|
|
|
60
63
|
import { defineEvent, isEventDefinition } from "./events/define-event.js";
|
|
61
64
|
import "./events/index.js";
|
|
62
65
|
import { agentVersionConverge } from "./fleet/agent-version-converge.js";
|
|
66
|
+
import { SCALER_EVENT_NAMES, ScaleDownReason, ScalerScaleDownPayload, ScalerScaleUpPayload } from "@kici-dev/engine";
|
|
63
67
|
import { z } from "zod";
|
|
64
|
-
export { ARTIFACT_NAME_MAX_LENGTH, ArtifactNameSchema, CacheSpecSchema, ChangedFilesUnavailableError, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, SecretNotFoundError, WaitForTimeoutError, afterStep, agentVersionConverge, applyIncludeExclude, beforeStep, buildKiciApi, buildNeedsContext, checkStep, cleanup, comment, create, createFilterContext, createJobOutputProxy, createRuleContext, createSnapshotOutputProxy, createStepOutputProxy, createStepSecrets, defineDispatchInputs, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, flattenStepInputs, fork, genericWebhook, getDynamicJobGroup, getDynamicJobNeeds, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventDefinition, isEventType, isHostJobOutputs, isMatrixJobOutputs, isParallelGroup, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, normalizeApproval, normalizeCacheSpecs, onCancel, onFailure, onSuccess, onlyOnFanoutIndex, onlyOnFirstHost, onlyOnLastHost, parallel, pr, provenanceSubjectIsPath, push, release, resolveJobOutputs, resolveStepOutputs, restartHost, review, reviewComment, rule, schedule, setJobOutputsMap, setStepOutputsMap, setStepRefMap, skip, star, status, step, tag, validateDag, waitFor, waitForHostAlive, waitForStep, watch, webhook, workflow, workflowComplete, workflowRun, workflowsFailedBatch, z };
|
|
68
|
+
export { ARTIFACT_NAME_MAX_LENGTH, ArtifactNameSchema, CacheSpecSchema, ChangedFilesUnavailableError, DYNAMIC_GROUP_TAG, DYNAMIC_JOB_GROUP_TAG, DYNAMIC_JOB_NEEDS_TAG, SCALER_EVENT_NAMES, ScaleDownReason, ScalerScaleDownPayload, ScalerScaleUpPayload, SecretNotFoundError, WaitForTimeoutError, afterStep, agentVersionConverge, applyIncludeExclude, assertSecretName, beforeStep, buildAgentCloudInit, buildKiciApi, buildNeedsContext, checkStep, cleanup, comment, create, createFilterContext, createJobOutputProxy, createRuleContext, createSnapshotOutputProxy, createStepOutputProxy, createStepSecrets, defineDispatchInputs, defineEvent, del as delete, dispatch, dynamicGroup, dynamicJob, evaluateRules, expandMatrix, fixture, flattenStepInputs, fork, genericWebhook, getDynamicJobGroup, getDynamicJobNeeds, getJobOutputsMap, getStepOutputsMap, getStepRefMap, idempotent, idempotentStep, invokeSource, isDynamicFunction, isDynamicGroupRef, isDynamicJobFn, isEventDefinition, isEventType, isHostJobOutputs, isMatrixJobOutputs, isParallelGroup, isStaticArray, isStaticObject, job, jobComplete, kiciEvent, lifecycle, normalizeApproval, normalizeCacheSpecs, onCancel, onFailure, onSuccess, onlyOnFanoutIndex, onlyOnFirstHost, onlyOnLastHost, parallel, pr, provenanceSubjectIsPath, push, release, resolveJobOutputs, resolveStepOutputs, restartHost, review, reviewComment, rule, schedule, setJobOutputsMap, setStepOutputsMap, setStepRefMap, skip, star, status, step, tag, validateDag, waitFor, waitForHostAlive, waitForStep, watch, webhook, workflow, workflowComplete, workflowRun, workflowsFailedBatch, z };
|
package/dist/invoke.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Config produced by {@link invokeSource}: emit a kici event at the source repo and gate on the runs it triggers. */
|
|
2
|
+
export interface InvokeConfig {
|
|
3
|
+
readonly _tag: 'InvokeSource';
|
|
4
|
+
/** The kici event name to emit. Subscribers opt in with `kiciEvent({ name })`. */
|
|
5
|
+
readonly event: string;
|
|
6
|
+
/** Target scope. `'source'` targets exactly `ctx.sourceRepo` (the only v1 scope). */
|
|
7
|
+
readonly scope: 'source';
|
|
8
|
+
/** Optional event payload delivered to subscribers. */
|
|
9
|
+
readonly payload?: Readonly<Record<string, unknown>>;
|
|
10
|
+
/**
|
|
11
|
+
* When true, a zero-subscriber emit succeeds immediately (the repo may opt out).
|
|
12
|
+
* When false/unset (the default), a zero-subscriber emit FAILS the gate — a repo
|
|
13
|
+
* that never wired up its tests must not silently pass the org gate.
|
|
14
|
+
*/
|
|
15
|
+
readonly optional?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Invoke the source repo's opt-in workflows and gate on them.
|
|
19
|
+
*
|
|
20
|
+
* Targets exactly `ctx.sourceRepo`, so a global workflow can hand control back to
|
|
21
|
+
* the repo whose event triggered it without any org-wide fan-out. Subscribers opt
|
|
22
|
+
* in with `kiciEvent({ name })`. Required by default: if no workflow subscribes,
|
|
23
|
+
* the gate fails unless `optional: true` is set.
|
|
24
|
+
*/
|
|
25
|
+
export declare function invokeSource(event: string, opts?: {
|
|
26
|
+
payload?: Record<string, unknown>;
|
|
27
|
+
optional?: boolean;
|
|
28
|
+
}): InvokeConfig;
|
|
29
|
+
//# sourceMappingURL=invoke.d.ts.map
|