@sst-community/sst 0.0.0-placeholder.0 → 4.17.2
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 +86 -0
- package/bin/sst.mjs +33 -0
- package/dist/auth/adapter/adapter.d.ts +23 -0
- package/dist/auth/adapter/adapter.js +4 -0
- package/dist/auth/adapter/apple.d.ts +5 -0
- package/dist/auth/adapter/apple.js +22 -0
- package/dist/auth/adapter/code.d.ts +7 -0
- package/dist/auth/adapter/code.js +47 -0
- package/dist/auth/adapter/facebook.d.ts +5 -0
- package/dist/auth/adapter/facebook.js +27 -0
- package/dist/auth/adapter/github.d.ts +7 -0
- package/dist/auth/adapter/github.js +15 -0
- package/dist/auth/adapter/google.d.ts +17 -0
- package/dist/auth/adapter/google.js +22 -0
- package/dist/auth/adapter/index.d.ts +11 -0
- package/dist/auth/adapter/index.js +10 -0
- package/dist/auth/adapter/link.d.ts +5 -0
- package/dist/auth/adapter/link.js +27 -0
- package/dist/auth/adapter/microsoft.d.ts +11 -0
- package/dist/auth/adapter/microsoft.js +16 -0
- package/dist/auth/adapter/oauth.d.ts +33 -0
- package/dist/auth/adapter/oauth.js +82 -0
- package/dist/auth/adapter/oidc.d.ts +19 -0
- package/dist/auth/adapter/oidc.js +48 -0
- package/dist/auth/adapter/spotify.d.ts +12 -0
- package/dist/auth/adapter/spotify.js +22 -0
- package/dist/auth/example/bun.d.ts +2 -0
- package/dist/auth/example/bun.js +46 -0
- package/dist/auth/handler.d.ts +57 -0
- package/dist/auth/handler.js +206 -0
- package/dist/auth/index.d.ts +10 -0
- package/dist/auth/index.js +10 -0
- package/dist/auth/session.d.ts +25 -0
- package/dist/auth/session.js +28 -0
- package/dist/aws/auth.d.ts +9 -0
- package/dist/aws/auth.js +12 -0
- package/dist/aws/bus.d.ts +28 -0
- package/dist/aws/bus.js +66 -0
- package/dist/aws/client.d.ts +8 -0
- package/dist/aws/client.js +54 -0
- package/dist/aws/realtime.d.ts +118 -0
- package/dist/aws/realtime.js +83 -0
- package/dist/aws/task.d.ts +228 -0
- package/dist/aws/task.js +232 -0
- package/dist/aws/workflow.d.ts +324 -0
- package/dist/aws/workflow.js +504 -0
- package/dist/event/index.d.ts +72 -0
- package/dist/event/index.js +35 -0
- package/dist/event/validator.d.ts +4 -0
- package/dist/event/validator.js +11 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +17 -0
- package/dist/realtime/index.d.ts +25 -0
- package/dist/realtime/index.js +24 -0
- package/dist/resource/cloudflare.d.ts +5 -0
- package/dist/resource/cloudflare.js +30 -0
- package/dist/resource/index.d.ts +1 -0
- package/dist/resource/index.js +1 -0
- package/dist/resource/node.d.ts +4 -0
- package/dist/resource/node.js +38 -0
- package/dist/resource/shared.d.ts +9 -0
- package/dist/resource/shared.js +62 -0
- package/dist/resource.d.ts +1 -0
- package/dist/resource.js +1 -0
- package/dist/util/prettify.d.ts +3 -0
- package/dist/util/prettify.js +1 -0
- package/dist/vector/index.d.ts +247 -0
- package/dist/vector/index.js +107 -0
- package/package.json +73 -1
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
import * as durable from "@aws/durable-execution-sdk-js";
|
|
2
|
+
import { awsFetch } from "./client.js";
|
|
3
|
+
/**
|
|
4
|
+
* The `workflow` SDK is a thin wrapper around the
|
|
5
|
+
* [`@aws/durable-execution-sdk-js`](https://www.npmjs.com/package/@aws/durable-execution-sdk-js)
|
|
6
|
+
* package and the AWS Lambda durable execution APIs.
|
|
7
|
+
*
|
|
8
|
+
* SST also adds a few helpers on top, including `ctx.stepWithRollback()`,
|
|
9
|
+
* `ctx.rollbackAll()`, and `ctx.waitUntil()`.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts title="src/workflow.ts"
|
|
13
|
+
* import { workflow } from "sst/aws/workflow";
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* Use `stepWithRollback()` and `rollbackAll()` to register compensating actions.
|
|
18
|
+
*
|
|
19
|
+
* ```ts title="src/workflow.ts"
|
|
20
|
+
* import { workflow } from "sst/aws/workflow";
|
|
21
|
+
*
|
|
22
|
+
* export const handler = workflow.handler(async (_event, ctx) => {
|
|
23
|
+
* try {
|
|
24
|
+
* const order = await ctx.stepWithRollback("create-order", {
|
|
25
|
+
* run: async () => ({ orderId: "order_123" }),
|
|
26
|
+
* undo: async (error, result) => {
|
|
27
|
+
* await fetch(`https://example.com/orders/${result.orderId}`, {
|
|
28
|
+
* method: "DELETE",
|
|
29
|
+
* });
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* await ctx.step("charge-card", async () => {
|
|
34
|
+
* throw new Error("Card declined");
|
|
35
|
+
* });
|
|
36
|
+
*
|
|
37
|
+
* return order;
|
|
38
|
+
* } catch (error) {
|
|
39
|
+
* await ctx.rollbackAll(error);
|
|
40
|
+
* throw error;
|
|
41
|
+
* }
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* Use `waitUntil()` when you already know the exact time the workflow should resume.
|
|
47
|
+
*
|
|
48
|
+
* ```ts title="src/workflow.ts"
|
|
49
|
+
* import { workflow } from "sst/aws/workflow";
|
|
50
|
+
*
|
|
51
|
+
* export const handler = workflow.handler(
|
|
52
|
+
* async (_event, ctx) => {
|
|
53
|
+
* const resumeAt = new Date();
|
|
54
|
+
* resumeAt.setMinutes(resumeAt.getMinutes() + 10);
|
|
55
|
+
*
|
|
56
|
+
* await ctx.waitUntil("wait-for-follow-up", resumeAt);
|
|
57
|
+
*
|
|
58
|
+
* return ctx.step("send-follow-up", async () => {
|
|
59
|
+
* return { delivered: true };
|
|
60
|
+
* });
|
|
61
|
+
* },
|
|
62
|
+
* );
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export var workflow;
|
|
66
|
+
(function (workflow) {
|
|
67
|
+
/**
|
|
68
|
+
* Create a durable workflow handler.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts title="src/workflow.ts"
|
|
72
|
+
* import { workflow } from "sst/aws/workflow";
|
|
73
|
+
*
|
|
74
|
+
* export const handler = workflow.handler(
|
|
75
|
+
* async (_event, ctx) => {
|
|
76
|
+
* const user = await ctx.step("load-user", async () => {
|
|
77
|
+
* return { id: "user_123", email: "alice@example.com" };
|
|
78
|
+
* });
|
|
79
|
+
*
|
|
80
|
+
* await ctx.wait("pause-before-email", "1 minute");
|
|
81
|
+
*
|
|
82
|
+
* return ctx.step("send-email", async () => {
|
|
83
|
+
* return { sent: true, userId: user.id };
|
|
84
|
+
* });
|
|
85
|
+
* },
|
|
86
|
+
* );
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
function handler(input, config) {
|
|
90
|
+
return durable.withDurableExecution((event, context) => input(event, withRollback(context)), config);
|
|
91
|
+
}
|
|
92
|
+
workflow.handler = handler;
|
|
93
|
+
/**
|
|
94
|
+
* Start a new workflow execution.
|
|
95
|
+
*
|
|
96
|
+
* This is the equivalent to calling
|
|
97
|
+
* [`Invoke`](https://docs.aws.amazon.com/lambda/latest/api/API_Invoke.html)
|
|
98
|
+
* for a durable Lambda function, using the durable invocation flow described in
|
|
99
|
+
* [Invoking durable Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-invoking.html).
|
|
100
|
+
*/
|
|
101
|
+
async function start(resource, input, options) {
|
|
102
|
+
const query = new URLSearchParams({
|
|
103
|
+
Qualifier: resource.qualifier,
|
|
104
|
+
});
|
|
105
|
+
const response = await awsFetch("lambda", `/2015-03-31/functions/${encodeURIComponent(resource.name)}/invocations?${query.toString()}`, {
|
|
106
|
+
method: "POST",
|
|
107
|
+
headers: {
|
|
108
|
+
"Content-Type": "application/json",
|
|
109
|
+
"X-Amz-Durable-Execution-Name": input.name,
|
|
110
|
+
"X-Amz-Invocation-Type": "Event",
|
|
111
|
+
},
|
|
112
|
+
body: input.payload === undefined
|
|
113
|
+
? undefined
|
|
114
|
+
: JSON.stringify(input.payload),
|
|
115
|
+
}, options);
|
|
116
|
+
if (!response.ok)
|
|
117
|
+
throw new StartError(response);
|
|
118
|
+
return {
|
|
119
|
+
arn: response.headers.get("X-Amz-Durable-Execution-Arn") ?? undefined,
|
|
120
|
+
statusCode: response.status,
|
|
121
|
+
version: response.headers.get("X-Amz-Executed-Version") ?? undefined,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
workflow.start = start;
|
|
125
|
+
/**
|
|
126
|
+
* List workflow executions.
|
|
127
|
+
*
|
|
128
|
+
* The SDK returns only the first page of results.
|
|
129
|
+
*/
|
|
130
|
+
async function list(resource, query, options) {
|
|
131
|
+
const startedAfter = query.createdAt?.from?.toISOString();
|
|
132
|
+
const startedBefore = query.createdAt?.to?.toISOString();
|
|
133
|
+
const direction = query.createdAt?.order ?? "asc";
|
|
134
|
+
const status = query.status;
|
|
135
|
+
if (startedAfter && startedBefore && startedAfter > startedBefore) {
|
|
136
|
+
throw new TypeError("workflow.list createdAt.from must be before createdAt.to");
|
|
137
|
+
}
|
|
138
|
+
if (direction !== "asc" && direction !== "desc") {
|
|
139
|
+
throw new TypeError(`Unsupported workflow order direction '${direction}'`);
|
|
140
|
+
}
|
|
141
|
+
const params = new URLSearchParams({
|
|
142
|
+
MaxItems: String(workflowListPageSize),
|
|
143
|
+
Qualifier: resource.qualifier,
|
|
144
|
+
});
|
|
145
|
+
if (Array.isArray(status)) {
|
|
146
|
+
throw new TypeError("workflow.list status must be a single status");
|
|
147
|
+
}
|
|
148
|
+
if (status)
|
|
149
|
+
params.append("Statuses", status);
|
|
150
|
+
if (startedAfter)
|
|
151
|
+
params.set("StartedAfter", startedAfter);
|
|
152
|
+
if (startedBefore)
|
|
153
|
+
params.set("StartedBefore", startedBefore);
|
|
154
|
+
if (direction === "desc")
|
|
155
|
+
params.set("ReverseOrder", "true");
|
|
156
|
+
const response = await awsFetch("lambda", `/2025-12-01/functions/${encodeURIComponent(resource.name)}/durable-executions?${params.toString()}`, {
|
|
157
|
+
method: "GET",
|
|
158
|
+
}, options);
|
|
159
|
+
if (!response.ok)
|
|
160
|
+
throw new ListError(response);
|
|
161
|
+
const data = (await response.json());
|
|
162
|
+
const executions = Array.isArray(data.DurableExecutions)
|
|
163
|
+
? data.DurableExecutions
|
|
164
|
+
: [];
|
|
165
|
+
return {
|
|
166
|
+
executions: executions.map(parseExecution),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
workflow.list = list;
|
|
170
|
+
/**
|
|
171
|
+
* Get the details for a single workflow execution.
|
|
172
|
+
*/
|
|
173
|
+
async function describe(arn, options) {
|
|
174
|
+
const response = await awsFetch("lambda", `/2025-12-01/durable-executions/${encodeURIComponent(arn)}`, {
|
|
175
|
+
method: "GET",
|
|
176
|
+
}, options);
|
|
177
|
+
if (!response.ok)
|
|
178
|
+
throw new DescribeError(response);
|
|
179
|
+
const data = (await response.json());
|
|
180
|
+
if (!data.DurableExecutionArn ||
|
|
181
|
+
!data.DurableExecutionName ||
|
|
182
|
+
!data.FunctionArn ||
|
|
183
|
+
data.StartTimestamp === undefined ||
|
|
184
|
+
data.Status === undefined) {
|
|
185
|
+
throw new DescribeError(response);
|
|
186
|
+
}
|
|
187
|
+
const execution = parseExecution(data);
|
|
188
|
+
return {
|
|
189
|
+
...execution,
|
|
190
|
+
version: data.Version,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
workflow.describe = describe;
|
|
194
|
+
/**
|
|
195
|
+
* Stop a running workflow execution.
|
|
196
|
+
*/
|
|
197
|
+
async function stop(arn, input, options) {
|
|
198
|
+
const response = await awsFetch("lambda", `/2025-12-01/durable-executions/${encodeURIComponent(arn)}/stop`, {
|
|
199
|
+
method: "POST",
|
|
200
|
+
headers: input?.error
|
|
201
|
+
? {
|
|
202
|
+
"Content-Type": "application/json",
|
|
203
|
+
}
|
|
204
|
+
: undefined,
|
|
205
|
+
body: input?.error === undefined
|
|
206
|
+
? undefined
|
|
207
|
+
: JSON.stringify(normalizeError(input.error)),
|
|
208
|
+
}, options);
|
|
209
|
+
if (!response.ok)
|
|
210
|
+
throw new StopError(response);
|
|
211
|
+
const data = (await response.json());
|
|
212
|
+
return {
|
|
213
|
+
arn,
|
|
214
|
+
status: "STOPPED",
|
|
215
|
+
stoppedAt: data.StopTimestamp === undefined
|
|
216
|
+
? undefined
|
|
217
|
+
: parseTimestamp(data.StopTimestamp),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
workflow.stop = stop;
|
|
221
|
+
/**
|
|
222
|
+
* Send a successful result for a pending workflow callback.
|
|
223
|
+
*
|
|
224
|
+
* This is the equivalent to calling
|
|
225
|
+
* [`SendDurableExecutionCallbackSuccess`](https://docs.aws.amazon.com/lambda/latest/api/API_SendDurableExecutionCallbackSuccess.html).
|
|
226
|
+
*/
|
|
227
|
+
async function succeed(token, input = {}, options) {
|
|
228
|
+
const response = await awsFetch("lambda", `/2025-12-01/durable-execution-callbacks/${encodeURIComponent(token)}/succeed`, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: {
|
|
231
|
+
"Content-Type": "application/json",
|
|
232
|
+
},
|
|
233
|
+
body: input.payload === undefined
|
|
234
|
+
? undefined
|
|
235
|
+
: JSON.stringify(input.payload),
|
|
236
|
+
}, options);
|
|
237
|
+
if (!response.ok)
|
|
238
|
+
throw new SucceedError(response);
|
|
239
|
+
}
|
|
240
|
+
workflow.succeed = succeed;
|
|
241
|
+
/**
|
|
242
|
+
* Send a failure result for a pending workflow callback.
|
|
243
|
+
*
|
|
244
|
+
* This is the equivalent to calling
|
|
245
|
+
* [`SendDurableExecutionCallbackFailure`](https://docs.aws.amazon.com/lambda/latest/api/API_SendDurableExecutionCallbackFailure.html).
|
|
246
|
+
*/
|
|
247
|
+
async function fail(token, input, options) {
|
|
248
|
+
const response = await awsFetch("lambda", `/2025-12-01/durable-execution-callbacks/${encodeURIComponent(token)}/fail`, {
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: {
|
|
251
|
+
"Content-Type": "application/json",
|
|
252
|
+
},
|
|
253
|
+
body: JSON.stringify(normalizeError(input.error)),
|
|
254
|
+
}, options);
|
|
255
|
+
if (!response.ok)
|
|
256
|
+
throw new FailError(response);
|
|
257
|
+
}
|
|
258
|
+
workflow.fail = fail;
|
|
259
|
+
/**
|
|
260
|
+
* Send a heartbeat for a pending workflow callback.
|
|
261
|
+
*
|
|
262
|
+
* This is useful when the external system handling the callback is still doing
|
|
263
|
+
* work and needs to prevent the callback from timing out.
|
|
264
|
+
*
|
|
265
|
+
* This is the equivalent to calling
|
|
266
|
+
* [`SendDurableExecutionCallbackHeartbeat`](https://docs.aws.amazon.com/lambda/latest/api/API_SendDurableExecutionCallbackHeartbeat.html).
|
|
267
|
+
*/
|
|
268
|
+
async function heartbeat(token, options) {
|
|
269
|
+
const response = await awsFetch("lambda", `/2025-12-01/durable-execution-callbacks/${encodeURIComponent(token)}/heartbeat`, {
|
|
270
|
+
method: "POST",
|
|
271
|
+
}, options);
|
|
272
|
+
if (!response.ok)
|
|
273
|
+
throw new HeartbeatError(response);
|
|
274
|
+
}
|
|
275
|
+
workflow.heartbeat = heartbeat;
|
|
276
|
+
class StartError extends Error {
|
|
277
|
+
response;
|
|
278
|
+
constructor(response) {
|
|
279
|
+
super("Failed to start workflow");
|
|
280
|
+
this.response = response;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
workflow.StartError = StartError;
|
|
284
|
+
class ListError extends Error {
|
|
285
|
+
response;
|
|
286
|
+
constructor(response) {
|
|
287
|
+
super("Failed to list workflows");
|
|
288
|
+
this.response = response;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
workflow.ListError = ListError;
|
|
292
|
+
class DescribeError extends Error {
|
|
293
|
+
response;
|
|
294
|
+
constructor(response) {
|
|
295
|
+
super("Failed to describe workflow");
|
|
296
|
+
this.response = response;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
workflow.DescribeError = DescribeError;
|
|
300
|
+
class StopError extends Error {
|
|
301
|
+
response;
|
|
302
|
+
constructor(response) {
|
|
303
|
+
super("Failed to stop workflow");
|
|
304
|
+
this.response = response;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
workflow.StopError = StopError;
|
|
308
|
+
class SucceedError extends Error {
|
|
309
|
+
response;
|
|
310
|
+
constructor(response) {
|
|
311
|
+
super("Failed to succeed workflow callback");
|
|
312
|
+
this.response = response;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
workflow.SucceedError = SucceedError;
|
|
316
|
+
class FailError extends Error {
|
|
317
|
+
response;
|
|
318
|
+
constructor(response) {
|
|
319
|
+
super("Failed to fail workflow callback");
|
|
320
|
+
this.response = response;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
workflow.FailError = FailError;
|
|
324
|
+
class HeartbeatError extends Error {
|
|
325
|
+
response;
|
|
326
|
+
constructor(response) {
|
|
327
|
+
super("Failed to heartbeat workflow callback");
|
|
328
|
+
this.response = response;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
workflow.HeartbeatError = HeartbeatError;
|
|
332
|
+
class RollbackError extends Error {
|
|
333
|
+
stepName;
|
|
334
|
+
originalError;
|
|
335
|
+
undoError;
|
|
336
|
+
constructor(stepName, originalError, undoError) {
|
|
337
|
+
super(`Failed to rollback workflow step '${stepName}': ${undoError instanceof Error ? undoError.message : String(undoError)}`);
|
|
338
|
+
this.stepName = stepName;
|
|
339
|
+
this.originalError = originalError;
|
|
340
|
+
this.undoError = undoError;
|
|
341
|
+
this.name = "RollbackError";
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
workflow.RollbackError = RollbackError;
|
|
345
|
+
})(workflow || (workflow = {}));
|
|
346
|
+
const workflowListPageSize = 1000;
|
|
347
|
+
const rollbackStateSymbol = Symbol("sst.workflow.rollback.state");
|
|
348
|
+
function normalizeError(error) {
|
|
349
|
+
function serializeErrorData(input) {
|
|
350
|
+
if (input === undefined)
|
|
351
|
+
return undefined;
|
|
352
|
+
if (typeof input === "string")
|
|
353
|
+
return input;
|
|
354
|
+
try {
|
|
355
|
+
return JSON.stringify(input);
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
return String(input);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function normalizeStack(input) {
|
|
362
|
+
if (typeof input === "string") {
|
|
363
|
+
return input.split("\n").map((line) => line.trim());
|
|
364
|
+
}
|
|
365
|
+
if (Array.isArray(input))
|
|
366
|
+
return input.map(String);
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
if (error === undefined) {
|
|
370
|
+
return {
|
|
371
|
+
ErrorMessage: "Callback failed",
|
|
372
|
+
ErrorType: "Error",
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
if (error instanceof Error) {
|
|
376
|
+
const { message, name, stack, ...rest } = error;
|
|
377
|
+
return {
|
|
378
|
+
ErrorMessage: message,
|
|
379
|
+
ErrorType: name,
|
|
380
|
+
ErrorData: Object.keys(rest).length
|
|
381
|
+
? serializeErrorData(rest)
|
|
382
|
+
: undefined,
|
|
383
|
+
StackTrace: normalizeStack(stack),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (typeof error === "string") {
|
|
387
|
+
return {
|
|
388
|
+
ErrorMessage: error,
|
|
389
|
+
ErrorType: "Error",
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
if (error === null || typeof error !== "object") {
|
|
393
|
+
return {
|
|
394
|
+
ErrorMessage: String(error),
|
|
395
|
+
ErrorType: "Error",
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
const value = error;
|
|
399
|
+
const { data, message, name, stack, type, ...rest } = value;
|
|
400
|
+
const hasKnownFields = message !== undefined ||
|
|
401
|
+
name !== undefined ||
|
|
402
|
+
type !== undefined ||
|
|
403
|
+
data !== undefined ||
|
|
404
|
+
stack !== undefined;
|
|
405
|
+
return {
|
|
406
|
+
ErrorMessage: typeof message === "string" ? message : "Callback failed",
|
|
407
|
+
ErrorType: typeof type === "string"
|
|
408
|
+
? type
|
|
409
|
+
: typeof name === "string"
|
|
410
|
+
? name
|
|
411
|
+
: "Error",
|
|
412
|
+
ErrorData: data !== undefined
|
|
413
|
+
? serializeErrorData(data)
|
|
414
|
+
: Object.keys(rest).length
|
|
415
|
+
? serializeErrorData(rest)
|
|
416
|
+
: hasKnownFields
|
|
417
|
+
? undefined
|
|
418
|
+
: serializeErrorData(error),
|
|
419
|
+
StackTrace: normalizeStack(stack),
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
function parseExecution(execution) {
|
|
423
|
+
return {
|
|
424
|
+
arn: execution.DurableExecutionArn,
|
|
425
|
+
name: execution.DurableExecutionName,
|
|
426
|
+
functionArn: execution.FunctionArn,
|
|
427
|
+
status: execution.Status,
|
|
428
|
+
createdAt: parseTimestamp(execution.StartTimestamp),
|
|
429
|
+
endedAt: execution.EndTimestamp === undefined
|
|
430
|
+
? undefined
|
|
431
|
+
: parseTimestamp(execution.EndTimestamp),
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function parseTimestamp(timestamp) {
|
|
435
|
+
const value = typeof timestamp === "number" ? timestamp : Number(timestamp);
|
|
436
|
+
if (Number.isFinite(value)) {
|
|
437
|
+
return new Date(value < 1_000_000_000_000 ? value * 1000 : value);
|
|
438
|
+
}
|
|
439
|
+
return new Date(timestamp);
|
|
440
|
+
}
|
|
441
|
+
function resolveWaitUntilDuration(until) {
|
|
442
|
+
const timestamp = until.getTime();
|
|
443
|
+
if (!Number.isFinite(timestamp)) {
|
|
444
|
+
throw new TypeError("waitUntil requires a valid Date");
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
seconds: Math.max(0, Math.ceil((timestamp - Date.now()) / 1000)),
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function withRollback(context) {
|
|
451
|
+
const wrapped = context;
|
|
452
|
+
if (wrapped[rollbackStateSymbol])
|
|
453
|
+
return wrapped;
|
|
454
|
+
const rollbackState = { undoStack: [] };
|
|
455
|
+
wrapped[rollbackStateSymbol] = rollbackState;
|
|
456
|
+
Object.defineProperty(wrapped, "stepWithRollback", {
|
|
457
|
+
configurable: true,
|
|
458
|
+
enumerable: false,
|
|
459
|
+
writable: true,
|
|
460
|
+
value: function (name, handler, config) {
|
|
461
|
+
const undoConfig = config?.retryStrategy || config?.semantics
|
|
462
|
+
? {
|
|
463
|
+
retryStrategy: config.retryStrategy,
|
|
464
|
+
semantics: config.semantics,
|
|
465
|
+
}
|
|
466
|
+
: undefined;
|
|
467
|
+
return new durable.DurablePromise(async () => {
|
|
468
|
+
const result = await context.step(name, handler.run, config);
|
|
469
|
+
rollbackState.undoStack.push({
|
|
470
|
+
name,
|
|
471
|
+
execute: async (error, rollbackContext) => {
|
|
472
|
+
await rollbackContext.step(`Undo '${name}'`, (stepContext) => handler.undo(error, result, stepContext), undoConfig);
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
return result;
|
|
476
|
+
});
|
|
477
|
+
},
|
|
478
|
+
});
|
|
479
|
+
Object.defineProperty(wrapped, "waitUntil", {
|
|
480
|
+
configurable: true,
|
|
481
|
+
enumerable: false,
|
|
482
|
+
writable: true,
|
|
483
|
+
value: (name, until) => context.wait(name, resolveWaitUntilDuration(until)),
|
|
484
|
+
});
|
|
485
|
+
Object.defineProperty(wrapped, "rollbackAll", {
|
|
486
|
+
configurable: true,
|
|
487
|
+
enumerable: false,
|
|
488
|
+
writable: true,
|
|
489
|
+
value: async (error) => {
|
|
490
|
+
while (rollbackState.undoStack.length > 0) {
|
|
491
|
+
const rollbackStep = rollbackState.undoStack.pop();
|
|
492
|
+
if (!rollbackStep)
|
|
493
|
+
continue;
|
|
494
|
+
try {
|
|
495
|
+
await rollbackStep.execute(error, context);
|
|
496
|
+
}
|
|
497
|
+
catch (undoError) {
|
|
498
|
+
throw new workflow.RollbackError(rollbackStep.name, error, undoError);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
return wrapped;
|
|
504
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export declare namespace event {
|
|
2
|
+
export type Definition = {
|
|
3
|
+
type: string;
|
|
4
|
+
$input: any;
|
|
5
|
+
$output: any;
|
|
6
|
+
$metadata: any;
|
|
7
|
+
$payload: any;
|
|
8
|
+
create: (...args: any[]) => Promise<any>;
|
|
9
|
+
};
|
|
10
|
+
export function builder<Metadata extends ((type: string, properties: any) => any) | Parameters<Validator>[0], Validator extends (schema: any) => (input: any) => any>(input: {
|
|
11
|
+
validator: Validator;
|
|
12
|
+
metadata?: Metadata;
|
|
13
|
+
}): {
|
|
14
|
+
<Type extends string, Schema extends Parameters<Validator>[0]>(type: Type, schema: Schema): {
|
|
15
|
+
create: Metadata extends (type: string, properties: any) => any ? (properties: inferParser<Schema>["in"]) => Promise<{
|
|
16
|
+
type: Type;
|
|
17
|
+
properties: inferParser<Schema>["out"];
|
|
18
|
+
metadata: Metadata extends (type: string, properties: any) => any ? ReturnType<Metadata> : inferParser<Metadata>["out"];
|
|
19
|
+
}> : (properties: inferParser<Schema>["in"], metadata: inferParser<Metadata>["in"]) => Promise<{
|
|
20
|
+
type: Type;
|
|
21
|
+
properties: inferParser<Schema>["out"];
|
|
22
|
+
metadata: Metadata extends (type: string, properties: any) => any ? ReturnType<Metadata> : inferParser<Metadata>["out"];
|
|
23
|
+
}>;
|
|
24
|
+
type: Type;
|
|
25
|
+
$input: inferParser<Schema>["in"];
|
|
26
|
+
$output: inferParser<Schema>["out"];
|
|
27
|
+
$payload: {
|
|
28
|
+
type: Type;
|
|
29
|
+
properties: inferParser<Schema>["out"];
|
|
30
|
+
metadata: Metadata extends (type: string, properties: any) => any ? ReturnType<Metadata> : inferParser<Metadata>["out"];
|
|
31
|
+
};
|
|
32
|
+
$metadata: Metadata extends (type: string, properties: any) => any ? ReturnType<Metadata> : inferParser<Metadata>["out"];
|
|
33
|
+
};
|
|
34
|
+
coerce<Events extends Definition>(_events: Events | Events[], raw: any): { [K in Events["type"]]: Extract<Events, {
|
|
35
|
+
type: K;
|
|
36
|
+
}>["$payload"]; }[Events["type"]];
|
|
37
|
+
};
|
|
38
|
+
type ParserZodEsque<TInput, TParsedInput> = {
|
|
39
|
+
_input: TInput;
|
|
40
|
+
_output: TParsedInput;
|
|
41
|
+
};
|
|
42
|
+
type ParserValibotEsque<TInput, TParsedInput> = {
|
|
43
|
+
_types?: {
|
|
44
|
+
input: TInput;
|
|
45
|
+
output: TParsedInput;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
type ParserMyZodEsque<TInput> = {
|
|
49
|
+
parse: (input: any) => TInput;
|
|
50
|
+
};
|
|
51
|
+
type ParserSuperstructEsque<TInput> = {
|
|
52
|
+
create: (input: unknown) => TInput;
|
|
53
|
+
};
|
|
54
|
+
type ParserCustomValidatorEsque<TInput> = (input: unknown) => Promise<TInput> | TInput;
|
|
55
|
+
type ParserYupEsque<TInput> = {
|
|
56
|
+
validateSync: (input: unknown) => TInput;
|
|
57
|
+
};
|
|
58
|
+
type ParserScaleEsque<TInput> = {
|
|
59
|
+
assert(value: unknown): asserts value is TInput;
|
|
60
|
+
};
|
|
61
|
+
export type ParserWithoutInput<TInput> = ParserCustomValidatorEsque<TInput> | ParserMyZodEsque<TInput> | ParserScaleEsque<TInput> | ParserSuperstructEsque<TInput> | ParserYupEsque<TInput>;
|
|
62
|
+
export type ParserWithInputOutput<TInput, TParsedInput> = ParserZodEsque<TInput, TParsedInput> | ParserValibotEsque<TInput, TParsedInput>;
|
|
63
|
+
export type Parser = ParserWithInputOutput<any, any> | ParserWithoutInput<any>;
|
|
64
|
+
export type inferParser<TParser extends Parser> = TParser extends ParserWithInputOutput<infer $TIn, infer $TOut> ? {
|
|
65
|
+
in: $TIn;
|
|
66
|
+
out: $TOut;
|
|
67
|
+
} : TParser extends ParserWithoutInput<infer $InOut> ? {
|
|
68
|
+
in: $InOut;
|
|
69
|
+
out: $InOut;
|
|
70
|
+
} : never;
|
|
71
|
+
export {};
|
|
72
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export var event;
|
|
2
|
+
(function (event) {
|
|
3
|
+
function builder(input) {
|
|
4
|
+
const validator = input.validator;
|
|
5
|
+
const fn = function event(type, schema) {
|
|
6
|
+
const validate = validator(schema);
|
|
7
|
+
async function create(properties, metadata) {
|
|
8
|
+
metadata = input.metadata
|
|
9
|
+
? typeof input.metadata === "function"
|
|
10
|
+
? input.metadata(type, properties)
|
|
11
|
+
: input.metadata(metadata)
|
|
12
|
+
: metadata ?? {};
|
|
13
|
+
properties = validate(properties);
|
|
14
|
+
return {
|
|
15
|
+
type,
|
|
16
|
+
properties,
|
|
17
|
+
metadata,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
create: create,
|
|
22
|
+
type,
|
|
23
|
+
$input: {},
|
|
24
|
+
$output: {},
|
|
25
|
+
$payload: {},
|
|
26
|
+
$metadata: {},
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
fn.coerce = (_events, raw) => {
|
|
30
|
+
return raw;
|
|
31
|
+
};
|
|
32
|
+
return fn;
|
|
33
|
+
}
|
|
34
|
+
event.builder = builder;
|
|
35
|
+
})(event || (event = {}));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ZodSchema, z } from "zod";
|
|
2
|
+
export declare function ZodValidator<Schema extends ZodSchema>(schema: Schema): (input: z.input<Schema>) => z.output<Schema>;
|
|
3
|
+
import { BaseSchema, InferInput } from "valibot";
|
|
4
|
+
export declare function ValibotValidator<T extends BaseSchema<any, any, any>>(schema: T): (value: InferInput<T>) => import("valibot").InferOutput<T>;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export * from "./realtime/index.js";
|
|
2
|
+
export { Resource } from "./resource/index.js";
|
|
3
|
+
export * from "./vector/index.js";
|
|
4
|
+
import { format } from "util";
|
|
5
|
+
if (process.env?.ECS_CONTAINER_METADATA_URI_V4 &&
|
|
6
|
+
!process.env.SST_DISABLE_LOG_POLYFILL) {
|
|
7
|
+
const log = (level) => (msg, ...rest) => {
|
|
8
|
+
let line = `${level}\t${format(msg, ...rest)}`;
|
|
9
|
+
line = line.replace(/\n/g, "\r");
|
|
10
|
+
process.stdout.write(line + "\n");
|
|
11
|
+
};
|
|
12
|
+
console.log = log("INFO");
|
|
13
|
+
console.warn = log("WARN");
|
|
14
|
+
console.error = log("ERROR");
|
|
15
|
+
console.trace = log("TRACE");
|
|
16
|
+
console.debug = log("DEBUG");
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { realtime } from "../aws/realtime.js";
|
|
2
|
+
export type RealtimeAuthResult = realtime.AuthResult;
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated import from `sst/aws/realtime` instead.
|
|
5
|
+
*
|
|
6
|
+
* Creates an authorization handler for the `Realtime` component, that validates
|
|
7
|
+
* the token and grants permissions for the topics the client can subscribe and publish to.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```js
|
|
11
|
+
* import { RealtimeAuthHandler, Resource } from "sst";
|
|
12
|
+
*
|
|
13
|
+
* export const handler = RealtimeAuthHandler(async (token) => {
|
|
14
|
+
* // Validate the token
|
|
15
|
+
* console.log(token);
|
|
16
|
+
*
|
|
17
|
+
* // Return the topics to subscribe and publish
|
|
18
|
+
* return {
|
|
19
|
+
* subscribe: [`${Resource.App.name}/${Resource.App.stage}/chat/room1`],
|
|
20
|
+
* publish: [`${Resource.App.name}/${Resource.App.stage}/chat/room1`],
|
|
21
|
+
* };
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare const RealtimeAuthHandler: typeof realtime.authorizer;
|