@suss/contract-wrangler 0.9.0 → 0.10.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/README.md CHANGED
@@ -25,10 +25,14 @@ queue = "greeting-events"
25
25
  | --- | --- |
26
26
  | `name`, `main` | the deployable unit and the code it runs |
27
27
  | `[vars]` | the Worker's runtime configuration, names and values |
28
- | `[[kv_namespaces]]`, `[[r2_buckets]]`, `[[d1_databases]]` | one store each |
28
+ | `[[kv_namespaces]]`, `[[r2_buckets]]`, `[[d1_databases]]` | one store each, under the binding name the code spells |
29
29
  | `[[queues.producers]]`, `[[queues.consumers]]` | one channel each, on `cloudflare-queues` |
30
30
  | `[env.<name>]` | the same Worker deployed again, with the top-level document as its default |
31
31
 
32
+ A store's container is the binding name, `SESSIONS`, because that is what an access in the Worker spells (`env.SESSIONS.get(...)`), and `@suss/framework-cloudflare-workers` records the same name on the code side, so the storage check pairs the two. The resource's own name, the KV namespace id or the bucket name, goes on the summary as `physicalTable`, the same split a Prisma model has between the model and the table it maps to.
33
+
34
+ Binding names are also listed on the runtime-config contract, beside the `[vars]` names: a binding is a property of the same `env` object, so a Worker that reads `env.AUDIT_KV` without a binding block for it gets the same finding as a read of a variable nobody set.
35
+
32
36
  ## The values, not only the names
33
37
 
34
38
  A runtime-config contract usually records which variables a runtime supplies, and that is enough to say whether code reads one nobody set. A Worker needs more, because it addresses its stores through a variable:
package/dist/index.cjs CHANGED
@@ -79,9 +79,9 @@ function storeSummaries(document, context) {
79
79
  return summaries;
80
80
  }
