@suss/packs 0.33.0 → 0.34.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/README.md +10 -11
  2. package/dist/activerecord.d.ts +7 -0
  3. package/dist/activerecord.js +34 -4
  4. package/dist/apollo-client.js +26 -39
  5. package/dist/apollo.js +12 -20
  6. package/dist/aws-dynamodb.js +4 -4
  7. package/dist/aws-eventbridge.js +3 -3
  8. package/dist/aws-lambda.js +31 -54
  9. package/dist/aws-s3.js +1 -1
  10. package/dist/aws-secrets-manager.js +1 -1
  11. package/dist/aws-sns.js +2 -2
  12. package/dist/aws-sqs.js +20 -11
  13. package/dist/aws-ssm.js +1 -1
  14. package/dist/axios.js +13 -27
  15. package/dist/bigquery-python.js +3 -3
  16. package/dist/bigquery.js +1 -1
  17. package/dist/{chunk-NYWZHQBJ.js → chunk-GK4BILHB.js} +8 -9
  18. package/dist/cloudflare-workers.js +26 -35
  19. package/dist/drizzle.js +15 -20
  20. package/dist/express.js +3 -6
  21. package/dist/fabrication.d.ts +1 -0
  22. package/dist/fabrication.js +36 -0
  23. package/dist/factory-bot.d.ts +1 -0
  24. package/dist/factory-bot.js +36 -0
  25. package/dist/faraday.js +4 -5
  26. package/dist/fastapi.js +21 -5
  27. package/dist/fastify.js +10 -14
  28. package/dist/fetch.js +3 -4
  29. package/dist/flask-restx.js +19 -12
  30. package/dist/gcs.js +1 -1
  31. package/dist/graphql-ruby.js +20 -16
  32. package/dist/hono.js +17 -27
  33. package/dist/httpx.js +3 -5
  34. package/dist/minitest.d.ts +1 -0
  35. package/dist/minitest.js +59 -0
  36. package/dist/mongoose.js +7 -7
  37. package/dist/nestjs-graphql.js +14 -25
  38. package/dist/nestjs-microservices.js +9 -10
  39. package/dist/nestjs-rest.js +42 -22
  40. package/dist/net-http.js +5 -6
  41. package/dist/nextjs.js +16 -17
  42. package/dist/node.js +144 -28
  43. package/dist/package-exports.js +1 -1
  44. package/dist/pg.js +3 -2
  45. package/dist/prisma.js +281 -48
  46. package/dist/pytest.d.ts +1 -0
  47. package/dist/pytest.js +81 -0
  48. package/dist/rails.js +46 -27
  49. package/dist/react-query.js +1 -1
  50. package/dist/react-router.js +21 -48
  51. package/dist/react.js +14 -5
  52. package/dist/redis.js +1 -1
  53. package/dist/requests.js +4 -5
  54. package/dist/rspec.d.ts +1 -0
  55. package/dist/rspec.js +135 -0
  56. package/dist/sqlalchemy.js +1 -1
  57. package/dist/sqlmodel.js +7 -8
  58. package/dist/ts-rest.js +6 -8
  59. package/dist/typeorm.d.ts +1 -0
  60. package/dist/typeorm.js +291 -0
  61. package/dist/vitest.d.ts +1 -0
  62. package/dist/vitest.js +64 -0
  63. package/package.json +47 -11
package/README.md CHANGED
@@ -8,24 +8,23 @@ Every pack suss ships, as one package with a subpath per pack.
8
8
  npm install --save-dev @suss/packs
9
9
  ```
10
10
 
11
- A pack is reached by its own subpath, which is the name `suss extract -f`
12
- takes:
11
+ Each pack has its own subpath, and the subpath is the name that
12
+ `suss extract -f` takes:
13
13
 
14
14
  ```ts
15
15
  import mongoose from "@suss/packs/mongoose";
16
16
  import express from "@suss/packs/express";
