@suss/packs 0.11.0
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/LICENSE +205 -0
- package/README.md +29 -0
- package/dist/activerecord.d.ts +30 -0
- package/dist/activerecord.js +45 -0
- package/dist/apollo-client.d.ts +1 -0
- package/dist/apollo-client.js +137 -0
- package/dist/apollo.d.ts +1 -0
- package/dist/apollo.js +90 -0
- package/dist/aws-dynamodb.d.ts +1 -0
- package/dist/aws-dynamodb.js +386 -0
- package/dist/aws-eventbridge.d.ts +1 -0
- package/dist/aws-eventbridge.js +240 -0
- package/dist/aws-lambda.d.ts +1 -0
- package/dist/aws-lambda.js +382 -0
- package/dist/aws-s3.d.ts +1 -0
- package/dist/aws-s3.js +120 -0
- package/dist/aws-sqs.d.ts +1 -0
- package/dist/aws-sqs.js +296 -0
- package/dist/axios.d.ts +1 -0
- package/dist/axios.js +107 -0
- package/dist/cloudflare-workers.d.ts +1 -0
- package/dist/cloudflare-workers.js +562 -0
- package/dist/drizzle.d.ts +1 -0
- package/dist/drizzle.js +383 -0
- package/dist/express.d.ts +1 -0
- package/dist/express.js +124 -0
- package/dist/fastapi.d.ts +1 -0
- package/dist/fastapi.js +42 -0
- package/dist/fastify.d.ts +1 -0
- package/dist/fastify.js +116 -0
- package/dist/fetch.d.ts +1 -0
- package/dist/fetch.js +64 -0
- package/dist/flask-restx.d.ts +1 -0
- package/dist/flask-restx.js +59 -0
- package/dist/gcs.d.ts +1 -0
- package/dist/gcs.js +134 -0
- package/dist/graphql-ruby.d.ts +1 -0
- package/dist/graphql-ruby.js +84 -0
- package/dist/hono.d.ts +1 -0
- package/dist/hono.js +184 -0
- package/dist/mongoose.d.ts +1 -0
- package/dist/mongoose.js +379 -0
- package/dist/nestjs-graphql.d.ts +1 -0
- package/dist/nestjs-graphql.js +77 -0
- package/dist/nestjs-rest.d.ts +1 -0
- package/dist/nestjs-rest.js +89 -0
- package/dist/nextjs.d.ts +1 -0
- package/dist/nextjs.js +154 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +667 -0
- package/dist/prisma.d.ts +1 -0
- package/dist/prisma.js +448 -0
- package/dist/react-router.d.ts +1 -0
- package/dist/react-router.js +197 -0
- package/dist/react.d.ts +1 -0
- package/dist/react.js +221 -0
- package/dist/redis.d.ts +1 -0
- package/dist/redis.js +93 -0
- package/dist/sqlalchemy.d.ts +1 -0
- package/dist/sqlalchemy.js +48 -0
- package/dist/ts-rest.d.ts +1 -0
- package/dist/ts-rest.js +89 -0
- package/package.json +208 -0
package/dist/aws-sqs.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// ../framework/aws-sqs/dist/index.js
|
|
2
|
+
import {
|
|
3
|
+
Node as N
|
|
4
|
+
} from "ts-morph";
|
|
5
|
+
import { readConfiguredCall, rootIdentifier } from "@suss/adapter-typescript";
|
|
6
|
+
import { messageBusBinding } from "@suss/behavioral-ir";
|
|
7
|
+
import { unwrapJsonStringify } from "@suss/extractor";
|
|
8
|
+
var SEND_COMMANDS = {
|
|
9
|
+
SendMessageCommand: "send",
|
|
10
|
+
SendMessageBatchCommand: "sendBatch"
|
|
11
|
+
};
|
|
12
|
+
function sqsRecognizer(call, ctx) {
|
|
13
|
+
const callNode = call;
|
|
14
|
+
const recognizerCtx = ctx;
|
|
15
|
+
const calleeExpr = callNode.getExpression();
|
|
16
|
+
if (!N.isPropertyAccessExpression(calleeExpr)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
if (calleeExpr.getName() !== "send") {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const args = callNode.getArguments();
|
|
23
|
+
if (args.length === 0) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const firstArg = args[0];
|
|
27
|
+
if (!N.isNewExpression(firstArg)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const ctorExpr = firstArg.getExpression();
|
|
31
|
+
const ctorLeafName = N.isPropertyAccessExpression(ctorExpr) ? ctorExpr.getName() : ctorExpr.getText();
|
|
32
|
+
const operation = SEND_COMMANDS[ctorLeafName];
|
|
33
|
+
if (operation === void 0) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const importCheckTarget = N.isPropertyAccessExpression(ctorExpr) ? rootIdentifier(ctorExpr) : ctorExpr;
|
|
37
|
+
if (importCheckTarget === null || !recognizerCtx.isImportedFrom(importCheckTarget, "@aws-sdk/client-sqs")) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const ctorArgs = firstArg.getArguments();
|
|
41
|
+
if (ctorArgs.length === 0) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const input = ctorArgs[0];
|
|
45
|
+
if (!N.isObjectLiteralExpression(input)) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const channel = readQueueUrlChannel(
|
|
49
|
+
input,
|
|
50
|
+
recognizerCtx.resolveWrittenValue ?? (() => null)
|
|
51
|
+
);
|
|
52
|
+
const rawBody = readPropertyArg(
|
|
53
|
+
input,
|
|
54
|
+
"MessageBody",
|
|
55
|
+
recognizerCtx.extractArgs,
|
|
56
|
+
callNode
|
|
57
|
+
);
|
|
58
|
+
const body = unwrapJsonStringify(rawBody);
|
|
59
|
+
return [
|
|
60
|
+
{
|
|
61
|
+
type: "interaction",
|
|
62
|
+
binding: messageBusBinding({
|
|
63
|
+
recognition: "@suss/framework-aws-sqs",
|
|
64
|
+
messageBus: "aws_sqs",
|
|
65
|
+
channel
|
|
66
|
+
}),
|
|
67
|
+
callee: callNode.getExpression().getText(),
|
|
68
|
+
interaction: {
|
|
69
|
+
class: "message-send",
|
|
70
|
+
...body !== null ? { body } : {}
|
|
71
|
+
// routingKey unused for SQS standard queues. SQS FIFO uses
|
|
72
|
+
// MessageGroupId; future enhancement.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
function readQueueUrlChannel(input, resolveWrittenValue) {
|
|
78
|
+
if (!N.isObjectLiteralExpression(input)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
for (const prop of input.getProperties()) {
|
|
82
|
+
if (!N.isPropertyAssignment(prop)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (prop.getName() !== "QueueUrl") {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const initializer = prop.getInitializer();
|
|
89
|
+
if (initializer === void 0) {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
const named = channelNamedBy(initializer);
|
|
93
|
+
if (named !== null) {
|
|
94
|
+
return named;
|
|
95
|
+
}
|
|
96
|
+
const resolved = resolveWrittenValue(initializer);
|
|
97
|
+
return resolved === null ? null : channelNamedBy(resolved);
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function channelNamedBy(expr) {
|
|
102
|
+
if (N.isPropertyAccessExpression(expr)) {
|
|
103
|
+
const text = expr.getText();
|
|
104
|
+
const match = text.match(/^process\.env\.(\w+)$/);
|
|
105
|
+
return match === null ? null : match[1] ?? null;
|
|
106
|
+
}
|
|
107
|
+
if (N.isStringLiteral(expr)) {
|
|
108
|
+
return expr.getLiteralValue();
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
function readPropertyArg(input, propName, extractCallArgs, callNode) {
|
|
113
|
+
const callArgs = extractCallArgs();
|
|
114
|
+
const first = callArgs[0];
|
|
115
|
+
if (first === null || typeof first !== "object" || first.kind !== "call") {
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
const ctorArgs = first.args ?? [];
|
|
119
|
+
const inputArg = ctorArgs[0];
|
|
120
|
+
if (inputArg === null || typeof inputArg !== "object" || inputArg.kind !== "object") {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const fields = inputArg.fields ?? {};
|
|
124
|
+
void input;
|
|
125
|
+
void callNode;
|
|
126
|
+
return fields[propName] ?? null;
|
|
127
|
+
}
|
|
128
|
+
function messageReceiveRecognizer(call, ctx) {
|
|
129
|
+
const callNode = call;
|
|
130
|
+
void ctx;
|
|
131
|
+
const calleeExpr = callNode.getExpression();
|
|
132
|
+
if (!N.isPropertyAccessExpression(calleeExpr)) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
if (calleeExpr.getName() !== "parse") {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const receiver = calleeExpr.getExpression();
|
|
139
|
+
if (!N.isIdentifier(receiver) || receiver.getText() !== "JSON") {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const args = callNode.getArguments();
|
|
143
|
+
if (args.length !== 1) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
const arg = args[0];
|
|
147
|
+
if (!N.isPropertyAccessExpression(arg)) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
if (arg.getName() !== "body") {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
const recordExpr = arg.getExpression();
|
|
154
|
+
if (!N.isIdentifier(recordExpr)) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
if (!isSqsRecordIdentifier(recordExpr)) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const fields = extractDestructuredFields(callNode);
|
|
161
|
+
return [
|
|
162
|
+
{
|
|
163
|
+
type: "interaction",
|
|
164
|
+
// Channel intentionally null: the queue a handler drains is
|
|
165
|
+
// stated by the CFN event-source mapping, so this side does not
|
|
166
|
+
// name it and the pairing pass joins by codeScope instead.
|
|
167
|
+
binding: messageBusBinding({
|
|
168
|
+
recognition: "@suss/framework-aws-sqs",
|
|
169
|
+
messageBus: "aws_sqs",
|
|
170
|
+
channel: null
|
|
171
|
+
}),
|
|
172
|
+
callee: callNode.getExpression().getText(),
|
|
173
|
+
interaction: {
|
|
174
|
+
class: "message-receive",
|
|
175
|
+
...fields !== null ? { body: { kind: "object", fields } } : {}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
function isSqsRecordIdentifier(recordExpr) {
|
|
181
|
+
if (!N.isIdentifier(recordExpr)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const symbol = recordExpr.getSymbol();
|
|
185
|
+
if (symbol === void 0) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
for (const decl of symbol.getDeclarations()) {
|
|
189
|
+
if (!N.isVariableDeclaration(decl)) {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const declList = decl.getParent();
|
|
193
|
+
if (declList === void 0) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const forOf = declList.getParent();
|
|
197
|
+
if (forOf === void 0 || !N.isForOfStatement(forOf)) {
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const iterated = forOf.getExpression();
|
|
201
|
+
if (N.isPropertyAccessExpression(iterated) && iterated.getName() === "Records") {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
function extractDestructuredFields(call) {
|
|
208
|
+
let parent = call.getParent();
|
|
209
|
+
while (parent !== void 0 && (N.isAsExpression(parent) || N.isParenthesizedExpression(parent))) {
|
|
210
|
+
parent = parent.getParent();
|
|
211
|
+
}
|
|
212
|
+
if (parent === void 0 || !N.isVariableDeclaration(parent)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const nameNode = parent.getNameNode();
|
|
216
|
+
if (!N.isObjectBindingPattern(nameNode)) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const fields = {};
|
|
220
|
+
for (const element of nameNode.getElements()) {
|
|
221
|
+
const propertyNameNode = element.getPropertyNameNode();
|
|
222
|
+
let fieldName;
|
|
223
|
+
if (propertyNameNode !== void 0) {
|
|
224
|
+
fieldName = propertyNameNode.getText();
|
|
225
|
+
} else {
|
|
226
|
+
const nameInner = element.getNameNode();
|
|
227
|
+
if (!N.isIdentifier(nameInner)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
fieldName = nameInner.getText();
|
|
231
|
+
}
|
|
232
|
+
fields[fieldName] = {
|
|
233
|
+
kind: "identifier",
|
|
234
|
+
name: fieldName
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return fields;
|
|
238
|
+
}
|
|
239
|
+
function configuredProducerRecognizer(spec) {
|
|
240
|
+
return ((call, ctx) => {
|
|
241
|
+
const read = readConfiguredCall(
|
|
242
|
+
call,
|
|
243
|
+
ctx,
|
|
244
|
+
spec
|
|
245
|
+
);
|
|
246
|
+
if (read === null) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
return [
|
|
250
|
+
{
|
|
251
|
+
type: "interaction",
|
|
252
|
+
binding: messageBusBinding({
|
|
253
|
+
recognition: "@suss/framework-aws-sqs",
|
|
254
|
+
messageBus: "aws_sqs",
|
|
255
|
+
channel: read.subject
|
|
256
|
+
}),
|
|
257
|
+
callee: read.callee,
|
|
258
|
+
interaction: {
|
|
259
|
+
class: "message-send",
|
|
260
|
+
...read.body !== null ? { body: read.body } : {}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
];
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
function sqsFramework(options = {}) {
|
|
267
|
+
const producers = options.producers ?? [];
|
|
268
|
+
return {
|
|
269
|
+
name: "sqs",
|
|
270
|
+
protocol: "sqs",
|
|
271
|
+
languages: ["typescript", "javascript"],
|
|
272
|
+
discovery: [],
|
|
273
|
+
terminals: [],
|
|
274
|
+
inputMapping: { type: "positionalParams", params: [] },
|
|
275
|
+
// Skip files that don't import either `@aws-sdk/client-sqs`
|
|
276
|
+
// (producer side) or `aws-lambda` (consumer side; SQSEvent type).
|
|
277
|
+
// The recognizers' structural checks are quick but the import
|
|
278
|
+
// gate spares walking SQS-irrelevant files in monorepos.
|
|
279
|
+
requiresImport: [
|
|
280
|
+
.../* @__PURE__ */ new Set([
|
|
281
|
+
"@aws-sdk/client-sqs",
|
|
282
|
+
"aws-lambda",
|
|
283
|
+
...producers.map((p) => p.module)
|
|
284
|
+
])
|
|
285
|
+
],
|
|
286
|
+
invocationRecognizers: [
|
|
287
|
+
sqsRecognizer,
|
|
288
|
+
messageReceiveRecognizer,
|
|
289
|
+
...producers.map(configuredProducerRecognizer)
|
|
290
|
+
]
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
var index_default = sqsFramework;
|
|
294
|
+
export {
|
|
295
|
+
index_default as default
|
|
296
|
+
};
|
package/dist/axios.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@suss/client-axios';
|
package/dist/axios.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// ../client/axios/dist/index.js
|
|
2
|
+
var HTTP_METHODS = [
|
|
3
|
+
"get",
|
|
4
|
+
"post",
|
|
5
|
+
"put",
|
|
6
|
+
"delete",
|
|
7
|
+
"patch",
|
|
8
|
+
"head",
|
|
9
|
+
"options"
|
|
10
|
+
];
|
|
11
|
+
function discoveryForVerb(verb, factories) {
|
|
12
|
+
const patterns = [
|
|
13
|
+
{
|
|
14
|
+
// Matches both shapes:
|
|
15
|
+
// axios.<verb>("/path", ...)
|
|
16
|
+
// const api = axios.create({ ... }); api.<verb>("/path", ...)
|
|
17
|
+
// The factoryMethods entry tells the adapter that variables initialized
|
|
18
|
+
// from axios.create(...) are also clients, wherever that call and
|
|
19
|
+
// this one turn out to live.
|
|
20
|
+
kind: "client",
|
|
21
|
+
match: {
|
|
22
|
+
type: "clientCall",
|
|
23
|
+
importModule: "axios",
|
|
24
|
+
importName: "axios",
|
|
25
|
+
methodFilter: [verb],
|
|
26
|
+
factoryMethods: ["create"]
|
|
27
|
+
},
|
|
28
|
+
bindingExtraction: {
|
|
29
|
+
method: { type: "literal", value: verb.toUpperCase() },
|
|
30
|
+
path: { type: "fromArgumentLiteral", position: 0 }
|
|
31
|
+
},
|
|
32
|
+
requiresImport: ["axios"]
|
|
33
|
+
}
|
|
34
|
+
];
|
|
35
|
+
for (const factory of factories) {
|
|
36
|
+
patterns.push({
|
|
37
|
+
kind: "client",
|
|
38
|
+
match: {
|
|
39
|
+
type: "clientCall",
|
|
40
|
+
importModule: factory.module,
|
|
41
|
+
importName: factory.export,
|
|
42
|
+
methodFilter: [verb]
|
|
43
|
+
},
|
|
44
|
+
bindingExtraction: {
|
|
45
|
+
method: { type: "literal", value: verb.toUpperCase() },
|
|
46
|
+
path: { type: "fromArgumentLiteral", position: 0 }
|
|
47
|
+
},
|
|
48
|
+
// A bare specifier gates the way "axios" above does: cheap and
|
|
49
|
+
// exact, since two files spelling a package name the same way
|
|
50
|
+
// mean the same package. A path-shaped module ("./apiClient")
|
|
51
|
+
// points at a location relative to wherever it's written, and the
|
|
52
|
+
// pre-filter only ever reads a file's own import text before
|
|
53
|
+
// anything is parsed, so it has no way to tell "./apiClient"
|
|
54
|
+
// and a consumer's "../apiClient" apart from string text alone.
|
|
55
|
+
// Narrowing on that string would exclude the consumer roughly
|
|
56
|
+
// as often as include it, so a path-shaped factory gives no
|
|
57
|
+
// gate at all and every file is walked; the discovery layer
|
|
58
|
+
// resolves the module correctly once it's reading a file's
|
|
59
|
+
// imports against a parsed project.
|
|
60
|
+
requiresImport: isPathShapedSpecifier(factory.module) ? [] : [factory.module]
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return patterns;
|
|
64
|
+
}
|
|
65
|
+
function isPathShapedSpecifier(specifier) {
|
|
66
|
+
return specifier.startsWith(".") || specifier.startsWith("/");
|
|
67
|
+
}
|
|
68
|
+
function axiosPack(options = {}) {
|
|
69
|
+
const factories = options.factories ?? [];
|
|
70
|
+
return {
|
|
71
|
+
name: "axios",
|
|
72
|
+
protocol: "http",
|
|
73
|
+
languages: ["typescript", "javascript"],
|
|
74
|
+
discovery: HTTP_METHODS.flatMap(
|
|
75
|
+
(verb) => discoveryForVerb(verb, factories)
|
|
76
|
+
),
|
|
77
|
+
terminals: [
|
|
78
|
+
{
|
|
79
|
+
kind: "return",
|
|
80
|
+
match: { type: "returnStatement" },
|
|
81
|
+
extraction: {}
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
kind: "throw",
|
|
85
|
+
match: { type: "throwExpression" },
|
|
86
|
+
extraction: {}
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
inputMapping: {
|
|
90
|
+
type: "positionalParams",
|
|
91
|
+
params: []
|
|
92
|
+
},
|
|
93
|
+
responseSemantics: [
|
|
94
|
+
// axios returns AxiosResponse: body lives on .data, not .body or .json()
|
|
95
|
+
{ name: "data", access: "property", semantics: { type: "body" } },
|
|
96
|
+
{ name: "status", access: "property", semantics: { type: "statusCode" } },
|
|
97
|
+
{ name: "headers", access: "property", semantics: { type: "headers" } }
|
|
98
|
+
],
|
|
99
|
+
// A non-2xx rejects, so the caller never gets a response to read a
|
|
100
|
+
// status off, and its catch is where every failure arrives.
|
|
101
|
+
failureDelivery: "exception"
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
var index_default = axiosPack;
|
|
105
|
+
export {
|
|
106
|
+
index_default as default
|
|
107
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from '@suss/framework-cloudflare-workers';
|