81
81
  function storeSummary(store, entry, context) {
82
- const container = stringOf(entry[store.nameKey]);
82
+ const resourceName = stringOf(entry[store.nameKey]);
83
83
  const boundAs = stringOf(entry.binding);
84
- if (container === null) {
84
+ if (resourceName === null) {
85
85
  return null;
86
86
  }
87
87
  return {
@@ -92,13 +92,15 @@ function storeSummary(store, entry, context) {
92
92
  exportName: null
93
93
  },
94
94
  identity: {
95
- name: `${store.block}.${boundAs ?? container}`,
95
+ name: `${store.block}.${boundAs ?? resourceName}`,
96
96
  exportPath: null,
97
97
  boundaryBinding: (0, import_behavioral_ir.storageBinding)({
98
98
  recognition: RECOGNITION,
99
99
  storageSystem: store.storageSystem,
100
100
  scope: "default",
101
- container,
101
+ // The binding name is what an access in the Worker spells, so
102
+ // it is the name the storage check pairs on.
103
+ container: boundAs ?? resourceName,
102
104
  accessPath: null
103
105
  })
104
106
  },
@@ -107,11 +109,42 @@ function storeSummary(store, entry, context) {
107
109
  gaps: [],
108
110
  confidence: { source: "declared", level: "high" },
109
111
  metadata: {
110
- storageContract: { fieldSet: store.fieldSet, physicalTable: container },
112
+ storageContract: {
113
+ fieldSet: store.fieldSet,
114
+ physicalTable: resourceName
115
+ },
111
116
  ...boundAs === null ? {} : { wrangler: { binding: boundAs } }
112
117
  }
113
118
  };
114
119
  }
120
+ var BINDING_BLOCKS = [
121
+ "kv_namespaces",
122
+ "r2_buckets",
123
+ "d1_databases",
124
+ "queues"
125
+ ];
126
+ function bindingNames(document) {
127
+ const names = [];
128
+ for (const store of STORES) {
129
+ for (const entry of blockEntries(document[store.block])) {
130
+ const boundAs = stringOf(entry.binding);
131
+ if (boundAs !== null) {
132
+ names.push(boundAs);
133
+ }
134
+ }
135
+ }
136
+ const queues = asRecord(document.queues);
137
+ for (const entry of blockEntries(queues?.producers)) {
138
+ const boundAs = stringOf(entry.binding);
139
+ if (boundAs !== null) {
140
+ names.push(boundAs);
141
+ }
142
+ }
143
+ return names;
144
+ }
145
+ function asRecord(raw) {
146
+ return raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
147
+ }
115
148
  function queueSummaries(document, context) {
116
149
  const queues = document.queues;
117
150
  if (queues === null || typeof queues !== "object") {
@@ -248,10 +281,22 @@ function environmentDocuments(document) {
248
281
  return deployments;
249
282
  }
250
283
  function inheritedNames(document, overrides) {
251
- if (overrides.vars !== void 0) {
252
- return /* @__PURE__ */ new Set();
284
+ const names = /* @__PURE__ */ new Set();
285
+ if (overrides.vars === void 0) {
286
+ for (const name of Object.keys(varsOf(document))) {
287
+ names.add(name);
288
+ }
289
+ }
290
+ const kept = {};
291
+ for (const block of BINDING_BLOCKS) {
292
+ if (overrides[block] === void 0) {
293
+ kept[block] = document[block];
294
+ }
295
+ }
296
+ for (const name of bindingNames(kept)) {
297
+ names.add(name);
253
298
  }
254
- return new Set(Object.keys(varsOf(document)));
299
+ return names;
255
300
  }
256
301
  function nameOf(document) {
257
302
  return typeof document.name === "string" && document.name.length > 0 ? document.name : null;
@@ -262,7 +307,9 @@ function varsOf(document) {
262
307
  }
263
308
  function runtimeConfigSummary(deployment, context) {
264
309
  const vars = varsOf(deployment.merged);
265
- const names = Object.keys(vars).sort();
310
+ const names = [
311
+ .../* @__PURE__ */ new Set([...Object.keys(vars), ...bindingNames(deployment.merged)])
312
+ ].sort();
266
313
  const sources = {};
267
314
  const values = {};
268
315
  for (const name of names) {
package/dist/index.d.cts CHANGED
@@ -57,10 +57,11 @@ declare function loadConfigurationDocument(file: string): WranglerDocument;
57
57
  *
58
58
  * Every binding block in a Wrangler document has the same two halves:
59
59
  * `binding`, the name the code reads it under, and a key giving the
60
- * resource's own name. The code says the first, the deployment declares the
61
- * second, so a summary keeps both: the container is the resource's own
62
- * name, which is what another manifest declaring that resource spells,
63
- * and `physicalTable` records it again for a reader.
60
+ * resource's own name. The code says the first, the deployment declares
61
+ * the second, so a summary keeps both: the container is the binding
62
+ * name, which is what an access in the Worker spells (`env.SESSIONS`),
63
+ * and `physicalTable` is the resource's own name, the same split a
64
+ * Prisma model has between the model and the table it maps to.
64
65
  */
65
66
 
66
67
  /** The manifest language recorded on every binding this reader writes. */
package/dist/index.d.ts CHANGED
@@ -57,10 +57,11 @@ declare function loadConfigurationDocument(file: string): WranglerDocument;
57
57
  *
58
58
  * Every binding block in a Wrangler document has the same two halves:
59
59
  * `binding`, the name the code reads it under, and a key giving the
60
- * resource's own name. The code says the first, the deployment declares the
61
- * second, so a summary keeps both: the container is the resource's own
62
- * name, which is what another manifest declaring that resource spells,
63
- * and `physicalTable` records it again for a reader.
60
+ * resource's own name. The code says the first, the deployment declares
61
+ * the second, so a summary keeps both: the container is the binding
62
+ * name, which is what an access in the Worker spells (`env.SESSIONS`),
63
+ * and `physicalTable` is the resource's own name, the same split a
64
+ * Prisma model has between the model and the table it maps to.
64
65
  */
65
66
 
66
67
  /** The manifest language recorded on every binding this reader writes. */
package/dist/index.js CHANGED
@@ -38,9 +38,9 @@ function storeSummaries(document, context) {
38
38
  return summaries;
39
39
  }
40
40
  function storeSummary(store, entry, context) {
41
- const container = stringOf(entry[store.nameKey]);
41
+ const resourceName = stringOf(entry[store.nameKey]);
42
42
  const boundAs = stringOf(entry.binding);
43
- if (container === null) {
43
+ if (resourceName === null) {
44
44
  return null;
45
45
  }
46
46
  return {
@@ -51,13 +51,15 @@ function storeSummary(store, entry, context) {
51
51
  exportName: null
52
52
  },
53
53
  identity: {
54
- name: `${store.block}.${boundAs ?? container}`,
54
+ name: `${store.block}.${boundAs ?? resourceName}`,
55
55
  exportPath: null,
56
56
  boundaryBinding: storageBinding({
57
57
  recognition: RECOGNITION,
58
58
  storageSystem: store.storageSystem,
59
59
  scope: "default",
60
- container,
60
+ // The binding name is what an access in the Worker spells, so
61
+ // it is the name the storage check pairs on.
62
+ container: boundAs ?? resourceName,
61
63
  accessPath: null
62
64
  })
63
65
  },
@@ -66,11 +68,42 @@ function storeSummary(store, entry, context) {
66
68
  gaps: [],
67
69
  confidence: { source: "declared", level: "high" },
68
70
  metadata: {
69
- storageContract: { fieldSet: store.fieldSet, physicalTable: container },
71
+ storageContract: {
72
+ fieldSet: store.fieldSet,
73
+ physicalTable: resourceName
74
+ },
70
75
  ...boundAs === null ? {} : { wrangler: { binding: boundAs } }
71
76
  }
72
77
  };
73
78
  }
79
+ var BINDING_BLOCKS = [
80
+ "kv_namespaces",
81
+ "r2_buckets",
82
+ "d1_databases",
83
+ "queues"
84
+ ];
85
+ function bindingNames(document) {
86
+ const names = [];
87
+ for (const store of STORES) {
88
+ for (const entry of blockEntries(document[store.block])) {
89
+ const boundAs = stringOf(entry.binding);
90
+ if (boundAs !== null) {
91
+ names.push(boundAs);
92
+ }
93
+ }
94
+ }
95
+ const queues = asRecord(document.queues);
96
+ for (const entry of blockEntries(queues?.producers)) {
97
+ const boundAs = stringOf(entry.binding);
98
+ if (boundAs !== null) {
99
+ names.push(boundAs);
100
+ }
101
+ }
102
+ return names;
103
+ }
104
+ function asRecord(raw) {
105
+ return raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw : null;
106
+ }
74
107
  function queueSummaries(document, context) {
75
108
  const queues = document.queues;
76
109
  if (queues === null || typeof queues !== "object") {
@@ -207,10 +240,22 @@ function environmentDocuments(document) {
207
240
  return deployments;
208
241
  }
209
242
  function inheritedNames(document, overrides) {
210
- if (overrides.vars !== void 0) {
211
- return /* @__PURE__ */ new Set();
243
+ const names = /* @__PURE__ */ new Set();
244
+ if (overrides.vars === void 0) {
245
+ for (const name of Object.keys(varsOf(document))) {
246
+ names.add(name);
247
+ }
248
+ }
249
+ const kept = {};
250
+ for (const block of BINDING_BLOCKS) {
251
+ if (overrides[block] === void 0) {
252
+ kept[block] = document[block];
253
+ }
254
+ }
255
+ for (const name of bindingNames(kept)) {
256
+ names.add(name);
212
257
  }
213
- return new Set(Object.keys(varsOf(document)));
258
+ return names;
214
259
  }
215
260
  function nameOf(document) {
216
261
  return typeof document.name === "string" && document.name.length > 0 ? document.name : null;
@@ -221,7 +266,9 @@ function varsOf(document) {
221
266
  }
222
267
  function runtimeConfigSummary(deployment, context) {
223
268
  const vars = varsOf(deployment.merged);
224
- const names = Object.keys(vars).sort();
269
+ const names = [
270
+ .../* @__PURE__ */ new Set([...Object.keys(vars), ...bindingNames(deployment.merged)])
271
+ ].sort();
225
272
  const sources = {};
226
273
  const values = {};
227
274
  for (const name of names) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@suss/contract-wrangler",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "description": "Generate suss behavioral summaries from a Cloudflare wrangler.toml or wrangler.jsonc.",
6
6
  "keywords": [
@@ -45,8 +45,8 @@
45
45
  "typecheck": "tsc --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@suss/behavioral-ir": "0.9.0",
49
- "@suss/ir-core": "0.9.0",
48
+ "@suss/behavioral-ir": "0.10.0",
49
+ "@suss/ir-core": "0.10.0",
50
50
  "jsonc-parser": "^3.3.1",
51
51
  "smol-toml": "^1.4.2"
52
52
  },