@notation/resource 0.13.0 → 0.14.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/dist/index.d.ts CHANGED
@@ -323,6 +323,56 @@ type ResourceBuilder<ApiSchema extends DefineResourceApiSchema> = {
323
323
  declare function defineResource<ApiSchema extends DefineResourceApiSchema>(meta: DefineResourceMeta): ResourceBuilder<ApiSchema>;
324
324
  declare const resource: typeof defineResource;
325
325
 
326
+ /**
327
+ * Stands in for a param whose value is known only once a dependency has been
328
+ * applied. Compared structurally, so it survives a JSON round trip.
329
+ */
330
+ declare const UNKNOWN_AFTER_APPLY: {
331
+ readonly $unknown: "after-apply";
332
+ };
333
+ type UnknownAfterApply = typeof UNKNOWN_AFTER_APPLY;
334
+ declare function isUnknownAfterApply(value: unknown): value is UnknownAfterApply;
335
+ /**
336
+ * A field that forces replacement. `known: false` means the desired value is
337
+ * unknown after apply, so the field may force replacement.
338
+ */
339
+ type ReplaceField = {
340
+ name: string;
341
+ known: boolean;
342
+ };
343
+ type ParamsDiffDisplay = {
344
+ added: Record<string, unknown>;
345
+ deleted: Record<string, unknown>;
346
+ updated: Record<string, unknown>;
347
+ };
348
+ type ParamsDiff = {
349
+ /** Changed comparable params only. */
350
+ patch: Record<string, unknown>;
351
+ /** Names of changed fields. */
352
+ changed: string[];
353
+ /** Fields that force replacement. */
354
+ replaceFields: ReplaceField[];
355
+ /** For plan display. */
356
+ diff: ParamsDiffDisplay;
357
+ };
358
+ /**
359
+ * Keeps the params that take part in a comparison: `param` items that are
360
+ * neither volatile nor hidden. An `undefined` value counts as absent: state
361
+ * is stored as JSON, which drops it, so keeping it would make an unset
362
+ * optional param look changed on every deploy.
363
+ */
364
+ declare function toComparableParams(schema: Schema, values: Record<string, unknown>): Record<string, unknown>;
365
+ /**
366
+ * Compares previous and desired params field by field, and reads the schema
367
+ * to decide which changes no update can apply: a change to an immutable or
368
+ * key param, or any change at all when the resource cannot update. Pure: it
369
+ * reads nothing but its arguments, so any engine planning a Notation resource
370
+ * reaches the same answer as the reconciler.
371
+ */
372
+ declare function diffParams(schema: Schema, previous: Record<string, unknown>, desired: Record<string, unknown>, options: {
373
+ canUpdate: boolean;
374
+ }): ParamsDiff;
375
+
326
376
  type ResourceGroupOptions = {
327
377
  /**
328
378
  * Optional pre-assigned ID. Used outside graph collection.
@@ -349,4 +399,4 @@ type ResourceGraph = {
349
399
  };
350
400
  declare function collectResourceGraph(evaluate: () => unknown | Promise<unknown>): Promise<ResourceGraph>;
351
401
 
352
- export { type BaseResource, type CompoundKey, type ComputedPrimaryKey, type DeepPartial, type DefineResourceApiSchema, type DefineResourceMeta, type Fallback, type IfAllPropertiesOptional, type InferResourceTypes, type MapSchema, type NoInfer, type OmitOptional, type OptionalIfAllPropertiesOptional, type Output, type Params, type PickOptional, type ResolveSchema, type ResolvedSchema, Resource, type ResourceBuilder, type ResourceClass, type ResourceDependenciesBuilder, type ResourceGraph, ResourceGroup, type ResourceGroupOptions, ResourceNotFoundError, type ResourceOperationContext, ResourceOperationPendingError, type ResourceOperationSignal, type ResourceOperationsOptions, type ResourceOpts, type ResourceSchemaBuilder, type ResourceType, type ResourceTypes, type Result, type Schema, type SchemaFromApi, type SchemaItem, type Simplify, type State, type TypedValue, collectResourceGraph, defineResource, resource, typed };
402
+ export { type BaseResource, type CompoundKey, type ComputedPrimaryKey, type DeepPartial, type DefineResourceApiSchema, type DefineResourceMeta, type Fallback, type IfAllPropertiesOptional, type InferResourceTypes, type MapSchema, type NoInfer, type OmitOptional, type OptionalIfAllPropertiesOptional, type Output, type Params, type ParamsDiff, type ParamsDiffDisplay, type PickOptional, type ReplaceField, type ResolveSchema, type ResolvedSchema, Resource, type ResourceBuilder, type ResourceClass, type ResourceDependenciesBuilder, type ResourceGraph, ResourceGroup, type ResourceGroupOptions, ResourceNotFoundError, type ResourceOperationContext, ResourceOperationPendingError, type ResourceOperationSignal, type ResourceOperationsOptions, type ResourceOpts, type ResourceSchemaBuilder, type ResourceType, type ResourceTypes, type Result, type Schema, type SchemaFromApi, type SchemaItem, type Simplify, type State, type TypedValue, UNKNOWN_AFTER_APPLY, type UnknownAfterApply, collectResourceGraph, defineResource, diffParams, isUnknownAfterApply, resource, toComparableParams, typed };
package/dist/index.js CHANGED
@@ -1,6 +1,69 @@
1
1
  // src/resource.schema.ts
2
2
  var typed = () => ({});
3
3
 
4
+ // src/diff-params.ts
5
+ import { detailedDiff, diff } from "deep-object-diff";
6
+ var UNKNOWN_AFTER_APPLY = { $unknown: "after-apply" };
7
+ function isUnknownAfterApply(value) {
8
+ return value !== null && typeof value === "object" && value.$unknown === UNKNOWN_AFTER_APPLY.$unknown;
9
+ }
10
+ function toComparableParams(schema, values) {
11
+ const comparable = {};
12
+ for (const [key, item] of Object.entries(schema)) {
13
+ if (!isComparable(item)) continue;
14
+ if (values[key] !== void 0) comparable[key] = values[key];
15
+ }
16
+ return comparable;
17
+ }
18
+ function diffParams(schema, previous, desired, options) {
19
+ const previousComparable = toComparableParams(schema, previous);
20
+ const desiredComparable = toComparableParams(schema, desired);
21
+ const patch = diff(previousComparable, desiredComparable);
22
+ const changed = [];
23
+ const replaceFields = [];
24
+ for (const [name, item] of Object.entries(schema)) {
25
+ if (!isComparable(item)) continue;
26
+ const unknown = isUnknownAfterApply(desiredComparable[name]);
27
+ if (!unknown && !(name in patch)) continue;
28
+ if (!(name in patch)) patch[name] = desiredComparable[name];
29
+ changed.push(name);
30
+ if (!options.canUpdate || forcesReplacement(item)) {
31
+ replaceFields.push({ name, known: !unknown });
32
+ }
33
+ }
34
+ return {
35
+ patch,
36
+ changed,
37
+ replaceFields,
38
+ diff: toDisplayDiff(detailedDiff(previousComparable, desiredComparable))
39
+ };
40
+ }
41
+ function isComparable(item) {
42
+ return item.propertyType === "param" && !item.volatile && !item.hidden;
43
+ }
44
+ function forcesReplacement(item) {
45
+ return item.propertyType === "param" && Boolean(item.immutable || item.primaryKey || item.secondaryKey);
46
+ }
47
+ function toDisplayDiff(diffResult) {
48
+ return {
49
+ added: toJsonSafe(diffResult.added),
50
+ deleted: toJsonSafe(diffResult.deleted),
51
+ updated: toJsonSafe(diffResult.updated)
52
+ };
53
+ }
54
+ function toJsonSafe(value) {
55
+ if (value === void 0) return null;
56
+ if (Array.isArray(value)) return value.map(toJsonSafe);
57
+ if (value !== null && typeof value === "object") {
58
+ const safe = {};
59
+ for (const [key, entry] of Object.entries(value)) {
60
+ safe[key] = toJsonSafe(entry);
61
+ }
62
+ return safe;
63
+ }
64
+ return value;
65
+ }
66
+
4
67
  // src/resource.ts
5
68
  var Resource = class {
6
69
  config;
@@ -28,16 +91,7 @@ var Resource = class {
28
91
  this.output = output;
29
92
  }
30
93
  toComparable(output) {
31
- const parsed = {};
32
- for (const [k, v] of Object.entries(this.schema)) {
33
- if (v.volatile) continue;
34
- if (v.hidden) continue;
35
- if (v.propertyType !== "param") continue;
36
- if (k in output) {
37
- parsed[k] = output[k];
38
- }
39
- }
40
- return parsed;
94
+ return toComparableParams(this.schema, output);
41
95
  }
42
96
  toState(output) {
43
97
  const parsed = {};
@@ -209,8 +263,12 @@ export {
209
263
  ResourceGroup,
210
264
  ResourceNotFoundError,
211
265
  ResourceOperationPendingError,
266
+ UNKNOWN_AFTER_APPLY,
212
267
  collectResourceGraph,
213
268
  defineResource,
269
+ diffParams,
270
+ isUnknownAfterApply,
214
271
  resource,
272
+ toComparableParams,
215
273
  typed
216
274
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@notation/resource",
4
- "version": "0.13.0",
4
+ "version": "0.14.0",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "exports": {
@@ -13,6 +13,9 @@
13
13
  "files": [
14
14
  "dist"
15
15
  ],
16
+ "dependencies": {
17
+ "deep-object-diff": "^1.1.9"
18
+ },
16
19
  "scripts": {
17
20
  "build": "tsup --clean",
18
21
  "dev": "tsup --watch"