@haverstack/core 0.31.0 → 0.33.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/adapter-entry.d.ts +2 -2
- package/dist/adapter-entry.d.ts.map +1 -1
- package/dist/adapter-entry.js +1 -1
- package/dist/adapter-entry.js.map +1 -1
- package/dist/attachment-download.d.ts +25 -0
- package/dist/attachment-download.d.ts.map +1 -1
- package/dist/attachment-download.js +30 -0
- package/dist/attachment-download.js.map +1 -1
- package/dist/changes.d.ts +23 -2
- package/dist/changes.d.ts.map +1 -1
- package/dist/changes.js +35 -2
- package/dist/changes.js.map +1 -1
- package/dist/combine.d.ts.map +1 -1
- package/dist/combine.js +2 -1
- package/dist/combine.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/query-validation.d.ts +15 -1
- package/dist/query-validation.d.ts.map +1 -1
- package/dist/query-validation.js +25 -0
- package/dist/query-validation.js.map +1 -1
- package/dist/record-changes.d.ts +55 -2
- package/dist/record-changes.d.ts.map +1 -1
- package/dist/record-changes.js +82 -6
- package/dist/record-changes.js.map +1 -1
- package/dist/scoped-stack.d.ts +12 -3
- package/dist/scoped-stack.d.ts.map +1 -1
- package/dist/scoped-stack.js +19 -14
- package/dist/scoped-stack.js.map +1 -1
- package/dist/stack.d.ts +100 -24
- package/dist/stack.d.ts.map +1 -1
- package/dist/stack.js +219 -43
- package/dist/stack.js.map +1 -1
- package/dist/testing.d.ts +25 -16
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +63 -18
- package/dist/testing.js.map +1 -1
- package/dist/types.d.ts +164 -41
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wire-entry.d.ts +2 -2
- package/dist/wire-entry.d.ts.map +1 -1
- package/dist/wire-entry.js +7 -6
- package/dist/wire-entry.js.map +1 -1
- package/dist/wire-request.d.ts +11 -1
- package/dist/wire-request.d.ts.map +1 -1
- package/dist/wire-request.js +19 -0
- package/dist/wire-request.js.map +1 -1
- package/package.json +1 -1
package/dist/stack.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../src/stack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAiCH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,UAAU,EACV,MAAM,EACN,YAAY,EACZ,UAAU,EAEV,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,EAET,aAAa,EACb,aAAa,EACb,WAAW,EAEX,iBAAiB,EACjB,MAAM,EAEN,QAAQ,EAER,KAAK,EAEL,YAAY,EACZ,YAAY,EAGZ,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,YAAY,EACZ,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAiCpB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA6B/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAqChD,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;;;OAKG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,kEAAkE;IAClE,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AACF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,8BAA8B,GAAG,mBAAmB,GAAG;IACjE;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,IAAI,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;OAIG;IACH,UAAU,CAAC,EAAE,QAAQ,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD;;;;;;;;OAQG;IACH,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,+BAA+B,GAAG;IAC5C;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;CACjC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,gBAAgB,GAAG;IACnD,iFAAiF;IACjF,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAMF;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;IACjC,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChE,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EACV,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC,CAAC;IACzC,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACtE,KAAK,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAChD;;;;;;OAMG;IACH,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC3D,4EAA4E;IAC5E,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAC9C;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1F,0EAA0E;IAC1E,YAAY,CACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,EACrC,IAAI,CAAC,EAAE,gBAAgB,GACtB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACtE,kFAAkF;IAClF,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACvE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACpE,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;IAClD,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC;IACvE,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3F;;;;;;;;;;;;;OAaG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC5E;;;;;;;OAOG;IACH,eAAe,CACb,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,IAAI,CAAC,EAAE,gBAAgB,GACtB,OAAO,CAAC,WAAW,CAAC,CAAC;IACxB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnD,aAAa,CACX,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,KAAK,GACZ,OAAO,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAC;IACzD,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,wBAAwB,CACtB,IAAI,CAAC,EAAE,+BAA+B,GACrC,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC3C,SAAS,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACnG;AAMD,qBAAa,KAAM,YAAW,WAAW;IA2BrC,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IA3BzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;IAC3D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA6B;IAC/D;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAE1D,6DAA6D;IAC7D,OAAO,CAAC,MAAM,CAAS;IAEvB;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAE/C,OAAO;IAKP;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAclB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAS1B;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;YAQV,aAAa;IAQ3B;;OAEG;WACU,MAAM,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;IAkBnF;;;;;;;;;OASG;YACW,iBAAiB;IAY/B,IAAI,aAAa,IAAI,QAAQ,CAE5B;IAEK,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAI1D,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAInD,IAAI,QAAQ,IAAI,MAAM,GAAG,SAAS,CAEjC;IAED,IAAI,QAAQ,IAAI,aAAa,CAE5B;IAED;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,GAAE,kBAAuB,GAAG,WAAW;IAe/E;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,WAAW;IAQ9C;;;;;;OAMG;IACG,UAAU,CACd,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,SAAS,CAAC;IA8Df,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAKpD,+FAA+F;IACzF,SAAS,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAOvC;;;OAGG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAWpF;;;;;OAKG;IACH,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAQ7C;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAqB5B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAapB;;;;;OAKG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAqDnE;;;;;;;;;;OAUG;IACG,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,CAAC,EACV,IAAI,GAAE,8BAAmC,GACxC,OAAO,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,CAAC,CAAA;KAAE,CAAC;IA8IxC;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IA4BvB;;;;OAIG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAO/E;;;;;;;;;;;;;;;OAeG;IACG,MAAM,CACV,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,aAAa,EACtB,IAAI,GAAE,gBAAgB,GAAG,YAAiB,GACzC,OAAO,CAAC,WAAW,CAAC;IAkEvB;;;;OAIG;IACG,YAAY,CAChB,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAAC,EACrC,IAAI,GAAE,gBAAgB,GAAG,YAAiB,GACzC,OAAO,CAAC,WAAW,CAAC;IAIvB;;;;;;;;;;OAUG;YACW,iBAAiB;IAwE/B;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,uBAAuB;IAS/B;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,CACb,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,WAAW,EACxB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,WAAW,CAAC;IA8BvB;;;;;;;;OAQG;IACG,UAAU,CACd,EAAE,EAAE,MAAM,EACV,WAAW,EAAE,WAAW,EACxB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,WAAW,CAAC;IAoCvB;;;;;;;;;;OAUG;YACW,kBAAkB;IAUhC;;;;;;;;;;;;;;;;;;;;OAoBG;YACW,mBAAmB;IAkBjC;;;;;;OAMG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAmB,GAAG,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCtF;;;;;OAKG;IACG,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,GAAE,gBAAgB,GAAG,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC;IAiB5F;;;;;OAKG;IACG,KAAK,CAAC,KAAK,GAAE,UAAe,GAAG,OAAO,CAAC,WAAW,CAAC;IAwBzD;;;;;OAKG;YACW,mBAAmB;IAyB3B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAKvD;;;;;;;;;;;;;OAaG;IACG,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,YAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAM/E,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAK5E;;;;;;;OAOG;IACG,cAAc,CAClB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,gBAAgB,GAAG,YAAiB,GACzC,OAAO,CAAC,WAAW,CAAC;IA2EvB;;;;;;;;;;;;;;;;;;;OAmBG;IACG,eAAe,CACnB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,IAAI,GAAE,gBAAgB,GAAG,YAAiB,GACzC,OAAO,CAAC,WAAW,CAAC;IAUvB;;;;;;;;;;;;;;OAcG;YACW,sBAAsB;IAyEpC,6EAA6E;YAC/D,qBAAqB;IAUnC;;;;;OAKG;YACW,qBAAqB;IAkBnC;;;;;;;;;;;;;OAaG;YACW,sBAAsB;IAwBpC;;;;;;;;;;;;;;;;;OAiBG;YACW,kBAAkB;IA2BhC;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IAoB7B;;;;;;;;;;;;OAYG;YACW,+BAA+B;IAqB7C;;;;;;;;;;;OAWG;YACW,kCAAkC;IA0ChD;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IASjC;;;;;OAKG;IACH,OAAO,CAAC,4BAA4B;IASpC;;;;;;;OAOG;IACG,aAAa,CACjB,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,MAAM,EACjB,KAAK,CAAC,EAAE,KAAK,GACZ,OAAO,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,iBAAiB,CAAA;KAAE,CAAC;IAuBlD,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAKxD;;;;;;;;;;;OAWG;IACG,oBAAoB,CACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,WAAW,GAAG;QAAE,OAAO,EAAE,iBAAiB,CAAA;KAAE,CAAC,EAAE,CAAC;IAe5D;;;;OAIG;YACW,iBAAiB;IAK/B;;;;;OAKG;IACG,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B9E;;;;OAIG;YACW,2CAA2C;IA0BzD;;;;;OAKG;IACG,wBAAwB,CAC5B,IAAI,GAAE,+BAA+B,GAAG,YAAiB,GACxD,OAAO,CAAC,8BAA8B,CAAC;IA4E1C;;;;;;;;;OASG;IACG,SAAS,CACb,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,EACvC,IAAI,GAAE,gBAAqB,GAC1B,OAAO,CAAC,WAAW,CAAC;IAmBvB;;;;;;;;;;OAUG;YACW,SAAS;IAuBvB;;;OAGG;IACH,IAAI,aAAa,IAAI,OAAO,CAE3B;IAED;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;;;OAKG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAc5B;;;OAGG;IACH,UAAU,IAAI,IAAI;IAQlB;;;;;;;;;;;;;;;;;OAiBG;IACG,KAAK,CACT,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GACxD,OAAO,CAAC,WAAW,EAAE,CAAC;IAkBzB;;;;;;OAMG;IACG,UAAU,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA2B9D;;;;;OAKG;IACG,MAAM,CACV,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GACxD,OAAO,CAAC,IAAI,CAAC;IAuBhB;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;YA2CV,eAAe;IA0C7B;;;;;OAKG;IACH,OAAO,CAAC,cAAc;IAUtB;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IASpB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;CAa7B"}
|
package/dist/stack.js
CHANGED
|
@@ -19,16 +19,16 @@ import { validateContent, validateContentKeys, validatePatchValues, validateRese
|
|
|
19
19
|
import { applyMergePatch } from './merge.js';
|
|
20
20
|
import { hasGroupAdmin, isGroupAdminAssociation, validatePermissions } from './access.js';
|
|
21
21
|
import { compareRecordedAttachments } from './attachment-download.js';
|
|
22
|
-
import { ChangeEmitter, RelayDelivery, buildEmission, assertSinceUsable } from './changes.js';
|
|
22
|
+
import { ChangeEmitter, RelayDelivery, buildEmission, buildJournalEntry, assertSinceUsable, } from './changes.js';
|
|
23
23
|
import { SYSTEM_TYPES } from './types.js';
|
|
24
24
|
import { StackClosedError, StackConflictError, StackMigrationError, StackNotFoundError, StackPermissionError, StackQueryError, StackSchemaDriftError, StackValidationError, StackVersionConflictError, } from './errors.js';
|
|
25
|
-
import { assertQueryCapabilities, assertSortCapability, assertValidRelatedTo, assertValidSort, filtersContent, validateAssociation, validateAssociations, } from './query-validation.js';
|
|
25
|
+
import { assertQueryCapabilities, assertSortCapability, assertValidRelatedTo, assertValidJournalQuery, assertValidSort, filtersContent, validateAssociation, validateAssociations, } from './query-validation.js';
|
|
26
26
|
import { GRANT_ACTION_SET, READ_COMPANIONS, grantConveys, matchesGrantTarget, validateGrantTarget, grantCoversGrantee, UNGRANTABLE_SYSTEM_TYPES, loadGrantRecords, } from './grants.js';
|
|
27
27
|
import { bindingFieldsOf, uniqueBindingFieldsOf } from './identity-bindings.js';
|
|
28
28
|
import { assertAttachmentSize, assertContentSize } from './limits.js';
|
|
29
29
|
import { validateParentId, validateRecordId, validateClockField, validateIdTimestampSkew, DEFAULT_ID_TIMESTAMP_SKEW_MS, } from './record-id.js';
|
|
30
30
|
import { queryAllPages, findFirstMatch, lookupEntityByDid, MAX_QUERY_LIMIT, } from './stack-reads.js';
|
|
31
|
-
import { associationEqual, assertNonEmptyChangeSet, changeSetOps, effectiveChanges, stampGroupAdmin, isGroupRecord, } from './record-changes.js';
|
|
31
|
+
import { associationDelta, associationEqual, associationIdentical, assertNonEmptyChangeSet, changeSetOps, bumpsVersion, takesIfVersion, effectiveChanges, stampGroupAdmin, stripAssociationAnnotation, isGroupRecord, } from './record-changes.js';
|
|
32
32
|
import { ScopedStack } from './scoped-stack.js';
|
|
33
33
|
// -------------------------------------------------------
|
|
34
34
|
// Supporting types
|
|
@@ -101,12 +101,35 @@ export class Stack {
|
|
|
101
101
|
this.changes.emit(buildEmission(op, record, opts));
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* The
|
|
105
|
-
*
|
|
106
|
-
*
|
|
104
|
+
* The actor for a `create` journal entry, read off the record as just
|
|
105
|
+
* built. Create is the one journaled write that stamps the requester
|
|
106
|
+
* onto the row itself, so the record in hand is authoritative — and it
|
|
107
|
+
* carries `appId`, which ActorOptions has no field for.
|
|
107
108
|
*/
|
|
108
|
-
static
|
|
109
|
-
|
|
109
|
+
static createActor(record) {
|
|
110
|
+
if (!record.updatedBy)
|
|
111
|
+
return undefined;
|
|
112
|
+
return {
|
|
113
|
+
entityId: record.updatedBy,
|
|
114
|
+
...(record.updatedVia !== undefined && { principalId: record.updatedVia }),
|
|
115
|
+
...(record.appId !== undefined && { appId: record.appId }),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The requester behind a write that stamps nothing on the record itself —
|
|
120
|
+
* a hard delete, which leaves no record to stamp, and associate()/
|
|
121
|
+
* dissociate(), which don't bump and so don't touch updatedBy/updatedVia.
|
|
122
|
+
* Hard delete is owner-acting-alone only, so it never has a principal to
|
|
123
|
+
* name beside the subject; associate()/dissociate() can run delegated,
|
|
124
|
+
* so `updatedVia` rides along here when present.
|
|
125
|
+
*/
|
|
126
|
+
static actorFrom(opts) {
|
|
127
|
+
if (!opts.updatedBy)
|
|
128
|
+
return undefined;
|
|
129
|
+
return {
|
|
130
|
+
entityId: opts.updatedBy,
|
|
131
|
+
...(opts.updatedVia !== undefined && { principalId: opts.updatedVia }),
|
|
132
|
+
};
|
|
110
133
|
}
|
|
111
134
|
async getTypeCached(id) {
|
|
112
135
|
const cached = this.typeCache.get(id);
|
|
@@ -448,6 +471,7 @@ export class Stack {
|
|
|
448
471
|
if (typeId === `${SYSTEM_TYPES.ATTACHMENT}@1`) {
|
|
449
472
|
await this.checkAttachmentMimeTypeOnCreate(content);
|
|
450
473
|
}
|
|
474
|
+
await this.checkAttachmentAssociationPointers(opts.associations);
|
|
451
475
|
await this.checkBindingsOnCreate(typeId, content);
|
|
452
476
|
if (opts.id !== undefined) {
|
|
453
477
|
validateRecordId(opts.id);
|
|
@@ -518,7 +542,9 @@ export class Stack {
|
|
|
518
542
|
...(associations?.length && { associations }),
|
|
519
543
|
...(opts.unlisted && { unlistedAt: createdAt }),
|
|
520
544
|
};
|
|
521
|
-
const created = await this.adapter.createRecord(record
|
|
545
|
+
const created = await this.adapter.createRecord(record, {
|
|
546
|
+
journal: buildJournalEntry('create', { actor: Stack.createActor(record) }),
|
|
547
|
+
});
|
|
522
548
|
this.emitChange('create', created);
|
|
523
549
|
return created;
|
|
524
550
|
}
|
|
@@ -585,7 +611,12 @@ export class Stack {
|
|
|
585
611
|
if (!existing) {
|
|
586
612
|
throw new StackNotFoundError(`Record not found: "${id}"`);
|
|
587
613
|
}
|
|
588
|
-
|
|
614
|
+
// Checked before validation, so a caller that lost the race learns its
|
|
615
|
+
// version is stale rather than that its patch is bad, and before the
|
|
616
|
+
// no-op short-circuit below, so a precondition is never satisfied by a
|
|
617
|
+
// write that turned out to move nothing.
|
|
618
|
+
if (takesIfVersion(changes))
|
|
619
|
+
this.checkIfVersion(existing, opts.ifVersion);
|
|
589
620
|
const merged = await this.validateChangeSet(id, existing, changes);
|
|
590
621
|
const ops = changeSetOps(existing, changes, merged);
|
|
591
622
|
// Nothing moved, so there is nothing to version. Decided here rather
|
|
@@ -594,9 +625,43 @@ export class Stack {
|
|
|
594
625
|
// writes nothing.
|
|
595
626
|
if (ops.length === 0)
|
|
596
627
|
return existing;
|
|
628
|
+
// A change set touching only `associations` doesn't bump — the same
|
|
629
|
+
// rule associate()/dissociate() follow unconditionally. Its actor
|
|
630
|
+
// travels as an explicit opt rather than a record stamp, since a
|
|
631
|
+
// non-bumping write never touches updatedBy/updatedVia.
|
|
632
|
+
// See docs/spec/versioning.md § Version history.
|
|
633
|
+
const bumps = bumpsVersion(ops);
|
|
634
|
+
// Computed against the same before/after changeSetOps compared, so
|
|
635
|
+
// whether associate/dissociate appear in `ops` and what these list can
|
|
636
|
+
// never disagree. See docs/spec/events.md § The event shape.
|
|
637
|
+
const assocDelta = changes.associations
|
|
638
|
+
? associationDelta(existing.associations ?? [], changes.associations)
|
|
639
|
+
: undefined;
|
|
597
640
|
const previousParentId = existing.parentId ?? null;
|
|
598
|
-
const updated = await this.adapter.mutateRecord(id, effectiveChanges(changes, ops),
|
|
599
|
-
|
|
641
|
+
const updated = await this.adapter.mutateRecord(id, effectiveChanges(changes, ops), {
|
|
642
|
+
...(bumps
|
|
643
|
+
? this.writeOptions(existing, opts)
|
|
644
|
+
: {
|
|
645
|
+
updatedBy: opts.updatedBy,
|
|
646
|
+
updatedVia: opts.updatedVia,
|
|
647
|
+
}),
|
|
648
|
+
bumpsVersion: bumps,
|
|
649
|
+
journal: buildJournalEntry(ops, {
|
|
650
|
+
actor: Stack.actorFrom(opts),
|
|
651
|
+
...(ops.includes('reparent') && { previousParentId }),
|
|
652
|
+
...(assocDelta && {
|
|
653
|
+
associationsAdded: assocDelta.added,
|
|
654
|
+
associationsRemoved: assocDelta.removed,
|
|
655
|
+
associationsReplaced: assocDelta.replaced,
|
|
656
|
+
}),
|
|
657
|
+
}),
|
|
658
|
+
});
|
|
659
|
+
this.emitChange(ops, updated, {
|
|
660
|
+
...(ops.includes('reparent') && { previousParentId }),
|
|
661
|
+
...(!bumps && { actor: Stack.actorFrom(opts) }),
|
|
662
|
+
...(assocDelta?.added.length && { associationsAdded: assocDelta.added }),
|
|
663
|
+
...(assocDelta?.removed.length && { associationsRemoved: assocDelta.removed }),
|
|
664
|
+
});
|
|
600
665
|
return updated;
|
|
601
666
|
}
|
|
602
667
|
/**
|
|
@@ -633,6 +698,7 @@ export class Stack {
|
|
|
633
698
|
];
|
|
634
699
|
if (errors.length > 0)
|
|
635
700
|
throw new StackValidationError(errors);
|
|
701
|
+
await this.checkAttachmentAssociationPointers(associations, existing.associations);
|
|
636
702
|
let merged;
|
|
637
703
|
if (contentPatch) {
|
|
638
704
|
// The patch is what travels, so the patch is what's measured — a
|
|
@@ -696,11 +762,21 @@ export class Stack {
|
|
|
696
762
|
'least one `admin` relationship association. Name the incoming admin in the same write.');
|
|
697
763
|
}
|
|
698
764
|
/**
|
|
699
|
-
* Add an association to a record.
|
|
700
|
-
*
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
765
|
+
* Add an association to a record. Never bumps `version`/`updatedAt` and
|
|
766
|
+
* never snapshots — a set-add composes correctly regardless of write
|
|
767
|
+
* order, so it needs neither the OCC `ifVersion` guards content,
|
|
768
|
+
* `parentId` and `permissions`, nor the rollback history that guards.
|
|
769
|
+
* See docs/spec/versioning.md § Version history.
|
|
770
|
+
*
|
|
771
|
+
* An association the record already holds, saying the same thing, is a
|
|
772
|
+
* no-op; one matching an existing association's identity but naming a
|
|
773
|
+
* different `attachmentRecordId` — or none, which clears the one stored —
|
|
774
|
+
* re-points that association in place, rather than adding a second
|
|
775
|
+
* reference to the same file. The emitted event's `associationsAdded`
|
|
776
|
+
* carries the association as it now stands either way — a re-point's
|
|
777
|
+
* old `attachmentRecordId` is not reported anywhere; nothing keeps it
|
|
778
|
+
* once this call lands. See docs/spec/events.md § The event shape.
|
|
779
|
+
* Returns the record as it now stands — unchanged on a no-op.
|
|
704
780
|
*/
|
|
705
781
|
async associate(id, association, opts = {}) {
|
|
706
782
|
this.assertOpen();
|
|
@@ -711,18 +787,34 @@ export class Stack {
|
|
|
711
787
|
if (!existing) {
|
|
712
788
|
throw new StackNotFoundError(`Record not found: "${id}"`);
|
|
713
789
|
}
|
|
714
|
-
|
|
715
|
-
if ((existing.associations ?? []).some((a) => associationEqual(a, association))) {
|
|
790
|
+
if ((existing.associations ?? []).some((a) => associationIdentical(a, association))) {
|
|
716
791
|
return existing;
|
|
717
792
|
}
|
|
718
|
-
const
|
|
719
|
-
this.
|
|
793
|
+
const replaced = (existing.associations ?? []).find((a) => associationEqual(a, association));
|
|
794
|
+
await this.checkAttachmentAssociationPointers([association]);
|
|
795
|
+
const updated = await this.adapter.associate(id, association, {
|
|
796
|
+
journal: buildJournalEntry('associate', {
|
|
797
|
+
actor: Stack.actorFrom(opts),
|
|
798
|
+
associationsAdded: [association],
|
|
799
|
+
// The association this call overwrites in place, if any. Nothing
|
|
800
|
+
// else retains the attachmentRecordId it carried.
|
|
801
|
+
...(replaced && { associationsReplaced: [replaced] }),
|
|
802
|
+
}),
|
|
803
|
+
});
|
|
804
|
+
this.emitChange('associate', updated, {
|
|
805
|
+
actor: Stack.actorFrom(opts),
|
|
806
|
+
associationsAdded: [association],
|
|
807
|
+
});
|
|
720
808
|
return updated;
|
|
721
809
|
}
|
|
722
810
|
/**
|
|
723
|
-
* Remove an association from a record.
|
|
724
|
-
*
|
|
725
|
-
*
|
|
811
|
+
* Remove an association from a record. Never bumps `version`/`updatedAt`
|
|
812
|
+
* — see associate(). Matched by kind, label, and payload. No-op if not
|
|
813
|
+
* found. The emitted event's `associationsRemoved` names the association
|
|
814
|
+
* by identity only — an attachment's `attachmentRecordId` is not
|
|
815
|
+
* repeated there, since it no longer describes anything current. See
|
|
816
|
+
* docs/spec/events.md § The event shape. Returns the record as it now
|
|
817
|
+
* stands — unchanged on a no-op.
|
|
726
818
|
*/
|
|
727
819
|
async dissociate(id, association, opts = {}) {
|
|
728
820
|
this.assertOpen();
|
|
@@ -733,8 +825,8 @@ export class Stack {
|
|
|
733
825
|
if (!existing) {
|
|
734
826
|
throw new StackNotFoundError(`Record not found: "${id}"`);
|
|
735
827
|
}
|
|
736
|
-
|
|
737
|
-
if (!
|
|
828
|
+
const matched = (existing.associations ?? []).find((a) => associationEqual(a, association));
|
|
829
|
+
if (!matched) {
|
|
738
830
|
return existing;
|
|
739
831
|
}
|
|
740
832
|
// Removing anything else cannot take the roster to zero, so only an
|
|
@@ -744,8 +836,16 @@ export class Stack {
|
|
|
744
836
|
if (isGroupAdminAssociation(association)) {
|
|
745
837
|
this.assertGroupAdminRemains(existing, (existing.associations ?? []).filter((a) => !associationEqual(a, association)));
|
|
746
838
|
}
|
|
747
|
-
const updated = await this.adapter.dissociate(id, association,
|
|
748
|
-
|
|
839
|
+
const updated = await this.adapter.dissociate(id, association, {
|
|
840
|
+
journal: buildJournalEntry('dissociate', {
|
|
841
|
+
actor: Stack.actorFrom(opts),
|
|
842
|
+
associationsRemoved: [stripAssociationAnnotation(matched)],
|
|
843
|
+
}),
|
|
844
|
+
});
|
|
845
|
+
this.emitChange('dissociate', updated, {
|
|
846
|
+
actor: Stack.actorFrom(opts),
|
|
847
|
+
associationsRemoved: [stripAssociationAnnotation(matched)],
|
|
848
|
+
});
|
|
749
849
|
return updated;
|
|
750
850
|
}
|
|
751
851
|
/**
|
|
@@ -825,7 +925,7 @@ export class Stack {
|
|
|
825
925
|
expectedVersion: opts.ifVersion,
|
|
826
926
|
});
|
|
827
927
|
if (purged)
|
|
828
|
-
this.emitChange('hard-delete', purged, { actor: Stack.
|
|
928
|
+
this.emitChange('hard-delete', purged, { actor: Stack.actorFrom(opts) });
|
|
829
929
|
return;
|
|
830
930
|
}
|
|
831
931
|
const existing = await this.adapter.getRecord(id);
|
|
@@ -835,7 +935,10 @@ export class Stack {
|
|
|
835
935
|
this.checkIfVersion(existing, opts.ifVersion);
|
|
836
936
|
if (existing.deletedAt)
|
|
837
937
|
return;
|
|
838
|
-
const deleted = await this.adapter.deleteRecord(id,
|
|
938
|
+
const deleted = await this.adapter.deleteRecord(id, {
|
|
939
|
+
...this.writeOptions(existing, opts),
|
|
940
|
+
journal: buildJournalEntry('delete', { actor: Stack.actorFrom(opts) }),
|
|
941
|
+
});
|
|
839
942
|
if (deleted)
|
|
840
943
|
this.emitChange('delete', deleted);
|
|
841
944
|
}
|
|
@@ -854,7 +957,10 @@ export class Stack {
|
|
|
854
957
|
this.checkIfVersion(existing, opts.ifVersion);
|
|
855
958
|
if (!existing.deletedAt)
|
|
856
959
|
return existing;
|
|
857
|
-
const undeleted = await this.adapter.undeleteRecord(id,
|
|
960
|
+
const undeleted = await this.adapter.undeleteRecord(id, {
|
|
961
|
+
...this.writeOptions(existing, opts),
|
|
962
|
+
journal: buildJournalEntry('undelete', { actor: Stack.actorFrom(opts) }),
|
|
963
|
+
});
|
|
858
964
|
this.emitChange('undelete', undeleted);
|
|
859
965
|
return undeleted;
|
|
860
966
|
}
|
|
@@ -912,6 +1018,25 @@ export class Stack {
|
|
|
912
1018
|
this.assertOpen();
|
|
913
1019
|
return this.adapter.getVersions(id);
|
|
914
1020
|
}
|
|
1021
|
+
/**
|
|
1022
|
+
* A record's change journal, oldest first — what moved, who moved it,
|
|
1023
|
+
* and the association deltas nothing else retains. The mutation
|
|
1024
|
+
* surface's read, on the same footing as getVersions(): a log of who
|
|
1025
|
+
* changed what, gated on current read access, would make a record's past
|
|
1026
|
+
* exactly as reachable as its present. `ScopedStack` applies that gate;
|
|
1027
|
+
* this layer is unscoped and trusted by definition.
|
|
1028
|
+
*
|
|
1029
|
+
* An adapter with no journal to read refuses rather than answering an
|
|
1030
|
+
* empty log — "nothing changed" and "this stack does not remember" are
|
|
1031
|
+
* not the same answer, and a caller reconstructing an association's
|
|
1032
|
+
* history cannot tell them apart. The refusal is the adapter's own, so
|
|
1033
|
+
* it can name why. See docs/spec/versioning.md § The change journal.
|
|
1034
|
+
*/
|
|
1035
|
+
async getJournal(id, query = {}) {
|
|
1036
|
+
this.assertOpen();
|
|
1037
|
+
assertValidJournalQuery(query);
|
|
1038
|
+
return this.adapter.getJournal(id, query);
|
|
1039
|
+
}
|
|
915
1040
|
async getVersion(id, version) {
|
|
916
1041
|
this.assertOpen();
|
|
917
1042
|
return this.adapter.getVersion(id, version);
|
|
@@ -919,9 +1044,9 @@ export class Stack {
|
|
|
919
1044
|
/**
|
|
920
1045
|
* Restore a record to a previous version by creating a new version —
|
|
921
1046
|
* never rewrites history. The snapshot is validated against its own
|
|
922
|
-
* stored typeId (not the record's current type), restores
|
|
923
|
-
*
|
|
924
|
-
*
|
|
1047
|
+
* stored typeId (not the record's current type), restores `parentId`
|
|
1048
|
+
* (absent on the snapshot is the root, so a restore always settles
|
|
1049
|
+
* containment), and restores neither associations nor permissions. See
|
|
925
1050
|
* docs/spec/versioning.md § Restore semantics.
|
|
926
1051
|
*/
|
|
927
1052
|
async restoreVersion(id, version, opts = {}) {
|
|
@@ -970,11 +1095,15 @@ export class Stack {
|
|
|
970
1095
|
if (moves && targetParentId !== null) {
|
|
971
1096
|
await this.assertNoParentCycle(id, targetParentId);
|
|
972
1097
|
}
|
|
973
|
-
//
|
|
1098
|
+
// Associations never restore, for any Record — a snapshot never
|
|
1099
|
+
// carries them, so there's nothing here for the adapter to roll back.
|
|
974
1100
|
// See docs/spec/versioning.md § Restore semantics.
|
|
975
1101
|
const restored = await this.adapter.restoreVersion(id, version, {
|
|
976
1102
|
...this.writeOptions(existing, opts),
|
|
977
|
-
|
|
1103
|
+
journal: buildJournalEntry('restore', {
|
|
1104
|
+
actor: Stack.actorFrom(opts),
|
|
1105
|
+
...(moves && { previousParentId }),
|
|
1106
|
+
}),
|
|
978
1107
|
});
|
|
979
1108
|
this.emitChange('restore', restored, moves ? { previousParentId } : {});
|
|
980
1109
|
return restored;
|
|
@@ -1067,7 +1196,10 @@ export class Stack {
|
|
|
1067
1196
|
if (id === SYSTEM_TYPES.CONFIG) {
|
|
1068
1197
|
this.checkConfigEntityIdUnchanged(existing.content.entityId, content.entityId);
|
|
1069
1198
|
}
|
|
1070
|
-
const migrated = await this.adapter.commitMigration(id, toTypeId, content,
|
|
1199
|
+
const migrated = await this.adapter.commitMigration(id, toTypeId, content, {
|
|
1200
|
+
...this.writeOptions(existing, opts),
|
|
1201
|
+
journal: buildJournalEntry('migrate', { actor: Stack.actorFrom(opts) }),
|
|
1202
|
+
});
|
|
1071
1203
|
this.emitChange('migrate', migrated);
|
|
1072
1204
|
return migrated;
|
|
1073
1205
|
}
|
|
@@ -1216,6 +1348,49 @@ export class Stack {
|
|
|
1216
1348
|
]);
|
|
1217
1349
|
}
|
|
1218
1350
|
}
|
|
1351
|
+
/**
|
|
1352
|
+
* An attachment association's `attachmentRecordId` names an `_attachment`
|
|
1353
|
+
* record for the same `fileId` — checked here so a reference can't be
|
|
1354
|
+
* annotated with an unrelated record's filename.
|
|
1355
|
+
*
|
|
1356
|
+
* Best-effort, like the mimeType check above: the named record can be
|
|
1357
|
+
* deleted afterwards, so every reader of the field falls back rather than
|
|
1358
|
+
* trusting it. `stored` is what the record already holds, asked so a
|
|
1359
|
+
* change set restating an association is never refused for a pointer the
|
|
1360
|
+
* record has carried since before the named record was deleted.
|
|
1361
|
+
* See docs/spec/attachments.md § Naming the upload a reference came from.
|
|
1362
|
+
*/
|
|
1363
|
+
async checkAttachmentAssociationPointers(associations, stored = []) {
|
|
1364
|
+
const pointed = (associations ?? []).flatMap((association) => association.kind === 'attachment' &&
|
|
1365
|
+
association.attachmentRecordId !== undefined &&
|
|
1366
|
+
!stored.some((a) => associationIdentical(a, association))
|
|
1367
|
+
? [{ fileId: association.fileId, attachmentRecordId: association.attachmentRecordId }]
|
|
1368
|
+
: []);
|
|
1369
|
+
// One round trip per pointer, taken together: a change set carries a
|
|
1370
|
+
// whole association list, and each pointer is an independent read.
|
|
1371
|
+
const named = await Promise.all(pointed.map(({ attachmentRecordId }) => this.adapter.getRecord(attachmentRecordId)));
|
|
1372
|
+
pointed.forEach(({ fileId }, i) => {
|
|
1373
|
+
const record = named[i];
|
|
1374
|
+
const content = record?.content;
|
|
1375
|
+
if (record &&
|
|
1376
|
+
baseIdOf(record.typeId) === SYSTEM_TYPES.ATTACHMENT &&
|
|
1377
|
+
content?.fileId === fileId) {
|
|
1378
|
+
return;
|
|
1379
|
+
}
|
|
1380
|
+
// One message for every way of failing: a missing record and a record
|
|
1381
|
+
// for other bytes must not be distinguishable, or this becomes an
|
|
1382
|
+
// existence oracle for records the caller cannot read. A write that
|
|
1383
|
+
// succeeds does confirm the record it names, but only to a caller who
|
|
1384
|
+
// already has file access for those bytes.
|
|
1385
|
+
// See the anti-oracle rule in docs/spec/attachments.md.
|
|
1386
|
+
throw new StackValidationError([
|
|
1387
|
+
{
|
|
1388
|
+
path: 'attachmentRecordId',
|
|
1389
|
+
message: 'attachmentRecordId must name an `_attachment` record for this fileId',
|
|
1390
|
+
},
|
|
1391
|
+
]);
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1219
1394
|
/**
|
|
1220
1395
|
* filename is the only mutable field on an `_attachment@1` record; fileId,
|
|
1221
1396
|
* size and mimeType are immutable, and the correction flow is delete +
|
|
@@ -1328,7 +1503,7 @@ export class Stack {
|
|
|
1328
1503
|
deletedRecords = await this.adapter.deleteUnreferencedAttachmentRecords(fileId, await this.attachmentTypeIds());
|
|
1329
1504
|
const at = new Date();
|
|
1330
1505
|
for (const record of deletedRecords) {
|
|
1331
|
-
this.emitChange('hard-delete', record, { actor: Stack.
|
|
1506
|
+
this.emitChange('hard-delete', record, { actor: Stack.actorFrom(opts), at });
|
|
1332
1507
|
}
|
|
1333
1508
|
}
|
|
1334
1509
|
else {
|
|
@@ -1762,10 +1937,12 @@ export class Stack {
|
|
|
1762
1937
|
}
|
|
1763
1938
|
/**
|
|
1764
1939
|
* Snapshot of a record's prior state, passed with the mutating adapter
|
|
1765
|
-
* call so snapshot and mutation land in one atomic write. `
|
|
1766
|
-
*
|
|
1767
|
-
*
|
|
1768
|
-
*
|
|
1940
|
+
* call so snapshot and mutation land in one atomic write. `parentId` is
|
|
1941
|
+
* always present (`null` where the record has none) so restore can
|
|
1942
|
+
* distinguish "at the root" from a snapshot that omits the key entirely
|
|
1943
|
+
* ("leave as-is"). Never carries `associations` — associate()/
|
|
1944
|
+
* dissociate() don't bump, so no version ever snapshots the association
|
|
1945
|
+
* set, and there is nothing for a restore to roll back to. See
|
|
1769
1946
|
* docs/spec/versioning.md § Version history.
|
|
1770
1947
|
*/
|
|
1771
1948
|
buildVersionSnapshot(record) {
|
|
@@ -1778,7 +1955,6 @@ export class Stack {
|
|
|
1778
1955
|
...(record.updatedBy && { updatedBy: record.updatedBy }),
|
|
1779
1956
|
...(record.updatedVia && { updatedVia: record.updatedVia }),
|
|
1780
1957
|
...(record.parentId !== undefined && { parentId: record.parentId }),
|
|
1781
|
-
associations: record.associations ?? [],
|
|
1782
1958
|
...(record.permissions && { permissions: record.permissions }),
|
|
1783
1959
|
};
|
|
1784
1960
|
}
|