@x12i/memorix-associator 1.0.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 (56) hide show
  1. package/README.md +90 -0
  2. package/dist/associated-properties/index.d.ts +16 -0
  3. package/dist/associated-properties/index.d.ts.map +1 -0
  4. package/dist/associated-properties/index.js +118 -0
  5. package/dist/associated-properties/index.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +88 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/engine.d.ts +12 -0
  11. package/dist/engine.d.ts.map +1 -0
  12. package/dist/engine.js +115 -0
  13. package/dist/engine.js.map +1 -0
  14. package/dist/index.d.ts +12 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +13 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/planning/build-plan.d.ts +10 -0
  19. package/dist/planning/build-plan.d.ts.map +1 -0
  20. package/dist/planning/build-plan.js +319 -0
  21. package/dist/planning/build-plan.js.map +1 -0
  22. package/dist/planning/fingerprint.d.ts +19 -0
  23. package/dist/planning/fingerprint.d.ts.map +1 -0
  24. package/dist/planning/fingerprint.js +47 -0
  25. package/dist/planning/fingerprint.js.map +1 -0
  26. package/dist/request/schema.d.ts +213 -0
  27. package/dist/request/schema.d.ts.map +1 -0
  28. package/dist/request/schema.js +2 -0
  29. package/dist/request/schema.js.map +1 -0
  30. package/dist/request/validate.d.ts +6 -0
  31. package/dist/request/validate.d.ts.map +1 -0
  32. package/dist/request/validate.js +64 -0
  33. package/dist/request/validate.js.map +1 -0
  34. package/dist/store/mongo.d.ts +4 -0
  35. package/dist/store/mongo.d.ts.map +1 -0
  36. package/dist/store/mongo.js +26 -0
  37. package/dist/store/mongo.js.map +1 -0
  38. package/dist/store/types.d.ts +30 -0
  39. package/dist/store/types.d.ts.map +1 -0
  40. package/dist/store/types.js +64 -0
  41. package/dist/store/types.js.map +1 -0
  42. package/dist/verification/associated-shape.d.ts +7 -0
  43. package/dist/verification/associated-shape.d.ts.map +1 -0
  44. package/dist/verification/associated-shape.js +52 -0
  45. package/dist/verification/associated-shape.js.map +1 -0
  46. package/dist/writing/failures.d.ts +13 -0
  47. package/dist/writing/failures.d.ts.map +1 -0
  48. package/dist/writing/failures.js +18 -0
  49. package/dist/writing/failures.js.map +1 -0
  50. package/dist/writing/smart-merge.d.ts +19 -0
  51. package/dist/writing/smart-merge.d.ts.map +1 -0
  52. package/dist/writing/smart-merge.js +77 -0
  53. package/dist/writing/smart-merge.js.map +1 -0
  54. package/docs/running-associations.md +340 -0
  55. package/examples/minimal-association-request.json +46 -0
  56. package/package.json +57 -0
