@reventlessdev/reventless-aws 3.0.0-alpha.401 → 3.0.0-alpha.403
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/CHANGELOG.md +25 -0
- package/package.json +8 -8
- package/src/Platform.res.mjs +2 -2
- package/src/adapter/Mcp/MCP_Lambda.res +1 -1
- package/src/adapter/Mcp/MCP_Lambda.res.mjs +0 -1
- package/src/adapter/Runtime/HeartbeatEntryPoint.res +0 -1
- package/src/adapter/Runtime/HeartbeatEntryPoint.res.mjs +1 -1
- package/src/adapter/Upload/Upload_Presign_S3_Ops.res +13 -3
- package/src/adapter/Upload/Upload_Presign_S3_Ops.res.mjs +7 -2
- package/src/components/Api/AppSync_Adapter.res +3 -0
- package/src/components/Api/AppSync_Adapter.res.mjs +3 -1
- package/src/plugin/cloner/ClonerRunner_Fargate.res +1 -2
- package/src/plugin/cloner/ClonerRunner_Fargate.res.mjs +1 -2
- package/src/util/Util_DeadLetterQueue.res +10 -4
- package/src/util/Util_DeadLetterQueue.res.mjs +6 -1
- package/tests/DcbEventLogStorage_DynamoDb_RuntimeTest.res.mjs +1 -1
- package/tests/EventMapperEntryPoint_OpsTest.res +1 -1
- package/tests/EventMapperEntryPoint_OpsTest.res.mjs +1 -1
- package/tests/PgChangeFeedRelay_IntegrationTest.res.mjs +3 -3
- package/tests/PgPipeline_IntegrationTest.res.mjs +1 -1
- package/tests/Upload_ReleaseRuleTest.res +24 -0
- package/tests/Upload_ReleaseRuleTest.res.mjs +15 -0
- package/tests/integration/DcbEventLogStorage_DynamoDb_IntegrationTest.res.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,31 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# 3.0.0-alpha.403 (2026-10-29)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @reventlessdev/reventless-aws
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# 3.0.0-alpha.402 (2026-10-29)
|
|
15
|
+
|
|
16
|
+
* feat(core)!: the caller's IP address leaves the messages a request causes ([aa9e8c7](https://github.com/ReventlessDev/reventless-core/commit/aa9e8c79c0360528a5cfeda2bb88d1da52f28674))
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
* **upload:** an upload's path carries nothing a person typed ([456c88c](https://github.com/ReventlessDev/reventless-core/commit/456c88c4ccee6a50943e3a71011a2e78aef0d770))
|
|
20
|
+
|
|
21
|
+
### BREAKING CHANGES
|
|
22
|
+
|
|
23
|
+
* `Message.generateMeta` no longer takes `~ip`. Drop the argument; a
|
|
24
|
+
message that must carry the address declares it as a field of its own payload.
|
|
25
|
+
|
|
26
|
+
Step PD3 of docs/plans/a-personal-field-is-marked-redacted-and-encrypted-at-the-seam.md.
|
|
27
|
+
Claude-Session: https://claude.ai/code/session_01HiQfdxVEsHwLHRoHSUcus1
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
6
31
|
# 3.0.0-alpha.401 (2026-10-29)
|
|
7
32
|
|
|
8
33
|
* refactor!: drop `dcbSources`, the cross-plugin DCB subscription nobody declared ([cf3b66d](https://github.com/ReventlessDev/reventless-core/commit/cf3b66d8c1b5d87673197b64eaee174598bb8253))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reventlessdev/reventless-aws",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.403",
|
|
4
4
|
"description": "AWS adapters for Reventless",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"bin": {
|
|
@@ -22,19 +22,19 @@
|
|
|
22
22
|
"sury": "11.0.0",
|
|
23
23
|
"uuid": "^13.0.0",
|
|
24
24
|
"yaml": "^2.8.3",
|
|
25
|
+
"@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.35",
|
|
25
26
|
"@reventlessdev/rescript-aws-sdk": "3.0.0-alpha.36",
|
|
27
|
+
"@reventlessdev/rescript-node": "2.0.0-alpha.23",
|
|
26
28
|
"@reventlessdev/rescript-effect": "1.0.0-alpha.1",
|
|
27
29
|
"@reventlessdev/rescript-jest": "1.0.0-alpha.13",
|
|
28
|
-
"@reventlessdev/rescript-node": "2.0.0-alpha.23",
|
|
29
|
-
"@reventlessdev/rescript-pulumi-aws": "3.0.0-alpha.34",
|
|
30
30
|
"@reventlessdev/rescript-pulumi-pulumi": "3.0.0-alpha.0",
|
|
31
|
-
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
|
|
32
31
|
"@reventlessdev/rescript-web": "1.0.0-alpha.8",
|
|
33
|
-
"@reventlessdev/reventless-core": "3.0.0-alpha.
|
|
34
|
-
"@reventlessdev/
|
|
35
|
-
"@reventlessdev/reventless-postgres": "3.0.0-alpha.
|
|
32
|
+
"@reventlessdev/reventless-core": "3.0.0-alpha.313",
|
|
33
|
+
"@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
|
|
34
|
+
"@reventlessdev/reventless-postgres": "3.0.0-alpha.177",
|
|
36
35
|
"@reventlessdev/reventless-interop": "3.0.0-alpha.42",
|
|
37
|
-
"@reventlessdev/reventless-
|
|
36
|
+
"@reventlessdev/reventless-infra": "3.0.0-alpha.210",
|
|
37
|
+
"@reventlessdev/reventless-spec": "3.0.0-alpha.181"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"rescript": "12.3.1",
|
package/src/Platform.res.mjs
CHANGED
|
@@ -1552,7 +1552,7 @@ function MakeWithConfig(Config) {
|
|
|
1552
1552
|
};
|
|
1553
1553
|
let publishHeartbeat = CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(queue, "SQS_FIFO");
|
|
1554
1554
|
let message_id = hbConfig.pluginId;
|
|
1555
|
-
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name,
|
|
1555
|
+
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, "DeployHeartbeat", undefined, undefined, undefined, undefined, undefined);
|
|
1556
1556
|
let message_commandJson = Util_Sury$Reventless.toJson({
|
|
1557
1557
|
TAG: "RedetectPlugin",
|
|
1558
1558
|
_0: hbConfig.heartbeatTimeout
|
|
@@ -2962,7 +2962,7 @@ function Make($star) {
|
|
|
2962
2962
|
};
|
|
2963
2963
|
let publishHeartbeat = CommandTopicChannel_SQS_Runtime$ReventlessAws.publishJsons(queue, "SQS_FIFO");
|
|
2964
2964
|
let message_id = hbConfig.pluginId;
|
|
2965
|
-
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name,
|
|
2965
|
+
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, "DeployHeartbeat", undefined, undefined, undefined, undefined, undefined);
|
|
2966
2966
|
let message_commandJson = Util_Sury$Reventless.toJson({
|
|
2967
2967
|
TAG: "RedetectPlugin",
|
|
2968
2968
|
_0: hbConfig.heartbeatTimeout
|
|
@@ -383,7 +383,7 @@ let dispatchTool = async (tool: mcpToolEntry, args: JSON.t, identity: Reventless
|
|
|
383
383
|
let payload: ReventlessCore.CommandGenerator.payload = {
|
|
384
384
|
command: tool.name,
|
|
385
385
|
arguments: args->Obj.magic,
|
|
386
|
-
meta: {
|
|
386
|
+
meta: {user: identity.userId, info: `mcp/tools/${tool.name}`},
|
|
387
387
|
identity,
|
|
388
388
|
}
|
|
389
389
|
// Route through the shared dispatch helper so this tool call gets the same
|
|
@@ -254,7 +254,6 @@ async function dispatchTool(tool, args, identity) {
|
|
|
254
254
|
let generateCommand = CommandGenerator_CallbackResMjs.makeGenerateCommand(publishJsons, tool.name, Sury.json, tool.componentKind, false);
|
|
255
255
|
let payload_command = tool.name;
|
|
256
256
|
let payload_meta = {
|
|
257
|
-
ip: [],
|
|
258
257
|
user: identity.userId,
|
|
259
258
|
info: `mcp/tools/` + tool.name
|
|
260
259
|
};
|
|
@@ -39,7 +39,6 @@ let handler = async (_event: JSON.t, _context: PulumiAws.Lambda.context) => {
|
|
|
39
39
|
id: pluginId,
|
|
40
40
|
meta: ReventlessCore.Message.generateMeta(
|
|
41
41
|
~service=ReventlessInfra.PluginExtensionPointSpec.name,
|
|
42
|
-
~ip="",
|
|
43
42
|
~user="Heartbeat",
|
|
44
43
|
),
|
|
45
44
|
commandJson: ReventlessInfra.PluginExtensionPointSpec.Heartbeat(
|
|
@@ -26,7 +26,7 @@ let runtimeExtensionsReady = HandlerFactoryHelpersMjs.runtimeExtensionsReady;
|
|
|
26
26
|
|
|
27
27
|
async function handler(_event, _context) {
|
|
28
28
|
await runtimeExtensionsReady;
|
|
29
|
-
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, "
|
|
29
|
+
let message_meta = Message$ReventlessCore.generateMeta(PluginExtensionPointSpec$ReventlessInfra.name, "Heartbeat", undefined, undefined, undefined, undefined, undefined);
|
|
30
30
|
let message_commandJson = Util_Sury$Reventless.toJson({
|
|
31
31
|
TAG: "Heartbeat",
|
|
32
32
|
_0: timeout
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// surface — the earlier `decodeJwtSub` path is gone.
|
|
12
12
|
//
|
|
13
13
|
// Two operations dispatch on the `operation` field the resolver bakes in:
|
|
14
|
-
// presign → derive `{servedPrefix}/{sub}/{uuid}
|
|
14
|
+
// presign → derive `{servedPrefix}/{sub}/{uuid}.{ext}`, presign a PUT to the
|
|
15
15
|
// store's bucket (expires 300s), return `{uploadUrl, storageRef}`.
|
|
16
16
|
// release → apply the release rule (scope + age) to a `storageRef` and, if it
|
|
17
17
|
// passes, `DeleteObject`; return `{released, reason}`.
|
|
@@ -211,6 +211,10 @@ let headLastModifiedMs = async (~client: s3Client, ~bucket: string, ~key: string
|
|
|
211
211
|
|
|
212
212
|
// ── Operations ──────────────────────────────────────────────────────────────
|
|
213
213
|
|
|
214
|
+
// The object key a presign mints, pure so a test can pin its shape.
|
|
215
|
+
let presignKey = (~servedPrefix, ~sub, ~uuid, ~contentType) =>
|
|
216
|
+
`${servedPrefix}/${sub}/${Reventless.StorageRef.objectName(~uuid, ~contentType)}`
|
|
217
|
+
|
|
214
218
|
let handlePresign = async (
|
|
215
219
|
~client: s3Client,
|
|
216
220
|
~bucket: string,
|
|
@@ -221,11 +225,17 @@ let handlePresign = async (
|
|
|
221
225
|
if sub == "" {
|
|
222
226
|
JsError.throwWithMessage("unauthenticated")
|
|
223
227
|
}
|
|
224
|
-
let fileName = args.fileName->Option.getOr("upload")
|
|
225
228
|
// The object key doubles as the served path segment: rooted at the store's
|
|
226
229
|
// served prefix so the CloudFront `{prefix}/*` behavior fronts it, and namespaced
|
|
227
230
|
// by the verified `sub` so the release rule can tell one caller's objects apart.
|
|
228
|
-
|
|
231
|
+
// The `fileName` argument is not used: the key ends in an opaque name, because a
|
|
232
|
+
// ref is stored in an event and a file name is often personal data.
|
|
233
|
+
let key = presignKey(
|
|
234
|
+
~servedPrefix,
|
|
235
|
+
~sub,
|
|
236
|
+
~uuid=NodeCrypto.randomUUID(),
|
|
237
|
+
~contentType=args.contentType,
|
|
238
|
+
)
|
|
229
239
|
// The object is provisional from the moment the bytes land: it carries the
|
|
230
240
|
// pending tag until a committed event referencing it strips it (see
|
|
231
241
|
// `Upload_Claim_S3_Ops`). Written into the signature here, not asked of the
|
|
@@ -9,6 +9,7 @@ import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
|
9
9
|
import * as Stdlib_JsError from "@rescript/runtime/lib/es6/Stdlib_JsError.js";
|
|
10
10
|
import * as ClientS3 from "@aws-sdk/client-s3";
|
|
11
11
|
import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
|
|
12
|
+
import * as StorageRef$Reventless from "@reventlessdev/reventless-spec/src/semantic/StorageRef.res.mjs";
|
|
12
13
|
import * as S3RequestPresigner from "@aws-sdk/s3-request-presigner";
|
|
13
14
|
import * as Upload_PendingTag$ReventlessAws from "./Upload_PendingTag.res.mjs";
|
|
14
15
|
|
|
@@ -167,12 +168,15 @@ async function headLastModifiedMs(client, bucket, key) {
|
|
|
167
168
|
}
|
|
168
169
|
}
|
|
169
170
|
|
|
171
|
+
function presignKey(servedPrefix, sub, uuid, contentType) {
|
|
172
|
+
return servedPrefix + `/` + sub + `/` + StorageRef$Reventless.objectName(uuid, contentType);
|
|
173
|
+
}
|
|
174
|
+
|
|
170
175
|
async function handlePresign(client, bucket, servedPrefix, sub, args) {
|
|
171
176
|
if (sub === "") {
|
|
172
177
|
Stdlib_JsError.throwWithMessage("unauthenticated");
|
|
173
178
|
}
|
|
174
|
-
let
|
|
175
|
-
let key = servedPrefix + `/` + sub + `/` + Nodecrypto.randomUUID() + `/` + fileName;
|
|
179
|
+
let key = presignKey(servedPrefix, sub, Nodecrypto.randomUUID(), args.contentType);
|
|
176
180
|
let command = new ClientS3.PutObjectCommand({
|
|
177
181
|
Bucket: bucket,
|
|
178
182
|
Key: key,
|
|
@@ -235,6 +239,7 @@ export {
|
|
|
235
239
|
releaseResult,
|
|
236
240
|
keyOfRef,
|
|
237
241
|
headLastModifiedMs,
|
|
242
|
+
presignKey,
|
|
238
243
|
handlePresign,
|
|
239
244
|
handleRelease,
|
|
240
245
|
handler,
|
|
@@ -522,6 +522,9 @@ let _makeApiResourceWith = (
|
|
|
522
522
|
let appsyncLogConfig: AppSync.GraphQLApi.logConfig = {
|
|
523
523
|
cloudwatchLogsRoleArn: iamRole.arn->Pulumi.Output.asInput,
|
|
524
524
|
fieldLogLevel: AppSync.GraphQLApi.ERROR->Pulumi.Input.make,
|
|
525
|
+
// Without it an error line carries the request's arguments and the resolver's
|
|
526
|
+
// context, which hold whatever the caller sent, a person's name included.
|
|
527
|
+
excludeVerboseContent: true->Pulumi.Input.make,
|
|
525
528
|
}
|
|
526
529
|
|
|
527
530
|
// Resolve the Cognito UserPool — either supplied by the caller (plugin-stack
|
|
@@ -268,9 +268,11 @@ function _makeApiResourceWith(name, schema, userPoolConfig, opts) {
|
|
|
268
268
|
role: iamRole.name
|
|
269
269
|
}, customOpts);
|
|
270
270
|
let appsyncLogConfig_cloudwatchLogsRoleArn = iamRole.arn;
|
|
271
|
+
let appsyncLogConfig_excludeVerboseContent = true;
|
|
271
272
|
let appsyncLogConfig = {
|
|
272
273
|
cloudwatchLogsRoleArn: appsyncLogConfig_cloudwatchLogsRoleArn,
|
|
273
|
-
fieldLogLevel: "ERROR"
|
|
274
|
+
fieldLogLevel: "ERROR",
|
|
275
|
+
excludeVerboseContent: appsyncLogConfig_excludeVerboseContent
|
|
274
276
|
};
|
|
275
277
|
let userPoolConfigOut = userPoolConfig !== undefined ? userPoolConfig : Auth_Cognito$ReventlessAws.make(name + `-auth`, undefined).apply(c => ({
|
|
276
278
|
userPoolId: c.userPoolId,
|
|
@@ -114,7 +114,7 @@ export const handler = async (event) => {
|
|
|
114
114
|
["REVENTLESS_CORE_STACK", process.env.STACK_ORG + "/" + process.env.STACK_PROJECT + "/" + process.env.STACK_STACK],
|
|
115
115
|
["RESTORE_DATE_TIME", event.restoreDateTime],
|
|
116
116
|
]);
|
|
117
|
-
console.log("clone: requested by user " + event.meta.user
|
|
117
|
+
console.log("clone: requested by user " + event.meta.user);
|
|
118
118
|
await client.send(new RunTaskCommand({
|
|
119
119
|
taskDefinition: process.env.TASK_DEFINITION_ARN,
|
|
120
120
|
cluster: process.env.CLUSTER_ARN,
|
|
@@ -358,7 +358,6 @@ export function request(ctx) {
|
|
|
358
358
|
payload: {
|
|
359
359
|
restoreDateTime: ctx.args.restoreDateTime,
|
|
360
360
|
meta: {
|
|
361
|
-
ip: ctx.identity.sourceIp,
|
|
362
361
|
user: ctx.identity.username
|
|
363
362
|
}
|
|
364
363
|
}
|
|
@@ -67,7 +67,7 @@ export const handler = async (event) => {
|
|
|
67
67
|
["REVENTLESS_CORE_STACK", process.env.STACK_ORG + "/" + process.env.STACK_PROJECT + "/" + process.env.STACK_STACK],
|
|
68
68
|
["RESTORE_DATE_TIME", event.restoreDateTime],
|
|
69
69
|
]);
|
|
70
|
-
console.log("clone: requested by user " + event.meta.user
|
|
70
|
+
console.log("clone: requested by user " + event.meta.user);
|
|
71
71
|
await client.send(new RunTaskCommand({
|
|
72
72
|
taskDefinition: process.env.TASK_DEFINITION_ARN,
|
|
73
73
|
cluster: process.env.CLUSTER_ARN,
|
|
@@ -235,7 +235,6 @@ export function request(ctx) {
|
|
|
235
235
|
payload: {
|
|
236
236
|
restoreDateTime: ctx.args.restoreDateTime,
|
|
237
237
|
meta: {
|
|
238
|
-
ip: ctx.identity.sourceIp,
|
|
239
238
|
user: ctx.identity.username
|
|
240
239
|
}
|
|
241
240
|
}
|
|
@@ -88,9 +88,10 @@ let lambdaRole = IAM.Role.makeWithDefaultPolicy(
|
|
|
88
88
|
// bug removes the message that was stranded by it. Seven of them were still
|
|
89
89
|
// cycling twelve hours after the fix that made them impossible.
|
|
90
90
|
//
|
|
91
|
-
// What the loop costs is now a function of the line, not the count: the
|
|
92
|
-
//
|
|
93
|
-
//
|
|
91
|
+
// What the loop costs is now a function of the line, not the count: the first
|
|
92
|
+
// delivery writes the record's ids, kind, size and attribute names — never its
|
|
93
|
+
// body, which is a command or event and may be about a person — and every
|
|
94
|
+
// redelivery after it costs a single identity line. A stranded
|
|
94
95
|
// message is ~150 KB over a fortnight rather than ~17 MB, which is small enough
|
|
95
96
|
// that ending the loop early is an operator's job rather than the topology's.
|
|
96
97
|
let entryPointCode = `export const handler = async (event) => {
|
|
@@ -104,7 +105,12 @@ let entryPointCode = `export const handler = async (event) => {
|
|
|
104
105
|
" receiveCount=" + receiveCount +
|
|
105
106
|
" bodyBytes=" + (record?.body?.length ?? 0);
|
|
106
107
|
if (receiveCount <= 1) {
|
|
107
|
-
|
|
108
|
+
// Ids, type and size, never the body: a dead letter is a command or event,
|
|
109
|
+
// and its payload may be about a person.
|
|
110
|
+
const body = (() => { try { return JSON.parse(record?.body ?? "null") } catch { return null } })();
|
|
111
|
+
const kind = body?.command?.TAG ?? body?.event?.TAG ?? (body?.Message ? "sns" : "unknown");
|
|
112
|
+
console.error("DEAD LETTER ITEM: " + identity + " kind=" + kind +
|
|
113
|
+
" attributes=" + JSON.stringify(Object.keys(record?.messageAttributes ?? {})));
|
|
108
114
|
} else {
|
|
109
115
|
console.error("DEAD LETTER REDELIVERY: " + identity);
|
|
110
116
|
}
|
|
@@ -56,7 +56,12 @@ let entryPointCode = `export const handler = async (event) => {
|
|
|
56
56
|
" receiveCount=" + receiveCount +
|
|
57
57
|
" bodyBytes=" + (record?.body?.length ?? 0);
|
|
58
58
|
if (receiveCount <= 1) {
|
|
59
|
-
|
|
59
|
+
// Ids, type and size, never the body: a dead letter is a command or event,
|
|
60
|
+
// and its payload may be about a person.
|
|
61
|
+
const body = (() => { try { return JSON.parse(record?.body ?? "null") } catch { return null } })();
|
|
62
|
+
const kind = body?.command?.TAG ?? body?.event?.TAG ?? (body?.Message ? "sns" : "unknown");
|
|
63
|
+
console.error("DEAD LETTER ITEM: " + identity + " kind=" + kind +
|
|
64
|
+
" attributes=" + JSON.stringify(Object.keys(record?.messageAttributes ?? {})));
|
|
60
65
|
} else {
|
|
61
66
|
console.error("DEAD LETTER REDELIVERY: " + identity);
|
|
62
67
|
}
|
|
@@ -17,7 +17,7 @@ function tag(key, value) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function testMeta() {
|
|
20
|
-
return Message$ReventlessCore.generateMeta("test", undefined, undefined, undefined, undefined, undefined, undefined
|
|
20
|
+
return Message$ReventlessCore.generateMeta("test", undefined, undefined, undefined, undefined, undefined, undefined);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
let table = {
|
|
@@ -78,7 +78,7 @@ describe("EventMapperEntryPoint_Ops.makeStreamHandler", () => {
|
|
|
78
78
|
}
|
|
79
79
|
let command: ReventlessCore.Message.commandJson = {
|
|
80
80
|
id: "prd-1",
|
|
81
|
-
meta: ReventlessCore.Message.generateMeta(~service="Product", ~
|
|
81
|
+
meta: ReventlessCore.Message.generateMeta(~service="Product", ~user="test"),
|
|
82
82
|
commandJson: JSON.Encode.string("Add"),
|
|
83
83
|
}
|
|
84
84
|
let commonEventsHandler: EventMapperEntryPoint_Ops.commonEventsHandler = async jsons => {
|
|
@@ -70,7 +70,7 @@ globalThis.describe("EventMapperEntryPoint_Ops.makeStreamHandler", () => {
|
|
|
70
70
|
publishJsons: ops_publishJsons,
|
|
71
71
|
queryEngine: ops_queryEngine
|
|
72
72
|
};
|
|
73
|
-
let command_meta = Message$ReventlessCore.generateMeta("Product", "
|
|
73
|
+
let command_meta = Message$ReventlessCore.generateMeta("Product", "test", undefined, undefined, undefined, undefined, undefined);
|
|
74
74
|
let command = {
|
|
75
75
|
id: "prd-1",
|
|
76
76
|
meta: command_meta,
|
|
@@ -22,7 +22,7 @@ function stored(eventType, tags, data) {
|
|
|
22
22
|
eventType: eventType,
|
|
23
23
|
data: data,
|
|
24
24
|
tags: tags,
|
|
25
|
-
meta: Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined
|
|
25
|
+
meta: Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined)
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -124,7 +124,7 @@ if (url !== undefined) {
|
|
|
124
124
|
"data",
|
|
125
125
|
data
|
|
126
126
|
]
|
|
127
|
-
].concat(Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined
|
|
127
|
+
].concat(Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined))));
|
|
128
128
|
await match[1].append(0, "agg-1", [
|
|
129
129
|
flatItem("agg-1", 0, "NameUpdated", Object.fromEntries([[
|
|
130
130
|
"n",
|
|
@@ -155,7 +155,7 @@ if (url !== undefined) {
|
|
|
155
155
|
let mkOps = name => EventLogStorage_Postgres$ReventlessPostgres.makeStorage(pool, name, undefined, undefined)[1];
|
|
156
156
|
let opsB = mkOps("ClassicRelayIsoBEventLog");
|
|
157
157
|
let opsA = mkOps("ClassicRelayIsoAEventLog");
|
|
158
|
-
let meta = () => Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined
|
|
158
|
+
let meta = () => Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta("relay-it", undefined, undefined, undefined, undefined, undefined, undefined));
|
|
159
159
|
let item = (id, eventType) => Object.fromEntries([
|
|
160
160
|
[
|
|
161
161
|
"id",
|
|
@@ -132,7 +132,7 @@ function flatItem(id, seq, service, event) {
|
|
|
132
132
|
"data",
|
|
133
133
|
match[1]
|
|
134
134
|
]
|
|
135
|
-
].concat(Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta(service, undefined, undefined, undefined, undefined, undefined, undefined
|
|
135
|
+
].concat(Message$ReventlessCore.decomposeMeta(Message$ReventlessCore.generateMeta(service, undefined, undefined, undefined, undefined, undefined, undefined))));
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
function asSqsEvent(bodies) {
|
|
@@ -88,3 +88,27 @@ describe("Upload_Presign_S3_Ops.decideRelease", () => {
|
|
|
88
88
|
)
|
|
89
89
|
)
|
|
90
90
|
})
|
|
91
|
+
|
|
92
|
+
describe("Upload_Presign_S3_Ops.presignKey", () => {
|
|
93
|
+
testSync("is {prefix}/{sub}/{uuid}.{ext}, with nothing the uploader typed", () =>
|
|
94
|
+
expect(
|
|
95
|
+
Ops.presignKey(~servedPrefix=prefix, ~sub, ~uuid="0b1c", ~contentType=Some("image/png")),
|
|
96
|
+
)->toEqual("uploads/user-1/0b1c.png")
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
testSync("an undeclared content type is stored as bin", () =>
|
|
100
|
+
expect(Ops.presignKey(~servedPrefix=prefix, ~sub, ~uuid="0b1c", ~contentType=None))->toEqual(
|
|
101
|
+
"uploads/user-1/0b1c.bin",
|
|
102
|
+
)
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
testSync("a minted key passes the release rule's scope check for its own caller", () =>
|
|
106
|
+
expect(
|
|
107
|
+
Ops.scopeCheck(
|
|
108
|
+
~key=Ops.presignKey(~servedPrefix=prefix, ~sub, ~uuid="0b1c", ~contentType=None),
|
|
109
|
+
~sub,
|
|
110
|
+
~servedPrefix=prefix,
|
|
111
|
+
),
|
|
112
|
+
)->toEqual(Ok())
|
|
113
|
+
)
|
|
114
|
+
})
|
|
@@ -89,6 +89,21 @@ globalThis.describe("Upload_Presign_S3_Ops.decideRelease", () => {
|
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
91
|
|
|
92
|
+
globalThis.describe("Upload_Presign_S3_Ops.presignKey", () => {
|
|
93
|
+
globalThis.test("is {prefix}/{sub}/{uuid}.{ext}, with nothing the uploader typed", () => {
|
|
94
|
+
globalThis.expect(Upload_Presign_S3_Ops$ReventlessAws.presignKey(prefix, sub, "0b1c", "image/png")).toEqual("uploads/user-1/0b1c.png");
|
|
95
|
+
});
|
|
96
|
+
globalThis.test("an undeclared content type is stored as bin", () => {
|
|
97
|
+
globalThis.expect(Upload_Presign_S3_Ops$ReventlessAws.presignKey(prefix, sub, "0b1c", undefined)).toEqual("uploads/user-1/0b1c.bin");
|
|
98
|
+
});
|
|
99
|
+
globalThis.test("a minted key passes the release rule's scope check for its own caller", () => {
|
|
100
|
+
globalThis.expect(Upload_Presign_S3_Ops$ReventlessAws.scopeCheck(Upload_Presign_S3_Ops$ReventlessAws.presignKey(prefix, sub, "0b1c", undefined), sub, prefix)).toEqual({
|
|
101
|
+
TAG: "Ok",
|
|
102
|
+
_0: undefined
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
|
|
92
107
|
let Ops;
|
|
93
108
|
|
|
94
109
|
let nowMs = 1000000.0;
|
|
@@ -13,7 +13,7 @@ function tag(key, value) {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
function meta() {
|
|
16
|
-
return Message$ReventlessCore.generateMeta("dcb-it", undefined, undefined, undefined, undefined, undefined, undefined
|
|
16
|
+
return Message$ReventlessCore.generateMeta("dcb-it", undefined, undefined, undefined, undefined, undefined, undefined);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
function event(eventType, tags) {
|