@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.
Files changed (63) hide show
  1. package/LICENSE +205 -0
  2. package/README.md +29 -0
  3. package/dist/activerecord.d.ts +30 -0
  4. package/dist/activerecord.js +45 -0
  5. package/dist/apollo-client.d.ts +1 -0
  6. package/dist/apollo-client.js +137 -0
  7. package/dist/apollo.d.ts +1 -0
  8. package/dist/apollo.js +90 -0
  9. package/dist/aws-dynamodb.d.ts +1 -0
  10. package/dist/aws-dynamodb.js +386 -0
  11. package/dist/aws-eventbridge.d.ts +1 -0
  12. package/dist/aws-eventbridge.js +240 -0
  13. package/dist/aws-lambda.d.ts +1 -0
  14. package/dist/aws-lambda.js +382 -0
  15. package/dist/aws-s3.d.ts +1 -0
  16. package/dist/aws-s3.js +120 -0
  17. package/dist/aws-sqs.d.ts +1 -0
  18. package/dist/aws-sqs.js +296 -0
  19. package/dist/axios.d.ts +1 -0
  20. package/dist/axios.js +107 -0
  21. package/dist/cloudflare-workers.d.ts +1 -0
  22. package/dist/cloudflare-workers.js +562 -0
  23. package/dist/drizzle.d.ts +1 -0
  24. package/dist/drizzle.js +383 -0
  25. package/dist/express.d.ts +1 -0
  26. package/dist/express.js +124 -0
  27. package/dist/fastapi.d.ts +1 -0
  28. package/dist/fastapi.js +42 -0
  29. package/dist/fastify.d.ts +1 -0
  30. package/dist/fastify.js +116 -0
  31. package/dist/fetch.d.ts +1 -0
  32. package/dist/fetch.js +64 -0
  33. package/dist/flask-restx.d.ts +1 -0
  34. package/dist/flask-restx.js +59 -0
  35. package/dist/gcs.d.ts +1 -0
  36. package/dist/gcs.js +134 -0
  37. package/dist/graphql-ruby.d.ts +1 -0
  38. package/dist/graphql-ruby.js +84 -0
  39. package/dist/hono.d.ts +1 -0
  40. package/dist/hono.js +184 -0
  41. package/dist/mongoose.d.ts +1 -0
  42. package/dist/mongoose.js +379 -0
  43. package/dist/nestjs-graphql.d.ts +1 -0
  44. package/dist/nestjs-graphql.js +77 -0
  45. package/dist/nestjs-rest.d.ts +1 -0
  46. package/dist/nestjs-rest.js +89 -0
  47. package/dist/nextjs.d.ts +1 -0
  48. package/dist/nextjs.js +154 -0
  49. package/dist/node.d.ts +1 -0
  50. package/dist/node.js +667 -0
  51. package/dist/prisma.d.ts +1 -0
  52. package/dist/prisma.js +448 -0
  53. package/dist/react-router.d.ts +1 -0
  54. package/dist/react-router.js +197 -0
  55. package/dist/react.d.ts +1 -0
  56. package/dist/react.js +221 -0
  57. package/dist/redis.d.ts +1 -0
  58. package/dist/redis.js +93 -0
  59. package/dist/sqlalchemy.d.ts +1 -0
  60. package/dist/sqlalchemy.js +48 -0
  61. package/dist/ts-rest.d.ts +1 -0
  62. package/dist/ts-rest.js +89 -0
  63. package/package.json +208 -0