17
17
  ```
18
18
 
19
- The CLI resolves `-f mongoose` to `@suss/packs/mongoose` on its own, so
20
- running `suss` needs no import.
19
+ The CLI resolves `-f mongoose` to `@suss/packs/mongoose` itself, so you
20
+ do not need an import to run `suss`.
21
21
 
22
22
  ## Why one package
23
23
 
24
- npm exchanges a publishing credential against a trusted publisher that
25
- each package configures for itself, by hand, on npmjs.com. One package
26
- means that happens once rather than once per pack, so adding a pack is a
27
- directory and a line in the exports map.
24
+ npm issues a publishing credential through a trusted publisher, and each
25
+ package has to configure its trusted publisher by hand on npmjs.com.
26
+ With one package that setup happens once for every pack. Adding a pack
27
+ takes a directory and a line in the exports map.
28
28
 
29
- The packs have no dependencies outside `@suss/*`, and all of them
30
- together come to about 1.2 MB, so there is nothing to save by splitting
31
- them up.
29
+ The packs have no dependencies outside `@suss/*`, and together they come
30
+ to about 1.2 MB, so splitting them up would save nothing.
@@ -17,6 +17,8 @@ import '@suss/framework-bigquery';
17
17
  import '@suss/framework-cloudflare-workers';
18
18
  import '@suss/framework-drizzle';
19
19
  import '@suss/framework-express';
20
+ import '@suss/framework-fabrication';
21
+ import '@suss/framework-factory-bot';
20
22
  import '@suss/client-faraday';
21
23
  import '@suss/framework-fastapi';
22
24
  import '@suss/framework-fastify';
@@ -26,6 +28,7 @@ import '@suss/framework-gcs';
26
28
  import '@suss/framework-graphql-ruby';
27
29
  import '@suss/framework-hono';
28
30
  import '@suss/client-httpx';
31
+ import '@suss/framework-minitest';
29
32
  import '@suss/framework-mongoose';
30
33
  import '@suss/framework-nestjs-graphql';
31
34
  import '@suss/framework-nestjs-microservices';
@@ -37,13 +40,17 @@ import '@suss/framework-package-exports';
37
40
  import '@suss/framework-pg-ruby';
38
41
  import '@suss/framework-pg';
39
42
  import '@suss/framework-prisma';
43
+ import '@suss/framework-pytest';
40
44
  import '@suss/framework-rails';
41
45
  import '@suss/framework-react-query';
42
46
  import '@suss/framework-react-router';
43
47
  import '@suss/framework-react';
44
48
  import '@suss/framework-redis';
45
49
  import '@suss/client-requests';
50
+ import '@suss/framework-rspec';
46
51
  import '@suss/framework-sqlalchemy';
47
52
  import '@suss/framework-sqlmodel';
48
53
  import '@suss/framework-ts-rest';
54
+ import '@suss/framework-typeorm';
55
+ import '@suss/framework-vitest';
49
56
  import '@suss/framework-zustand';
@@ -1,10 +1,38 @@
1
1
  // ../framework/activerecord/dist/index.js
2
2
  import { z } from "zod";
3
3
  import { storageSystemOption } from "@suss/extractor";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ var STORAGE_SYSTEM_OF_ADAPTER = {
7
+ postgresql: "postgresql",
8
+ mysql2: "mysql",
9
+ trilogy: "mysql",
10
+ sqlite3: "sqlite"
11
+ };
12
+ function storageSystemFromDatabaseYml(projectRoot) {
13
+ const file = path.join(projectRoot, "config", "database.yml");
14
+ if (!fs.existsSync(file)) {
15
+ return null;
16
+ }
17
+ const systems = /* @__PURE__ */ new Set();
18
+ for (const match of fs.readFileSync(file, "utf8").matchAll(/^\s*adapter:\s*(.*)$/gm)) {
19
+ const system = STORAGE_SYSTEM_OF_ADAPTER[adapterName(match[1] ?? "")];
20
+ if (system === void 0) {
21
+ return null;
22
+ }
23
+ systems.add(system);
24
+ }
25
+ const [only] = systems;
26
+ return systems.size === 1 && only !== void 0 ? { storageSystem: only } : null;
27
+ }
28
+ function adapterName(written) {
29
+ const value = written.replace(/\s+#.*$/, "").trim();
30
+ return /^(["'])(.*)\1$/.exec(value)?.[2] ?? value;
31
+ }
4
32
  var optionsSchema = z.object({
5
33
  /**
6
- * Which database is behind the connection. ActiveRecord talks to all of
7
- * them and database.yml says which, so the project supplies this.
34
+ * The database behind the connection. ActiveRecord works with several,
35
+ * and database.yml picks one, so the project has to supply it.
8
36
  */
9
37
  storageSystem: storageSystemOption
10
38
  }).strict();
@@ -196,6 +224,7 @@ function activeRecordStorage(options) {
196
224
  plural: ["has_many", "has_and_belongs_to_many"],
197
225
  classNameKeyword: "class_name"
198
226
  },
227
+ scopes: ["scope"],
199
228
  storageSystem: options.storageSystem
200
229
  }
201
230
  ];
@@ -233,12 +262,13 @@ var declares = {
233
262
  { ecosystem: "rubygems", name: "activerecord" },
234
263
  { ecosystem: "rubygems", name: "rails" }
235
264
  ],
236
- reads: "ActiveRecord calls (Ruby): a call matches when its method is one ActiveRecord defines as a read or a write and the class behind its receiver reaches `ActiveRecord::Base`, following what each class extends through the project. Statements the project wrote itself are read for the tables they touch, whether they went through `find_by_sql` and `count_by_sql` or through the connection. A write also runs the model's callbacks, and what they reach lands on the body that did the write.",
265
+ reads: "ActiveRecord calls (Ruby): a call matches when its method is one ActiveRecord defines as a read or a write and the class behind its receiver reaches `ActiveRecord::Base`, following what each class extends through the project. Statements the project wrote itself are read for the tables they touch, whether they went through `find_by_sql` and `count_by_sql` or through the connection. A write also runs the model's callbacks, and what they reach is recorded on the body that did the write.",
237
266
  configuration: {
238
267
  file: "suss.activerecord.json",
239
268
  example: { storageSystem: "postgresql" },
240
269
  required: true,
241
- why: "which database is behind the connection: postgresql, mysql, or sqlite. ActiveRecord talks to all of them and database.yml settles which, so the pack cannot."
270
+ why: "which database is behind the connection: postgresql, mysql, or sqlite. ActiveRecord talks to all of them and database.yml settles which, so the pack cannot.",
271
+ readFromProject: storageSystemFromDatabaseYml
242
272
  }
243
273
  };