@@ -0,0 +1,64 @@
1
+ import { isAssociatedPropertyName } from "@x12i/memorix-resolvers";
2
+ export class AssociationRequestValidationError extends Error {
3
+ constructor(message) {
4
+ super(message);
5
+ this.name = "AssociationRequestValidationError";
6
+ }
7
+ }
8
+ function assertNonEmpty(value, label) {
9
+ if (!value || value.trim() === "") {
10
+ throw new AssociationRequestValidationError(`${label} is required`);
11
+ }
12
+ return value;
13
+ }
14
+ function validateAssociatedProperty(name) {
15
+ if (!isAssociatedPropertyName(name)) {
16
+ throw new AssociationRequestValidationError(`associatedProperty must start with "associated": ${name}`);
17
+ }
18
+ }
19
+ function validateRule(rule, index) {
20
+ if (rule.type !== "association") {
21
+ throw new AssociationRequestValidationError(`rules[${index}].type must be "association"`);
22
+ }
23
+ assertNonEmpty(rule.ruleKey, `rules[${index}].ruleKey`);
24
+ validateAssociatedProperty(rule.associatedProperty);
25
+ if (!Array.isArray(rule.sourceJoinPaths) || rule.sourceJoinPaths.length === 0) {
26
+ throw new AssociationRequestValidationError(`rules[${index}].sourceJoinPaths must be non-empty`);
27
+ }
28
+ assertNonEmpty(rule.target.db, `rules[${index}].target.db`);
29
+ assertNonEmpty(rule.target.collection, `rules[${index}].target.collection`);
30
+ if (!Array.isArray(rule.target.joinPaths) || rule.target.joinPaths.length === 0) {
31
+ throw new AssociationRequestValidationError(`rules[${index}].target.joinPaths must be non-empty`);
32
+ }
33
+ }
34
+ function validateNormalization(step, index) {
35
+ if (step.type !== "split-values") {
36
+ throw new AssociationRequestValidationError(`normalization[${index}].type must be "split-values"`);
37
+ }
38
+ assertNonEmpty(step.to, `normalization[${index}].to`);
39
+ }
40
+ export function validateAssociationRequest(request) {
41
+ assertNonEmpty(request.processId, "processId");
42
+ if (request.mode !== "dry-run" && request.mode !== "apply") {
43
+ throw new AssociationRequestValidationError('mode must be "dry-run" or "apply"');
44
+ }
45
+ assertNonEmpty(request.source.db, "source.db");
46
+ assertNonEmpty(request.source.collection, "source.collection");
47
+ assertNonEmpty(request.source.objectType, "source.objectType");
48
+ assertNonEmpty(request.source.contentType, "source.contentType");
49
+ if (!Array.isArray(request.rules) || request.rules.length === 0) {
50
+ throw new AssociationRequestValidationError("rules must be a non-empty array");
51
+ }
52
+ request.rules.forEach(validateRule);
53
+ request.normalization?.forEach(validateNormalization);
54
+ if (request.writePolicy.associatedArrayMode !== "append-unique") {
55
+ throw new AssociationRequestValidationError('writePolicy.associatedArrayMode must be "append-unique"');
56
+ }
57
+ if (request.mode === "apply" &&
58
+ request.safety.requireReviewedReportForApply &&
59
+ !request.safety.reviewedReportPath &&
60
+ !request.safety.expectedPlanFingerprint) {
61
+ throw new AssociationRequestValidationError("apply mode requires reviewedReportPath or expectedPlanFingerprint when requireReviewedReportForApply is true");
62
+ }
63
+ }
64
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/request/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { MongoClient } from "mongodb";
2
+ import type { RecordStore } from "./types.js";
3
+ export declare function createMongoRecordStore(client: MongoClient): RecordStore;
4
+ //# sourceMappingURL=mongo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo.d.ts","sourceRoot":"","sources":["../../src/store/mongo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAsB,WAAW,EAAE,MAAM,YAAY,CAAC;AAElE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAwBvE"}
@@ -0,0 +1,26 @@
1
+ export function createMongoRecordStore(client) {
2
+ return {
3
+ async collectionExists(db, collection) {
4
+ const matches = await client.db(db).listCollections({ name: collection }).toArray();
5
+ return matches.length > 0;
6
+ },
7
+ async *scanRecords(db, collection, filter = {}, limit) {
8
+ let count = 0;
9
+ const cursor = client.db(db).collection(collection).find(filter);
10
+ for await (const doc of cursor) {
11
+ yield doc;
12
+ count += 1;
13
+ if (limit !== undefined && count >= limit)
14
+ break;
15
+ }
16
+ },
17
+ async bulkWrite(db, collection, operations) {
18
+ if (operations.length === 0)
19
+ return { errors: 0 };
20
+ const result = await client.db(db).collection(collection).bulkWrite(operations, { ordered: false });
21
+ const errors = result.getWriteErrorCount?.() ?? 0;
22
+ return { errors };
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=mongo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo.js","sourceRoot":"","sources":["../../src/store/mongo.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,sBAAsB,CAAC,MAAmB;IACxD,OAAO;QACL,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,UAAU;YACnC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACpF,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC5B,CAAC;QAED,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK;YACnD,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjE,IAAI,KAAK,EAAE,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;gBAC/B,MAAM,GAA8B,CAAC;gBACrC,KAAK,IAAI,CAAC,CAAC;gBACX,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,IAAI,KAAK;oBAAE,MAAM;YACnD,CAAC;QACH,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU;YACxC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACpG,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,EAAE,EAAE,IAAI,CAAC,CAAC;YAClD,OAAO,EAAE,MAAM,EAAE,CAAC;QACpB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ export type BulkWriteOperation = {
2
+ updateOne: {
3
+ filter: Record<string, unknown>;
4
+ update: {
5
+ $set?: Record<string, unknown>;
6
+ $unset?: Record<string, "">;
7
+ };
8
+ upsert?: boolean;
9
+ };
10
+ };
11
+ export interface RecordStore {
12
+ collectionExists(db: string, collection: string): Promise<boolean>;
13
+ scanRecords(db: string, collection: string, filter?: Record<string, unknown>, limit?: number): AsyncIterable<Record<string, unknown>>;
14
+ bulkWrite(db: string, collection: string, operations: BulkWriteOperation[]): Promise<{
15
+ errors: number;
16
+ }>;
17
+ backupCollection?(db: string, collection: string): Promise<string>;
18
+ }
19
+ export declare class InMemoryRecordStore implements RecordStore {
20
+ private readonly data;
21
+ seed(db: string, collection: string, records: Record<string, unknown>[]): void;
22
+ private bucket;
23
+ collectionExists(db: string, collection: string): Promise<boolean>;
24
+ scanRecords(db: string, collection: string, filter?: Record<string, unknown>, limit?: number): AsyncIterable<Record<string, unknown>>;
25
+ bulkWrite(db: string, collection: string, operations: BulkWriteOperation[]): Promise<{
26
+ errors: number;
27
+ }>;
28
+ getRecords(db: string, collection: string): Record<string, unknown>[];
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE;QACT,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;SAAE,CAAC;QACxE,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,WAAW,CACT,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzG,gBAAgB,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpE;AAED,qBAAa,mBAAoB,YAAW,WAAW;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2D;IAEhF,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,IAAI;IAK9E,OAAO,CAAC,MAAM;IAMR,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAMjE,WAAW,CAChB,EAAE,EAAE,MAAM,EACV,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,KAAK,CAAC,EAAE,MAAM,GACb,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAanC,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IA4B9G,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;CAGtE"}
@@ -0,0 +1,64 @@
1
+ export class InMemoryRecordStore {
2
+ data = new Map();
3
+ seed(db, collection, records) {
4
+ const key = `${db}/${collection}`;
5
+ this.data.set(key, new Map(records.map((record, index) => [String(record._id ?? index), { ...record }])));
6
+ }
7
+ bucket(db, collection) {
8
+ const key = `${db}/${collection}`;
9
+ if (!this.data.has(key))
10
+ this.data.set(key, new Map());
11
+ return this.data.get(key);
12
+ }
13
+ async collectionExists(db, collection) {
14
+ const key = `${db}/${collection}`;
15
+ const bucket = this.data.get(key);
16
+ return bucket !== undefined && bucket.size > 0;
17
+ }
18
+ async *scanRecords(db, collection, filter, limit) {
19
+ let count = 0;
20
+ for (const record of this.bucket(db, collection).values()) {
21
+ if (filter) {
22
+ const matches = Object.entries(filter).every(([key, value]) => record[key] === value);
23
+ if (!matches)
24
+ continue;
25
+ }
26
+ yield { ...record };
27
+ count += 1;
28
+ if (limit !== undefined && count >= limit)
29
+ break;
30
+ }
31
+ }
32
+ async bulkWrite(db, collection, operations) {
33
+ const bucket = this.bucket(db, collection);
34
+ let errors = 0;
35
+ for (const op of operations) {
36
+ try {
37
+ const id = String(op.updateOne.filter._id);
38
+ const existing = bucket.get(id);
39
+ if (!existing) {
40
+ errors += 1;
41
+ continue;
42
+ }
43
+ const next = { ...existing };
44
+ if (op.updateOne.update.$set) {
45
+ Object.assign(next, op.updateOne.update.$set);
46
+ }
47
+ if (op.updateOne.update.$unset) {
48
+ for (const key of Object.keys(op.updateOne.update.$unset)) {
49
+ delete next[key];
50
+ }
51
+ }
52
+ bucket.set(id, next);
53
+ }
54
+ catch {
55
+ errors += 1;
56
+ }
57
+ }
58
+ return { errors };
59
+ }
60
+ getRecords(db, collection) {
61
+ return [...this.bucket(db, collection).values()];
62
+ }
63
+ }
64
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { VerificationReport } from "../request/schema.js";
2
+ export declare function verifyAssociatedShapeOnRecord(record: Record<string, unknown>): Array<{
3
+ property: string;
4
+ message: string;
5
+ }>;
6
+ export declare function verifyAssociatedShapes(records: Array<Record<string, unknown>>): VerificationReport;
7
+ //# sourceMappingURL=associated-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"associated-shape.d.ts","sourceRoot":"","sources":["../../src/verification/associated-shape.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,KAAK,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAmC9C;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,kBAAkB,CAgBpB"}
@@ -0,0 +1,52 @@
1
+ import { isAssociatedPropertyName } from "@x12i/memorix-resolvers";
2
+ import { isPlainObject } from "../planning/fingerprint.js";
3
+ export function verifyAssociatedShapeOnRecord(record) {
4
+ const issues = [];
5
+ for (const [key, value] of Object.entries(record)) {
6
+ if (!isAssociatedPropertyName(key))
7
+ continue;
8
+ if (value === undefined)
9
+ continue;
10
+ if (!Array.isArray(value)) {
11
+ issues.push({
12
+ property: key,
13
+ message: "associated property must be an array",
14
+ });
15
+ continue;
16
+ }
17
+ if (value.length === 0) {
18
+ issues.push({
19
+ property: key,
20
+ message: "empty associated arrays should be omitted",
21
+ });
22
+ continue;
23
+ }
24
+ for (const item of value) {
25
+ if (!isPlainObject(item)) {
26
+ issues.push({
27
+ property: key,
28
+ message: "associated array items must be objects (linked data payloads)",
29
+ });
30
+ break;
31
+ }
32
+ }
33
+ }
34
+ return issues;
35
+ }
36
+ export function verifyAssociatedShapes(records) {
37
+ const issues = [];
38
+ for (const record of records) {
39
+ const recordIssues = verifyAssociatedShapeOnRecord(record);
40
+ const recordId = String(record.recordId ?? record._id ?? "unknown");
41
+ for (const issue of recordIssues) {
42
+ issues.push({ recordId, ...issue });
43
+ }
44
+ }
45
+ return {
46
+ passed: issues.length === 0,
47
+ checkedRecords: records.length,
48
+ invalidAssociatedShapes: issues.length,
49
+ issues,
50
+ };
51
+ }
52
+ //# sourceMappingURL=associated-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"associated-shape.js","sourceRoot":"","sources":["../../src/verification/associated-shape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAG3D,MAAM,UAAU,6BAA6B,CAC3C,MAA+B;IAE/B,MAAM,MAAM,GAAiD,EAAE,CAAC;IAEhE,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC;YAAE,SAAS;QAC7C,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAElC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,sCAAsC;aAChD,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,GAAG;gBACb,OAAO,EAAE,2CAA2C;aACrD,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzB,MAAM,CAAC,IAAI,CAAC;oBACV,QAAQ,EAAE,GAAG;oBACb,OAAO,EAAE,+DAA+D;iBACzE,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,OAAuC;IAEvC,MAAM,MAAM,GAAiC,EAAE,CAAC;IAChD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,6BAA6B,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC;QACpE,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC3B,cAAc,EAAE,OAAO,CAAC,MAAM;QAC9B,uBAAuB,EAAE,MAAM,CAAC,MAAM;QACtC,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { AssociationFailureRecord, FailureReason } from "../request/schema.js";
2
+ export declare function defaultFailureCollection(objectType: string, override?: string): string;
3
+ export declare function buildFailureRecord(input: {
4
+ sourceDoc: Record<string, unknown>;
5
+ sourceObjectType: string;
6
+ sourceContentType: string;
7
+ ruleKey: string;
8
+ reason: FailureReason;
9
+ message: string;
10
+ details: Record<string, unknown>;
11
+ failedAt: string;
12
+ }): AssociationFailureRecord;
13
+ //# sourceMappingURL=failures.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.d.ts","sourceRoot":"","sources":["../../src/writing/failures.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEpF,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,wBAAwB,CAe3B"}
@@ -0,0 +1,18 @@
1
+ export function defaultFailureCollection(objectType, override) {
2
+ return override ?? `${objectType}-failed`;
3
+ }
4
+ export function buildFailureRecord(input) {
5
+ const recordId = String(input.sourceDoc.recordId ??
6
+ (input.sourceDoc._id !== undefined ? input.sourceDoc._id : ""));
7
+ return {
8
+ recordId: recordId || undefined,
9
+ sourceObjectType: input.sourceObjectType,
10
+ sourceContentType: input.sourceContentType,
11
+ ruleKey: input.ruleKey,
12
+ failedAt: input.failedAt,
13
+ reason: input.reason,
14
+ message: input.message,
15
+ details: input.details,
16
+ };
17
+ }
18
+ //# sourceMappingURL=failures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failures.js","sourceRoot":"","sources":["../../src/writing/failures.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,wBAAwB,CAAC,UAAkB,EAAE,QAAiB;IAC5E,OAAO,QAAQ,IAAI,GAAG,UAAU,SAAS,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KASlC;IACC,MAAM,QAAQ,GAAG,MAAM,CACrB,KAAK,CAAC,SAAS,CAAC,QAAQ;QACtB,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CACjE,CAAC;IACF,OAAO;QACL,QAAQ,EAAE,QAAQ,IAAI,SAAS;QAC/B,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ export type NormalizeAssociatedResult = {
2
+ value: unknown[] | undefined;
3
+ changed: boolean;
4
+ removedEmpty: boolean;
5
+ deduped: number;
6
+ };
7
+ export declare function normalizeAssociatedValue(value: unknown): NormalizeAssociatedResult;
8
+ export type MergeAssociatedResult = {
9
+ value: unknown[] | undefined;
10
+ appended: number;
11
+ changed: boolean;
12
+ normalized: NormalizeAssociatedResult;
13
+ };
14
+ export declare function mergeAssociatedAppendUnique(existing: unknown, incomingItems: unknown[]): MergeAssociatedResult;
15
+ export declare function buildUpdateOperation(originalAssociated: Map<string, unknown>, workingAssociated: Map<string, unknown>): {
16
+ $set?: Record<string, unknown>;
17
+ $unset?: Record<string, "">;
18
+ } | null;
19
+ //# sourceMappingURL=smart-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-merge.d.ts","sourceRoot":"","sources":["../../src/writing/smart-merge.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CA+BlF;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,yBAAyB,CAAC;CACvC,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,OAAO,EACjB,aAAa,EAAE,OAAO,EAAE,GACvB,qBAAqB,CAwBvB;AAED,wBAAgB,oBAAoB,CAClC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EACxC,iBAAiB,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GACtC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAoBxE"}
@@ -0,0 +1,77 @@
1
+ import { canonicalKey } from "../planning/fingerprint.js";
2
+ export function normalizeAssociatedValue(value) {
3
+ if (value === undefined) {
4
+ return { value: undefined, changed: false, removedEmpty: false, deduped: 0 };
5
+ }
6
+ const beforeKey = canonicalKey(value);
7
+ const arr = Array.isArray(value) ? value : [value];
8
+ const seen = new Set();
9
+ const normalized = [];
10
+ let deduped = 0;
11
+ for (const item of arr) {
12
+ const key = canonicalKey(item);
13
+ if (seen.has(key)) {
14
+ deduped += 1;
15
+ continue;
16
+ }
17
+ seen.add(key);
18
+ normalized.push(item);
19
+ }
20
+ if (normalized.length === 0) {
21
+ return { value: undefined, changed: true, removedEmpty: true, deduped };
22
+ }
23
+ return {
24
+ value: normalized,
25
+ changed: beforeKey !== canonicalKey(normalized),
26
+ removedEmpty: false,
27
+ deduped,
28
+ };
29
+ }
30
+ export function mergeAssociatedAppendUnique(existing, incomingItems) {
31
+ const normalized = normalizeAssociatedValue(existing);
32
+ const merged = normalized.value ? [...normalized.value] : [];
33
+ const seen = new Set(merged.map(canonicalKey));
34
+ let appended = 0;
35
+ for (const item of incomingItems) {
36
+ const key = canonicalKey(item);
37
+ if (seen.has(key))
38
+ continue;
39
+ seen.add(key);
40
+ merged.push(item);
41
+ appended += 1;
42
+ }
43
+ if (merged.length === 0) {
44
+ return { value: undefined, appended, changed: normalized.changed, normalized };
45
+ }
46
+ return {
47
+ value: merged,
48
+ appended,
49
+ changed: normalized.changed || appended > 0,
50
+ normalized,
51
+ };
52
+ }
53
+ export function buildUpdateOperation(originalAssociated, workingAssociated) {
54
+ const $set = {};
55
+ const $unset = {};
56
+ const keys = new Set([...originalAssociated.keys(), ...workingAssociated.keys()]);
57
+ for (const key of keys) {
58
+ const original = originalAssociated.get(key);
59
+ const next = workingAssociated.get(key);
60
+ if (next === undefined) {
61
+ if (original !== undefined)
62
+ $unset[key] = "";
63
+ continue;
64
+ }
65
+ if (canonicalKey(original) !== canonicalKey(next))
66
+ $set[key] = next;
67
+ }
68
+ const update = {};
69
+ if (Object.keys($set).length > 0)
70
+ update.$set = $set;
71
+ if (Object.keys($unset).length > 0)
72
+ update.$unset = $unset;
73
+ if (Object.keys(update).length === 0)
74
+ return null;
75
+ return update;
76
+ }
77
+ //# sourceMappingURL=smart-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"smart-merge.js","sourceRoot":"","sources":["../../src/writing/smart-merge.ts"],"names":[],"mappings":"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"}