package/dist/fetch.js ADDED
@@ -0,0 +1,64 @@
1
+ // ../client/web/dist/index.js
2
+ function webFetchPack() {
3
+ return {
4
+ name: "fetch",
5
+ protocol: "http",
6
+ languages: ["typescript"],
7
+ discovery: [
8
+ {
9
+ kind: "client",
10
+ match: {
11
+ type: "clientCall",
12
+ importModule: "global",
13
+ importName: "fetch"
14
+ },
15
+ bindingExtraction: {
16
+ method: {
17
+ type: "fromArgumentProperty",
18
+ position: 1,
19
+ property: "method",
20
+ default: "GET"
21
+ },
22
+ path: { type: "fromArgumentLiteral", position: 0 }
23
+ },
24
+ // No import gate: `fetch` is a global. Walk every file,
25
+ // the discovery dispatch is itself cheap (just looks for
26
+ // call expressions named `fetch`), so the lack of pre-
27
+ // filter doesn't blow up perf.
28
+ requiresImport: []
29
+ }
30
+ ],
31
+ terminals: [
32
+ {
33
+ kind: "return",
34
+ match: { type: "returnStatement" },
35
+ extraction: {}
36
+ },
37
+ {
38
+ kind: "throw",
39
+ match: { type: "throwExpression" },
40
+ extraction: {}
41
+ }
42
+ ],
43
+ inputMapping: {
44
+ type: "positionalParams",
45
+ params: []
46
+ },
47
+ responseSemantics: [
48
+ {
49
+ name: "ok",
50
+ access: "property",
51
+ semantics: { type: "statusRange", min: 200, max: 299 }
52
+ },
53
+ { name: "status", access: "property", semantics: { type: "statusCode" } },
54
+ { name: "json", access: "method", semantics: { type: "body" } },
55
+ { name: "text", access: "method", semantics: { type: "body" } },
56
+ { name: "body", access: "property", semantics: { type: "body" } },
57
+ { name: "headers", access: "property", semantics: { type: "headers" } }
58
+ ]
59
+ };
60
+ }
61
+ var index_default = webFetchPack;
62
+ export {
63
+ index_default as default
64
+ };
@@ -0,0 +1 @@
1
+ export { default } from '@suss/framework-flask-restx';
@@ -0,0 +1,59 @@
1
+ // ../framework/flask-restx/dist/index.js
2
+ var VERB_METHOD_NAMES = {
3
+ get: "GET",
4
+ post: "POST",
5
+ put: "PUT",
6
+ delete: "DELETE",
7
+ patch: "PATCH",
8
+ head: "HEAD",
9
+ options: "OPTIONS"
10
+ };
11
+ function flaskRestxFramework(options = {}) {
12
+ return {
13
+ name: "flask-restx",
14
+ protocol: "http",
15
+ ...options.wrapperModules !== void 0 ? { projectModules: options.wrapperModules } : {},
16
+ discovery: [
17
+ {
18
+ type: "decoratedClassRoute",
19
+ importModule: ["flask_restx", ...options.wrapperModules ?? []],
20
+ decoratorName: "route",
21
+ verbMethodNames: VERB_METHOD_NAMES,
22
+ pathParamSyntax: "flaskConverters",
23
+ // What each of these settings means for a written prefix is the
24
+ // grid in the Python adapter's README.
25
+ pathRepeatedSlashes: "merged",
26
+ routerComposition: {
27
+ routerConstructorName: "Namespace",
28
+ includeMethodName: "add_namespace",
29
+ prefixKeyword: "path",
30
+ mountPrefixEffect: "replaces",
31
+ constructorPrefixRequired: true,
32
+ constructorPrefixTrailingSlash: "trimmed",
33
+ noValuePrefix: "unstated",
34
+ mountObjectPrefix: {
35
+ prefixKeyword: "prefix",
36
+ carrier: {
37
+ importModule: ["flask"],
38
+ constructorName: "Blueprint",
39
+ argumentIndex: 0,
40
+ prefixKeyword: "url_prefix",
41
+ handoffMethodName: "init_app",
42
+ registerMethodName: "register_blueprint"
43
+ }
44
+ }
45
+ },
46
+ // Flask returns 200 from a resource method that returns a value
47
+ // and sets no status of its own.
48
+ defaultStatusCode: 200,
49
+ // Flask reads a status out of `return body, 201`, so the 200
50
+ // above only stands when the body writes no status of its own.
51
+ statusFromReturnedTuple: true
52
+ }
53
+ ]
54
+ };
55
+ }
56
+ var index_default = flaskRestxFramework;
57
+ export {
58
+ index_default as default
59
+ };
package/dist/gcs.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from '@suss/framework-gcs';
package/dist/gcs.js ADDED
@@ -0,0 +1,134 @@
1
+ // ../framework/gcs/dist/index.js
2
+ import { Node as N } from "ts-morph";
3
+ import { methodDeclaredIn, readName } from "@suss/adapter-typescript";
4
+ import { storageBinding } from "@suss/behavioral-ir";
5
+ var RECOGNITION = "@suss/framework-gcs";
6
+ var CLIENT_MODULE = "@google-cloud/storage";
7
+ var OPERATIONS = {
8
+ download: "read",
9
+ createReadStream: "read",
10
+ getMetadata: "read",
11
+ exists: "read",
12
+ isPublic: "read",
13
+ getFiles: "read",
14
+ save: "write",
15
+ upload: "write",
16
+ createWriteStream: "write",
17
+ delete: "write",
18
+ copy: "write",
19
+ move: "write",
20
+ rename: "write",
21
+ setMetadata: "write",
22
+ makePublic: "write",
23
+ makePrivate: "write"
24
+ };
25
+ var SIGNED_URL = "getSignedUrl";
26
+ var SIGNED_ACTIONS = {
27
+ read: "read",
28
+ write: "write",
29
+ delete: "write",
30
+ resumable: "write"
31
+ };
32
+ var BUCKET_STEP = "bucket";
33
+ var FILE_STEP = "file";
34
+ function gcsRecognizer(call, ctx) {
35
+ const callNode = call;
36
+ const resolve = ctx.resolveWrittenValue ?? (() => null);
37
+ const callee = callNode.getExpression();
38
+ if (!N.isPropertyAccessExpression(callee)) {
39
+ return null;
40
+ }
41
+ const operation = callee.getName();
42
+ const kind = kindOf(operation, callNode, resolve);
43
+ if (kind === null || !methodDeclaredIn(callee, CLIENT_MODULE)) {
44
+ return null;
45
+ }
46
+ const chain = walkChain(callee.getExpression(), resolve);
47
+ return [
48
+ {
49
+ type: "interaction",
50
+ binding: storageBinding({
51
+ recognition: RECOGNITION,
52
+ storageSystem: "gcs",
53
+ scope: "default",
54
+ container: chain.bucket,
55
+ accessPath: null
56
+ }),
57
+ callee: callee.getText(),
58
+ interaction: {
59
+ class: "storage-access",
60
+ kind,
61
+ // An object has no fields, so a call says nothing about any.
62
+ fields: [],
63
+ operation,
64
+ ...chain.object !== null ? { selector: [chain.object] } : {}
65
+ }
66
+ }
67
+ ];
68
+ }
69
+ function kindOf(operation, call, resolve) {
70
+ if (operation !== SIGNED_URL) {
71
+ return OPERATIONS[operation] ?? null;
72
+ }
73
+ const config = call.getArguments()[0];
74
+ const asked = config === void 0 ? null : property(config, "action");
75
+ const action = asked === null ? null : readName(asked, { resolve });
76
+ return action === null ? "read" : SIGNED_ACTIONS[action] ?? "read";
77
+ }
78
+ function walkChain(subject, resolve) {
79
+ let step = subject;
80
+ const found = { bucket: null, object: null };
81
+ for (let hops = 0; step !== null && hops < MAX_CHAIN_STEPS; hops++) {
82
+ if (N.isIdentifier(step) || N.isPropertyAccessExpression(step)) {
83
+ const written = resolve(step);
84
+ step = written === step ? null : written;
85
+ continue;
86
+ }
87
+ if (!N.isCallExpression(step)) {
88
+ return found;
89
+ }
90
+ const callee = step.getExpression();
91
+ if (!N.isPropertyAccessExpression(callee)) {
92
+ return found;
93
+ }
94
+ const named = callee.getName();
95
+ const argument = step.getArguments()[0];
96
+ if (named === FILE_STEP && found.object === null) {
97
+ found.object = argument === void 0 ? null : readName(argument, { resolve, unsettled: "reference" });
98
+ }
99
+ if (named === BUCKET_STEP && found.bucket === null) {
100
+ found.bucket = argument === void 0 ? null : readName(argument, { resolve, unsettled: "reference" });
101
+ return found;
102
+ }
103
+ step = callee.getExpression();
104
+ }
105
+ return found;
106
+ }
107
+ var MAX_CHAIN_STEPS = 8;
108
+ function property(input, name) {
109
+ if (!N.isObjectLiteralExpression(input)) {
110
+ return null;
111
+ }
112
+ for (const prop of input.getProperties()) {
113
+ if (N.isPropertyAssignment(prop) && prop.getName() === name) {
114
+ return prop.getInitializer() ?? null;
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ function gcsFramework() {
120
+ return {
121
+ name: "gcs",
122
+ protocol: "gcs",
123
+ languages: ["typescript", "javascript"],
124
+ discovery: [],
125
+ terminals: [],
126
+ inputMapping: { type: "positionalParams", params: [] },
127
+ requiresImport: [CLIENT_MODULE],
128
+ invocationRecognizers: [gcsRecognizer]
129
+ };
130
+ }
131
+ var index_default = gcsFramework;
132
+ export {
133
+ index_default as default
134
+ };
@@ -0,0 +1 @@
1
+ export { default } from '@suss/framework-graphql-ruby';
@@ -0,0 +1,84 @@
1
+ // ../framework/graphql-ruby/dist/index.js
2
+ import path from "path";
3
+ import { SCALAR_SHAPES } from "@suss/contract-graphql";
4
+ var DEFAULT_BASE_CLASS_NAMES = [
5
+ "Types::BaseObject",
6
+ "Types::BaseInterface",
7
+ "Types::BaseInputObject",
8
+ "Types::BaseEnum",
9
+ "Types::BaseUnion",
10
+ "Types::BaseScalar"
11
+ ];
12
+ function rootDirectory(options) {
13
+ if (options.configDirectory === void 0 || path.isAbsolute(options.root)) {
14
+ return options.root;
15
+ }
16
+ return path.resolve(options.configDirectory, options.root);
17
+ }
18
+ function graphqlRubyFramework(options) {
19
+ if (typeof options?.root !== "string" || options.root === "") {
20
+ throw new Error(
21
+ "it needs `root`, the directory a wired field's class is looked up under, and no default can be right: that is this project's own directory layout. A Rails app generated by the library keeps it at app/graphql."
22
+ );
23
+ }
24
+ const pattern = {
25
+ type: "graphqlObjectFields",
26
+ baseClassNames: [
27
+ ...DEFAULT_BASE_CLASS_NAMES,
28
+ ...options.baseClassNames ?? []
29
+ ],
30
+ root: rootDirectory(options),
31
+ pathConvention: "railsUnderscore",
32
+ fieldCallName: "field",
33
+ typeCallName: "type",
34
+ argumentCallName: "argument",
35
+ wiringKeywords: ["mutation", "resolver"],
36
+ resolverMethodName: "resolve",
37
+ // The classes graphql-ruby's own generated base classes extend or
38
+ // mix in. A project's chain ends at one of them.
39
+ ancestryRootClassNames: [
40
+ "GraphQL::Schema::Object",
41
+ "GraphQL::Schema::Mutation",
42
+ "GraphQL::Schema::Resolver",
43
+ "GraphQL::Schema::Interface",
44
+ "GraphQL::Schema::InputObject",
45
+ "GraphQL::Schema::Enum",
46
+ "GraphQL::Schema::Union",
47
+ "GraphQL::Schema::Scalar"
48
+ ],
49
+ requiredKeyword: "required",
50
+ // graphql-ruby registers an argument as required unless the call
51
+ // opts out with `required: false`.
52
+ requiredDefault: true,
53
+ camelizeKeyword: "camelize",
54
+ camelizeDefault: options.camelize ?? true,
55
+ // The standard scalars come from the shared SDL table, so a
56
+ // contract read from Ruby compares against one read from SDL
57
+ // without a vocabulary mismatch. graphql-ruby accepts Ruby's own
58
+ // `Integer` class as a synonym for its `Int` scalar.
59
+ scalars: {
60
+ ...SCALAR_SHAPES,
61
+ Integer: { type: "number" }
62
+ },
63
+ scalarNamePrefixes: ["GraphQL::Types::"],
64
+ typeNameConvention: "stripTypeSuffix",
65
+ // RelayClassicMutation wraps every declared argument into one
66
+ // `input` argument on the wire and adds clientMutationId to it.
67
+ argumentWrapping: {
68
+ ancestorClassName: "GraphQL::Schema::RelayClassicMutation",
69
+ argumentName: "input",
70
+ extraFields: {
71
+ clientMutationId: { type: { type: "text" }, required: false }
72
+ }
73
+ }
74
+ };
75
+ return {
76
+ name: "graphql-ruby",
77
+ protocol: "http-graphql",
78
+ discovery: [pattern]
79
+ };
80
+ }
81
+ var index_default = graphqlRubyFramework;
82
+ export {
83
+ index_default as default
84
+ };
package/dist/hono.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { default } from '@suss/framework-hono';
package/dist/hono.js ADDED
@@ -0,0 +1,184 @@
1
+ // ../framework/hono/dist/index.js
2
+ import { httpRouteDiscovery } from "@suss/extractor";
3
+ var HTTP_EXCEPTION_CODES = {
4
+ HTTPException: 500
5
+ };
6
+ function honoFramework() {
7
+ return {
8
+ name: "hono",
9
+ protocol: "http",
10
+ languages: ["typescript", "javascript"],
11
+ // createRoute wraps its config without changing it; the call IS the
12
+ // route object. Declared here because the wrapper's body lives in
13
+ // the library, where nobody can read it.
14
+ transparentWrappers: [
15
+ { callee: "createRoute", argument: 0, module: "@hono/zod-openapi" }
16
+ ],
17
+ // `new Hono()` and `new OpenAPIHono()` both register the same way.
18
+ // Sub-apps mounted with `app.route(prefix, sub)` compose the
19
+ // prefix into a route declared on the sub-app, following the sub-app
20
+ // through an import when it's declared in another file. A mount
21
+ // nested more than one level deep composes too, since the same
22
+ // index a mount resolves to is asked again for its own mount; a
23
+ // mount the resolution store can't follow to a concrete sub-app,
24
+ // or whose prefix isn't a string literal, leaves the route's path
25
+ // as written.
26
+ discovery: [
27
+ ...httpRouteDiscovery({
28
+ importModule: "hono",
29
+ importNames: ["Hono", "OpenAPIHono"],
30
+ methods: [
31
+ ".get",
32
+ ".post",
33
+ ".put",
34
+ ".delete",
35
+ ".patch",
36
+ ".options",
37
+ ".all"
38
+ ],
39
+ mount: { method: "route", prefixPosition: 0, targetPosition: 1 }
40
+ }),
41
+ ...httpRouteDiscovery({
42
+ importModule: "@hono/zod-openapi",
43
+ importNames: ["OpenAPIHono"],
44
+ methods: [
45
+ ".get",
46
+ ".post",
47
+ ".put",
48
+ ".delete",
49
+ ".patch",
50
+ ".options",
51
+ ".all"
52
+ ],
53
+ mount: { method: "route", prefixPosition: 0, targetPosition: 1 }
54
+ }),
55
+ {
56
+ // app.openapi(route, handler), where the route is a
57
+ // createRoute({ method, path, ... }) object that usually lives
58
+ // on a shared contract in another file. The fact layer follows
59
+ // the reference, and the route object has its own method and path on
60
+ // it.
61
+ kind: "handler",
62
+ match: {
63
+ type: "registrationCall",
64
+ importModule: "@hono/zod-openapi",
65
+ importName: "OpenAPIHono",
66
+ registrationChain: [".openapi"]
67
+ },
68
+ bindingExtraction: {
69
+ method: {
70
+ type: "fromArgumentProperty",
71
+ position: 0,
72
+ property: "method"
73
+ },
74
+ path: { type: "fromArgumentProperty", position: 0, property: "path" }
75
+ },
76
+ requiresImport: ["@hono/zod-openapi"]
77
+ }
78
+ ],
79
+ // The createRoute object registered alongside the handler declares
80
+ // the endpoint's responses, so a handler returning a status the
81
+ // route never declares is a contract finding, not a style choice.
82
+ contractReading: {
83
+ discovery: {
84
+ importModule: "@hono/zod-openapi",
85
+ importName: "OpenAPIHono",
86
+ registrationChain: [".openapi"]
87
+ },
88
+ responseExtraction: { property: "responses" },
89
+ methodProperty: "method",
90
+ pathProperty: "path",
91
+ endpoint: { from: "registrationArgument", position: 0 }
92
+ },
93
+ terminals: [
94
+ {
95
+ // c.json(body, status?)
96
+ kind: "response",
97
+ match: {
98
+ type: "parameterMethodCall",
99
+ parameterPosition: 0,
100
+ methodChain: ["json"]
101
+ },
102
+ extraction: {
103
+ statusCode: { from: "argument", position: 1 },
104
+ body: { from: "argument", position: 0 },
105
+ defaultStatusCode: 200
106
+ }
107
+ },
108
+ {
109
+ // c.text(body, status?)
110
+ kind: "response",
111
+ match: {
112
+ type: "parameterMethodCall",
113
+ parameterPosition: 0,
114
+ methodChain: ["text"]
115
+ },
116
+ extraction: {
117
+ statusCode: { from: "argument", position: 1 },
118
+ body: { from: "argument", position: 0 },
119
+ defaultStatusCode: 200
120
+ }
121
+ },
122
+ {
123
+ // c.body(data, status?)
124
+ kind: "response",
125
+ match: {
126
+ type: "parameterMethodCall",
127
+ parameterPosition: 0,
128
+ methodChain: ["body"]
129
+ },
130
+ extraction: {
131
+ statusCode: { from: "argument", position: 1 },
132
+ body: { from: "argument", position: 0 },
133
+ defaultStatusCode: 200
134
+ }
135
+ },
136
+ {
137
+ // c.redirect(location, status?). Hono defaults to 302.
138
+ kind: "response",
139
+ match: {
140
+ type: "parameterMethodCall",
141
+ parameterPosition: 0,
142
+ methodChain: ["redirect"]
143
+ },
144
+ extraction: {
145
+ statusCode: { from: "argument", position: 1 },
146
+ defaultStatusCode: 302
147
+ }
148
+ },
149
+ {
150
+ // c.notFound()
151
+ kind: "response",
152
+ match: {
153
+ type: "parameterMethodCall",
154
+ parameterPosition: 0,
155
+ methodChain: ["notFound"]
156
+ },
157
+ extraction: { defaultStatusCode: 404 }
158
+ },
159
+ {
160
+ // throw new HTTPException(status, { message }); hono sends the
161
+ // exception's status as the wire response.
162
+ kind: "throw",
163
+ match: { type: "throwExpression" },
164
+ extraction: {
165
+ statusCode: {
166
+ from: "constructor",
167
+ codes: HTTP_EXCEPTION_CODES
168
+ }
169
+ },
170
+ producesResponse: true
171
+ }
172
+ ],
173
+ // One parameter, the context, carrying the request and the response
174
+ // methods together.
175
+ inputMapping: {
176
+ type: "positionalParams",
177
+ params: [{ position: 0, role: "context" }]
178
+ }
179
+ };
180
+ }
181
+ var index_default = honoFramework;
182
+ export {
183
+ index_default as default
184
+ };
@@ -0,0 +1 @@
1
+ export { default } from '@suss/framework-mongoose';