244
274
  var index_default = activeRecordFramework;
@@ -11,20 +11,18 @@ var DOCUMENT_HOOKS = [
11
11
  ];
12
12
  var optionsSchema = z.object({
13
13
  /**
14
- * Which service each client talks to, keyed by the endpoint the
15
- * client is constructed with: the uri string itself, or the written
16
- * expression when the value is computed (an env read like
17
- * `import.meta.env.VITE_GRAPHQL_URL`). The value is the provider
18
- * workspace name. One line per client separates two GraphQL services
19
- * that share root field names.
14
+ * The provider workspace each client talks to, keyed by the endpoint
15
+ * the client is constructed with. The key is the uri string, or the
16
+ * expression as written when the value is computed, such as
17
+ * `import.meta.env.VITE_GRAPHQL_URL`. One entry per client keeps
18
+ * apart two GraphQL services that share root field names.
20
19
  */
21
20
  clients: z.record(z.string(), z.string()).optional(),
22
21
  /**
23
- * Which service the operations in a set of files talk to, for a
24
- * frontend that uses two clients. A hook call does not say which
25
- * client it goes through, so these globs decide by file: an
26
- * operation whose file matches gets the entry's workspace. First
27
- * matching entry wins.
22
+ * The workspace for operations in a set of files, for a frontend
23
+ * that uses two clients. A hook call does not show which client it
24
+ * goes through, so the pack decides by file. The first entry whose
25
+ * globs match the operation's file wins.
28
26
  */
29
27
  operationScopes: z.array(
30
28
  z.object({ files: z.array(z.string()), workspace: z.string() }).strict()
@@ -34,10 +32,8 @@ function apolloClientPack(options = {}) {
34
32
  return {
35
33
  name: "apollo-client",
36
34
  languages: ["typescript", "javascript"],
37
- // Apollo Client sits over HTTP (or WebSocket for subscriptions;
38
- // subscriptions reported separately via operationType but the
39
- // transport tag stays "http" for v0, the Apollo HttpLink is the
40
- // default path).
35
+ // Subscriptions can run over WebSocket, but operationType already
36
+ // records them, and HttpLink is Apollo's default transport.
41
37
  protocol: "http",
42
38
  discovery: [
43
39
  {
@@ -47,15 +43,11 @@ function apolloClientPack(options = {}) {
47
43
  importModule: "@apollo/client",
48
44
  hooks: [...DOCUMENT_HOOKS]
49
45
  },
50
- // Prefix match: covers `@apollo/client` AND `@apollo/client/react`
51
- // AND `@apollo/client/...` sub-paths in one go. The `importModule`
52
- // on the match itself stays exact-match for discovery's own
53
- // gating.
46
+ // requiresImport matches by prefix, so it also admits
47
+ // `@apollo/client/react`. importModule above matches exactly.
54
48
  requiresImport: ["@apollo/client"]
55
49
  },
56
- // Newer re-exports split per-runtime ("@apollo/client/react").
57
- // Apollo's current stable major is one path; the react-only
58
- // export is here to handle projects that pin per-runtime.
50
+ // For projects that import the hooks from the React entry point.
59
51
  {
60
52
  kind: "client",
61
53
  match: {
@@ -65,13 +57,9 @@ function apolloClientPack(options = {}) {
65
57
  },
66
58
  requiresImport: ["@apollo/client"]
67
59
  },
68
- // Imperative client: covers server-side data fetching,
69
- // Next.js getServerSideProps, Node scripts, anywhere calling
70
- // `client.query(...)` / `client.mutate(...)` directly rather
71
- // than via a hook. The client identifier can be any name,
72
- // we gate on the `ApolloClient` constructor being imported
73
- // so random `.query()` method calls in unrelated code don't
74
- // light up.
60
+ // `client.query(...)` outside a hook, as in server-side fetching.
61
+ // The client variable can have any name, so the match requires an
62
+ // `ApolloClient` import to skip unrelated `.query()` calls.
75
63
  {
76
64
  kind: "client",
77
65
  match: {
@@ -99,16 +87,16 @@ function apolloClientPack(options = {}) {
99
87
  requiresImport: ["@apollo/client"]
100
88
  }
101
89
  ],
102
- // The constructions an operation's calls go through. `uri` is
103
- // Apollo's own option, on the client shorthand and on the links.
90
+ // The endpoint an operation goes to comes from the `uri` option on
91
+ // whichever of these built its client.
104
92
  graphqlClients: [
105
93
  {
106
94
  importModule: "@apollo/client",
107
95
  importName: "ApolloClient",
108
96
  uriProperty: "uri",
109
- // `createFragmentRegistry` hands the registry to the cache's
110
- // `fragments` option; a document can then spread a fragment it
111
- // does not define and the client fills it in at run time.
97
+ // With a registry from `createFragmentRegistry` on the cache, a
98
+ // document can spread a fragment it does not define, and the
99
+ // client fills it in at run time.
112
100
  fragmentRegistry: {
113
101
  cacheProperty: "cache",
114
102
  cacheConstructor: {
@@ -144,10 +132,9 @@ function apolloClientPack(options = {}) {
144
132
  }
145
133
  ],
146
134
  inputMapping: {
147
- // Apollo hooks take no positional params we track, the surface
148
- // inputs are the operation-header `$variables`, which the adapter
149
- // reads from the resolved document and stamps onto the summary
150
- // directly (role "variable"), independent of this mapping.
135
+ // The inputs are the `$variables` in the operation header. The
136
+ // adapter reads them from the resolved document, so no positional
137
+ // parameter is mapped here.
151
138
  type: "positionalParams",
152
139
  params: []
153
140
  }
@@ -157,7 +144,7 @@ var declares = {
157
144
  kind: "client",
158
145
  package: "@suss/client-apollo",
159
146
  dependencies: [{ ecosystem: "npm", name: "@apollo/client" }],
160
- reads: "`@apollo/client` hooks + imperative `client.query`."
147
+ reads: "`@apollo/client` hooks and imperative `client.query` calls."
161
148
  };
162
149
  var index_default = apolloClientPack;
163
150
  export {
package/dist/apollo.js CHANGED
@@ -3,9 +3,8 @@ function apolloFramework() {
3
3
  return {
4
4
  name: "apollo",
5
5
  languages: ["typescript", "javascript"],
6
- // Apollo Server runs over HTTP; GraphQL semantics are discriminated
7
- // at the resolver level (decision: resolver-level, not field-level)
8
- // and surfaced via `graphql-resolver` semantics in the binding.
6
+ // Apollo Server runs over HTTP. The GraphQL type and field are set
7
+ // per resolver, on the `graphql-resolver` binding.
9
8
  protocol: "http",
10
9
  discovery: [
11
10
  {
@@ -14,14 +13,12 @@ function apolloFramework() {
14
13
  type: "resolverMap",
15
14
  importModule: "@apollo/server",
16
15
  importName: "ApolloServer",
17
- // Apollo v4 convention: the config key is `resolvers`.
18
16
  mapProperty: "resolvers"
19
17
  },
20
18
  requiresImport: ["@apollo/server"]
21
19
  },
22
- // Pre-v4 path: `import { ApolloServer } from "apollo-server"` /
23
- // `"apollo-server-express"` / similar. Same shape, different
24
- // module. Covers the bulk of real-world Apollo code before v4.
20
+ // Apollo before v4 exported the same `ApolloServer` from
21
+ // `apollo-server` and `apollo-server-express`.
25
22
  {
26
23
  kind: "resolver",
27
24
  match: {
@@ -44,10 +41,8 @@ function apolloFramework() {
44
41
  }
45
42
  ],
46
43
  terminals: [
47
- // Resolvers return a value; errors propagate as thrown
48
- // exceptions (Apollo maps them to `errors[]` on the outgoing
49
- // response). No framework-specific response-call shape to
50
- // match; return + throw cover the observable behavior.
44
+ // A resolver has no response call. It returns a value or throws,
45
+ // and Apollo turns a thrown error into `errors[]`.
51
46
  {
52
47
  kind: "return",
53
48
  match: { type: "returnStatement" },
@@ -58,21 +53,18 @@ function apolloFramework() {
58
53
  match: { type: "throwExpression" },
59
54
  extraction: {}
60
55
  },
61
- // Resolvers often fall off the end without an explicit return,
62
- // a type resolver can delegate to the default-resolver behavior
63
- // by returning nothing. Keep the default transition so
64
- // `transitions: []` isn't the shape we ship.
56
+ // A resolver that returns nothing hands off to Apollo's default
57
+ // resolver. Without this terminal it would come out with no
58
+ // transitions.
65
59
  {
66
60
  kind: "return",
67
61
  match: { type: "functionFallthrough" },
68
62
  extraction: {}
69
63
  }
70
64
  ],
71
- // Apollo resolvers have a fixed 4-positional shape:
72
- // (parent, args, context, info) => ...
73
- // Most resolvers ignore `parent` / `info`. We surface all four by
74
- // role so downstream checks can distinguish "uses args" from
75
- // "delegates to context" etc.
65
+ // All four positions get a role, even though most resolvers ignore
66
+ // `parent` and `info`, so a check can tell a resolver that reads
67
+ // `args` from one that hands off to `context`.
76
68
  inputMapping: {
77
69
  type: "positionalParams",
78
70
  params: [
@@ -214,9 +214,9 @@ function updateExpressionAttributes(expression, names) {
214
214
  }
215
215
  var optionsSchema = z.object({
216
216
  /**
217
- * Further modules whose presence makes a file worth reading. A helper
218
- * imported by a relative path gives the gate nothing to match on; the
219
- * signing library that helper imports gives it something.
217
+ * More modules that get a file read when it imports them. A relative
218
+ * import of a helper matches no module, so the usual entry is the
219
+ * signing library the helper imports.
220
220
  */
221
221
  requiresImport: z.array(z.string()).optional()
222
222
  }).strict();
@@ -335,7 +335,7 @@ var declares = {
335
335
  { ecosystem: "npm", name: "@aws-sdk/lib-dynamodb" },
336
336
  { ecosystem: "npm", name: "@aws-sdk/client-dynamodb" }
337
337
  ],
338
- reads: "AWS SDK v3 DynamoDB calls, emits storage-access interactions."
338
+ reads: "AWS SDK v3 DynamoDB calls. Each one becomes a storage-access interaction."
339
339
  };
340
340
  var index_default = dynamoFramework;
341
341
  export {
@@ -7,8 +7,8 @@ import { constructedFrom, messageSends, pack } from "@suss/recognize";
7
7
  var EVENTBRIDGE = "@aws-sdk/client-eventbridge";
8
8
  var optionsSchema = z.object({
9
9
  /**
10
- * Publishers this project emits through. Each one adds a recognizer
11
- * and widens the import gate to that publisher's module.
10
+ * Each publisher adds a recognizer, and the pack also reads files that
11
+ * import the publisher's module.
12
12
  */
13
13
  producers: z.array(configuredCallOption).optional()
14
14
  }).strict();
@@ -92,7 +92,7 @@ var declares = {
92
92
  kind: "effects",
93
93
  package: "@suss/framework-aws-eventbridge",
94
94
  dependencies: [{ ecosystem: "npm", name: "@aws-sdk/client-eventbridge" }],
95
- reads: "AWS EventBridge `PutEvents` producer calls, emits message-bus interactions."
95
+ reads: "AWS EventBridge `PutEvents` producer calls. Each one becomes a message-bus interaction."
96
96
  };
97
97
  var index_default = eventBridgeFramework;
98
98
  export {
@@ -146,9 +146,9 @@ function templatesForFiles(files) {
146
146
  }
147
147
  var HTTP_TERMINALS = [
148
148
  {
149
- // `return { statusCode, body, headers? }`, written at the return site or
150
- // built by a helper the adapter follows into. `body` contains the
151
- // serialized payload, so unwrap `JSON.stringify(x)` to the shape of `x`.
149
+ // `return { statusCode, body, headers? }`, at the return or in a helper
150
+ // the adapter follows. `body` contains the serialized payload, so
151
+ // `JSON.stringify(x)` is unwrapped to the shape of `x`.
152
152
  kind: "response",
153
153
  match: { type: "returnShape", requiredProperties: ["statusCode"] },
154
154
  extraction: {
@@ -157,9 +157,9 @@ var HTTP_TERMINALS = [
157
157
  }
158
158
  },
159
159
  {
160
- // `return { batchItemFailures }`, which is how a consumer tells Lambda
161
- // which records to retry and which to drop. Lambda defines this shape, so
162
- // the pack can match on it, the same way it matches the envelope above.
160
+ // `return { batchItemFailures }` makes Lambda retry the records it
161
+ // lists. Lambda defines this shape, so the pack can match on it the
162
+ // same way it matches the envelope above.
163
163
  kind: "return",
164
164
  match: {
165
165
  type: "returnShape",
@@ -168,9 +168,8 @@ var HTTP_TERMINALS = [
168
168
  extraction: {}
169
169
  },
170
170
  {
171
- // `throw new SomeError(...)`. An uncaught throw becomes a
172
- // throw-output transition; API Gateway maps it to a 5xx, but the
173
- // specific status is the platform's, not the handler's.
171
+ // An uncaught throw becomes a throw-output transition. API Gateway
172
+ // turns it into a 5xx, and the platform picks which one.
174
173
  kind: "throw",
175
174
  match: { type: "throwExpression" },
176
175
  extraction: {}
@@ -184,10 +183,9 @@ var NON_HTTP_TERMINALS = [
184
183
  extraction: {}
185
184
  },
186
185
  {
187
- // A queue consumer acknowledges a batch by not throwing: it processes the
188
- // records, falls off the end, and Lambda reads the absence of an error as
189
- // the ack. Without this the handler has no terminal, so it gets no
190
- // transition, and everything it does goes with it.
186
+ // A queue consumer acknowledges a batch by returning without an error.
187
+ // Without this pattern the handler has no terminal, so it gets no
188
+ // transition and everything it does is lost with it.
191
189
  kind: "return",
192
190
  match: { type: "functionFallthrough" },
193
191
  extraction: {}
@@ -367,45 +365,25 @@ function awsLambdaFramework(_options = {}) {
367
365
  return {
368
366
  name: "aws-lambda",
369
367
  protocol: "http",
370
- // Sentry's wrapper is a library call whose body the adapter cannot
371
- // read, so the pack states the judgment: the handler is argument 0.
372
- // Project-local wrappers need no declaration; the adapter derives
373
- // those by reading the factory body.
368
+ // The adapter cannot read Sentry's wrapper inside the library, so the
369
+ // pack declares that the handler is argument 0. A wrapper written in
370
+ // the project needs no entry, because the adapter reads its body.
374
371
  transparentWrappers: [
375
- {
376
- callee: "Sentry.wrapHandler",
377
- argument: 0,
378
- module: "@sentry/aws-serverless"
379
- }
372
+ { module: "@sentry/aws-serverless", name: "wrapHandler", argument: 0 }
380
373
  ],
381
374
  languages: ["typescript", "javascript"],
382
- // No data-driven discovery: routing lives in the SAM/CFN template,
383
- // not in code. The callback resolves handlers against the template.
375
+ // The routing is in the template, so the callback finds handlers
376
+ // there and the pattern list stays empty.
384
377
  discovery: [],
385
378
  discoverUnits: awsLambdaDiscovery(),
386
- // Everything this pack discovers comes off the template, so the
387
- // cache has to key on it the way it keys on a pack's config.
379
+ // Discovery reads the templates, so they go into the cache key and an
380
+ // edited template makes the next run read the project again.
388
381
  discoveryInputs: templatesForFiles,
389
- // No import gate, on purpose.
390
- //
391
- // A TypeScript handler writes `import type { APIGatewayProxyHandlerV2 }
392
- // from "aws-lambda"`, which TypeScript resolves to
393
- // `@types/aws-lambda`, to annotate its export. A JavaScript handler
394
- // has nothing to annotate and writes no such import. Gating
395
- // discovery on it therefore meant "TypeScript handlers that bothered
396
- // to annotate", and every JavaScript Lambda service extracted
397
- // nothing.
398
- //
399
- // The SAM template is the gate instead, and a better one, because it
400
- // says which handlers outright. `discoverUnits` looks each file up in
401
- // the template reachable from it, and a directory with no template
402
- // resolves to null once and stays memoized.
403
- // Route units extract against these. Non-HTTP accounting units get their
404
- // own wider list, attached per unit by the discovery callback.
382
+ // No import gate: a JavaScript handler imports nothing from
383
+ // `aws-lambda`, so the template acts as the gate. See the README.
384
+ // A unit that is not HTTP gets a longer list from the discovery
385
+ // callback in place of this one.
405
386
  terminals: HTTP_TERMINALS,
406
- // Lambda's handler signature is `(event, context, callback?)`. The
407
- // HTTP request data (path params, query, body) lives on `event`;
408
- // decomposing it into typed inputs is a follow-up.
409
387
  inputMapping: {
410
388
  type: "positionalParams",
411
389
  params: [
@@ -413,9 +391,9 @@ function awsLambdaFramework(_options = {}) {
413
391
  { position: 1, role: "context" }
414
392
  ]
415
393
  },
416
- // A proxy integration hands the handler API Gateway's event. The
417
- // body arrives on it as a string the handler parses, so a read of
418
- // it says the body was taken whole and never which field.
394
+ // A proxy integration passes the handler API Gateway's event, with the
395
+ // body as a string the handler parses. A read of the body records that
396
+ // the handler took all of it, with no field name.
419
397
  requestSpelling: {
420
398
  headers: { path: ["event", "headers"], saysWhichField: true },
421
399
  query: {
@@ -425,17 +403,16 @@ function awsLambdaFramework(_options = {}) {
425
403
  params: { path: ["event", "pathParameters"], saysWhichField: true },
426
404
  body: { path: ["event", "body"], saysWhichField: false }
427
405
  },
428
- // The powertools read their configuration from inside node_modules,
429
- // so a template that declares these has a reader no walk ever sees.
406
+ // Powertools reads these variables from inside node_modules, where no
407
+ // walk over the project goes, so without this entry they look unread.
430
408
  libraryEnvVars: [
431
409
  {
432
410
  module: "@aws-lambda-powertools/",
433
411
  prefixes: ["POWERTOOLS_"]
434
412
  }
435
413
  ],
436
- // Still no pack-level `requiresImport`: it would gate
437
- // `discoverUnits` as well, and each declaration checks the SDK its
438
- // command came from anyway.
414
+ // A pack-level `requiresImport` would gate `discoverUnits` too. Each
415
+ // declaration already checks which SDK its command class came from.
439
416
  invocationRecognizers: invokes.map(
440
417
  (match) => compile(match.declared, "@suss/framework-aws-lambda")
441
418
  ),
@@ -446,7 +423,7 @@ var declares = {
446
423
  kind: "framework",
447
424
  package: "@suss/framework-aws-lambda",
448
425
  dependencies: [{ ecosystem: "npm", name: "@types/aws-lambda" }],
449
- reads: "AWS Lambda HTTP handlers, paired to SAM / CloudFormation-declared routes."
426
+ reads: "AWS Lambda HTTP handlers, paired with the routes a SAM or CloudFormation template declares."
450
427
  };
451
428
  var index_default = awsLambdaFramework;
452
429
  export {
package/dist/aws-s3.js CHANGED
@@ -38,7 +38,7 @@ var declares = {
38
38
  kind: "effects",
39
39
  package: "@suss/framework-aws-s3",
40
40
  dependencies: [{ ecosystem: "npm", name: "@aws-sdk/client-s3" }],
41
- reads: "AWS SDK v3 S3 object calls, emits storage-access interactions."
41
+ reads: "AWS SDK v3 S3 object calls. Each one becomes a storage-access interaction."
42
42
  };
43
43
  var index_default = s3Framework;
44
44
  export {
@@ -32,7 +32,7 @@ var declares = {
32
32
  kind: "effects",
33
33
  package: "@suss/framework-aws-secrets-manager",
34
34
  dependencies: [{ ecosystem: "npm", name: "@aws-sdk/client-secrets-manager" }],
35
- reads: "AWS Secrets Manager calls, emits storage-access interactions against the secret."
35
+ reads: "AWS Secrets Manager calls. Each one becomes a storage-access interaction on the secret."
36
36
  };
37
37
  var index_default = secretsManagerFramework;
38
38
  export {
package/dist/aws-sns.js CHANGED
@@ -30,7 +30,7 @@ var PUBLISH_BATCH = messageSends({
30
30
  wire: "aws.sns",
31
31
  client: constructedFrom(SNS),
32
32
  messages: { each: "in", property: "PublishBatchRequestEntries" },
33
- // A batch states the topic once beside the list of messages.
33
+ // The topic is on the command input, once, beside the list of messages.
34
34
  channel: [{ property: TOPIC, on: "theInput" }],
35
35
  routingKey: "Subject",
36
36
  body: "Message"
@@ -48,7 +48,7 @@ var declares = {
48
48
  kind: "effects",
49
49
  package: "@suss/framework-aws-sns",
50
50
  dependencies: [{ ecosystem: "npm", name: "@aws-sdk/client-sns" }],
51
- reads: "AWS SDK v3 SNS `Publish` and `PublishBatch` calls, emits message-send interactions on the topic."
51
+ reads: "AWS SDK v3 SNS `Publish` and `PublishBatch` calls. Each one becomes a message-send interaction on the topic."
52
52
  };
53
53
  var index_default = snsFramework;
54
54
  export {