@milaboratories/pl-middle-layer 1.53.3 → 1.54.1

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 (32) hide show
  1. package/dist/js_render/computable_context.cjs +92 -85
  2. package/dist/js_render/computable_context.cjs.map +1 -1
  3. package/dist/js_render/computable_context.js +92 -84
  4. package/dist/js_render/computable_context.js.map +1 -1
  5. package/dist/js_render/context.cjs.map +1 -1
  6. package/dist/js_render/context.js.map +1 -1
  7. package/dist/js_render/service_injectors.cjs +49 -0
  8. package/dist/js_render/service_injectors.cjs.map +1 -0
  9. package/dist/js_render/service_injectors.js +48 -0
  10. package/dist/js_render/service_injectors.js.map +1 -0
  11. package/dist/middle_layer/middle_layer.cjs +10 -0
  12. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  13. package/dist/middle_layer/middle_layer.d.ts +4 -0
  14. package/dist/middle_layer/middle_layer.js +10 -0
  15. package/dist/middle_layer/middle_layer.js.map +1 -1
  16. package/dist/pool/driver.cjs +1 -0
  17. package/dist/pool/driver.cjs.map +1 -1
  18. package/dist/pool/driver.js +1 -0
  19. package/dist/pool/driver.js.map +1 -1
  20. package/dist/service_factories.cjs +22 -0
  21. package/dist/service_factories.cjs.map +1 -0
  22. package/dist/service_factories.js +21 -0
  23. package/dist/service_factories.js.map +1 -0
  24. package/package.json +20 -20
  25. package/src/js_render/computable_context.ts +105 -171
  26. package/src/js_render/context.ts +4 -4
  27. package/src/js_render/service_injectors.ts +153 -0
  28. package/src/middle_layer/middle_layer.ts +18 -0
  29. package/src/pool/driver.ts +1 -1
  30. package/src/service_factories.ts +22 -0
  31. package/dist/js_render/spec_driver.cjs +0 -2
  32. package/dist/js_render/spec_driver.js +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../../src/js_render/context.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { BlockCodeKnownFeatureFlags } from \"@platforma-sdk/model\";\nimport { JsRenderInternal } from \"@platforma-sdk/model\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport { randomUUID } from \"node:crypto\";\nimport type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { Scope, errors } from \"quickjs-emscripten\";\nimport type { BlockContextAny } from \"../middle_layer/block_ctx\";\nimport type { MiddleLayerEnvironment } from \"../middle_layer/middle_layer\";\nimport { stringifyWithResourceId } from \"@milaboratories/pl-client\";\nimport { PlQuickJSError } from \"@milaboratories/pl-errors\";\nimport { ComputableContextHelper } from \"./computable_context\";\n\nexport type DeadlineSettings = {\n currentExecutionTarget: string;\n deadline: number;\n};\n\n/**\n * Communicates a deadline to the quickjs runtime, that if passed, will interrupt the execution.\n * Undefined can be used to reset the deadline.\n * */\nexport type DeadlineSetter = (settings: DeadlineSettings | undefined) => void;\n\nfunction isArrayBufferOrView(obj: unknown): obj is ArrayBufferLike {\n return obj instanceof ArrayBuffer || ArrayBuffer.isView(obj);\n}\n\n/**\n * Contains references to objects needed to execute lambda within computable,\n * providing access to:\n * - block context\n * - computable context\n * - middle layer environment\n * */\nexport type ComputableEnv = {\n readonly blockCtx: BlockContextAny;\n readonly mlEnv: MiddleLayerEnvironment;\n computableCtx: ComputableCtx;\n};\n\n/** Execution stats accumulated during the lifetime of a JsExecutionContext. */\nexport type JsExecStats = {\n bundleEvalMs: number;\n bundleBytes: number;\n\n callbackMs: number;\n callbackCount: number;\n\n serInMs: number;\n serInBytes: number;\n serInCalls: number;\n\n serOutMs: number;\n serOutBytes: number;\n serOutCalls: number;\n\n ctxMethodCalls: number;\n ctxMethodMs: number;\n};\n\nexport class JsExecutionContext {\n private readonly callbackRegistry: QuickJSHandle;\n private readonly fnJSONStringify: QuickJSHandle;\n private readonly fnJSONParse: QuickJSHandle;\n\n public readonly errorRepo = new ErrorRepository();\n\n public readonly computableHelper: ComputableContextHelper | undefined;\n\n public readonly stats: JsExecStats = {\n bundleEvalMs: 0,\n bundleBytes: 0,\n callbackMs: 0,\n callbackCount: 0,\n serInMs: 0,\n serInBytes: 0,\n serInCalls: 0,\n serOutMs: 0,\n serOutBytes: 0,\n serOutCalls: 0,\n ctxMethodCalls: 0,\n ctxMethodMs: 0,\n };\n\n /**\n * Creates a new JS execution context.\n *\n * @param scope - QuickJS scope for memory management\n * @param vm - QuickJS VM context\n * @param deadlineSetter - Function to set execution deadline\n * @param featureFlags - Block feature flags\n * @param computableEnv - Optional reactive computable environment (for outputs, inputsValid, etc.)\n */\n constructor(\n public readonly scope: Scope,\n public readonly vm: QuickJSContext,\n private readonly deadlineSetter: DeadlineSetter,\n featureFlags: BlockCodeKnownFeatureFlags | undefined,\n computableEnv?: ComputableEnv,\n ) {\n this.callbackRegistry = this.scope.manage(this.vm.newObject());\n\n this.fnJSONStringify = scope.manage(\n vm.getProp(vm.global, \"JSON\").consume((json) => vm.getProp(json, \"stringify\")),\n );\n if (vm.typeof(this.fnJSONStringify) !== \"function\")\n throw new Error(`JSON.stringify() not found.`);\n\n this.fnJSONParse = scope.manage(\n vm.getProp(vm.global, \"JSON\").consume((json) => vm.getProp(json, \"parse\")),\n );\n if (vm.typeof(this.fnJSONParse) !== \"function\") throw new Error(`JSON.parse() not found.`);\n\n if (computableEnv !== undefined)\n this.computableHelper = new ComputableContextHelper(\n this,\n computableEnv.blockCtx,\n computableEnv.mlEnv,\n featureFlags,\n computableEnv.computableCtx,\n );\n\n this.injectCtx();\n }\n\n public resetComputableCtx() {\n notEmpty(\n this.computableHelper,\n \"Computable context helper is not initialized\",\n ).resetComputableCtx();\n }\n\n private static cleanErrorContext(error: unknown): void {\n if (typeof error === \"object\" && error !== null && \"context\" in error) delete error[\"context\"];\n }\n\n // private static cleanError(error: unknown): unknown {\n // if (error instanceof errors.QuickJSUnwrapError) {\n // const { cause, context: _, name, message, stack, ...rest } = error;\n // const clean = new errors.QuickJSUnwrapError(cause);\n // Object.assign(clean, { ...rest, name, message, stack });\n // return clean;\n // }\n // return error;\n // }\n\n public evaluateBundle(code: string) {\n const t0 = performance.now();\n try {\n this.deadlineSetter({\n currentExecutionTarget: \"evaluateBundle\",\n deadline: Date.now() + 10000,\n });\n this.vm.unwrapResult(this.vm.evalCode(code, \"bundle.js\", { type: \"global\" })).dispose();\n } catch (err: unknown) {\n JsExecutionContext.cleanErrorContext(err);\n throw err;\n } finally {\n this.deadlineSetter(undefined);\n this.stats.bundleEvalMs += performance.now() - t0;\n this.stats.bundleBytes += code.length;\n }\n }\n\n public runCallback(cbName: string, ...args: unknown[]): QuickJSHandle {\n const t0 = performance.now();\n try {\n this.deadlineSetter({ currentExecutionTarget: cbName, deadline: Date.now() + 10000 });\n return Scope.withScope((localScope) => {\n const targetCallback = localScope.manage(this.vm.getProp(this.callbackRegistry, cbName));\n\n if (this.vm.typeof(targetCallback) !== \"function\")\n throw new Error(`No such callback: ${cbName}`);\n\n return this.scope.manage(\n this.vm.unwrapResult(\n this.vm.callFunction(\n targetCallback,\n this.vm.undefined,\n ...args.map((arg) => this.exportObjectUniversal(arg, localScope)),\n ),\n ),\n );\n });\n } catch (err: unknown) {\n JsExecutionContext.cleanErrorContext(err);\n const original = this.errorRepo.getOriginal(err);\n throw original;\n } finally {\n this.deadlineSetter(undefined);\n this.stats.callbackMs += performance.now() - t0;\n this.stats.callbackCount++;\n }\n }\n\n //\n // QuickJS Helpers\n //\n\n public exportSingleValue(\n obj: boolean | number | string | null | ArrayBuffer | undefined,\n scope: Scope | undefined,\n ): QuickJSHandle {\n const result = this.tryExportSingleValue(obj, scope);\n if (result === undefined) {\n throw new Error(\n `Can't export value: ${obj === undefined ? \"undefined\" : JSON.stringify(obj)}`,\n );\n }\n return result;\n }\n\n public tryExportSingleValue(obj: unknown, scope: Scope | undefined): QuickJSHandle | undefined {\n let handle: QuickJSHandle;\n let manage = false;\n switch (typeof obj) {\n case \"string\":\n handle = this.vm.newString(obj);\n manage = true;\n break;\n case \"number\":\n handle = this.vm.newNumber(obj);\n manage = true;\n break;\n case \"undefined\":\n handle = this.vm.undefined;\n break;\n case \"boolean\":\n handle = obj ? this.vm.true : this.vm.false;\n break;\n default:\n if (obj === null) {\n handle = this.vm.null;\n break;\n }\n if (isArrayBufferOrView(obj)) {\n handle = this.vm.newArrayBuffer(obj);\n manage = true;\n break;\n }\n return undefined;\n }\n return manage && scope != undefined ? scope.manage(handle) : handle;\n }\n\n public exportObjectUniversal(obj: unknown, scope: Scope | undefined): QuickJSHandle {\n const simpleHandle = this.tryExportSingleValue(obj, scope);\n if (simpleHandle !== undefined) return simpleHandle;\n return this.exportObjectViaJson(obj, scope);\n }\n\n public exportObjectViaJson(obj: unknown, scope: Scope | undefined): QuickJSHandle {\n const t0 = performance.now();\n const json = JSON.stringify(obj);\n this.stats.serInBytes += json.length;\n this.stats.serInCalls++;\n const result = this.vm\n .newString(json)\n .consume((jsonHandle) =>\n this.vm.unwrapResult(this.vm.callFunction(this.fnJSONParse, this.vm.undefined, jsonHandle)),\n );\n this.stats.serInMs += performance.now() - t0;\n return scope !== undefined ? scope.manage(result) : result;\n }\n\n public importObjectUniversal(handle: QuickJSHandle | undefined): unknown {\n if (handle === undefined) return undefined;\n switch (this.vm.typeof(handle)) {\n case \"undefined\":\n return undefined;\n case \"boolean\":\n case \"number\":\n case \"string\":\n return this.vm.dump(handle);\n default:\n return this.importObjectViaJson(handle);\n }\n }\n\n public importObjectViaJson(handle: QuickJSHandle): unknown {\n const t0 = performance.now();\n const text = this.vm\n .unwrapResult(this.vm.callFunction(this.fnJSONStringify, this.vm.undefined, handle))\n .consume((strHandle) => this.vm.getString(strHandle));\n this.stats.serOutBytes += text.length;\n this.stats.serOutCalls++;\n if (text === \"undefined\") {\n // special case with futures\n this.stats.serOutMs += performance.now() - t0;\n return undefined;\n }\n const result = JSON.parse(text);\n this.stats.serOutMs += performance.now() - t0;\n return result;\n }\n\n private injectCtx() {\n Scope.withScope((localScope) => {\n const configCtx = localScope.manage(this.vm.newObject());\n\n //\n // Core props\n //\n\n this.vm.setProp(configCtx, \"callbackRegistry\", this.callbackRegistry);\n this.vm.setProp(\n configCtx,\n \"featureFlags\",\n this.exportObjectUniversal(JsRenderInternal.GlobalCfgRenderCtxFeatureFlags, localScope),\n );\n\n // Inject context values from computableHelper (reactive context for outputs, inputsValid, etc.)\n if (this.computableHelper !== undefined) {\n this.computableHelper.injectCtx(configCtx);\n }\n\n //\n // Creating global variable inside the vm\n //\n\n this.vm.setProp(this.vm.global, \"cfgRenderCtx\", configCtx);\n });\n }\n}\n\n/** Holds errors that happened in the host code (like in middle-layer's drivers)\n * and then throws it where the error from quick JS is needed.\n * QuickJS couldn't throw custom errors, so we store them here, and rethrow them when we exit QuickJS side. */\nexport class ErrorRepository {\n private readonly errorIdToError = new Map<string, unknown>();\n\n /** Sets the error to the repository and returns a mimicrated error that also has uuid key of the original error. */\n public setAndRecreateForQuickJS(error: unknown): {\n name: string;\n message: string;\n } {\n const errorId = randomUUID();\n this.errorIdToError.set(errorId, error);\n\n if (error instanceof Error) {\n return {\n name: `${error.name}/uuid:${errorId}`,\n message: error.message,\n };\n }\n\n return {\n name: `UnknownErrorQuickJS/uuid:${errorId}`,\n message: `${error as any}`,\n };\n }\n\n /** Returns the original error that was stored by parsing uuid of mimicrated error. */\n public getOriginal(quickJSError: unknown): unknown {\n if (!(quickJSError instanceof errors.QuickJSUnwrapError)) {\n console.warn(\n \"ErrorRepo: quickJSError is not a QuickJSUnwrapError\",\n stringifyWithResourceId(quickJSError),\n );\n return quickJSError;\n }\n\n const cause = quickJSError.cause;\n if (\n !(\n typeof cause === \"object\" &&\n cause !== null &&\n \"name\" in cause &&\n typeof cause.name === \"string\"\n )\n ) {\n console.warn(\n \"ErrorRepo: quickJSError.cause is not an Error (can be stack limit exceeded)\",\n stringifyWithResourceId(quickJSError),\n );\n return quickJSError;\n }\n\n const causeName = cause.name;\n const errorId = causeName.slice(causeName.indexOf(\"/uuid:\") + \"/uuid:\".length);\n if (!errorId) {\n throw new Error(\n `ErrorRepo: quickJSError.cause.name does not contain errorId: ${causeName}, ${stringifyWithResourceId(quickJSError)}`,\n );\n }\n\n const error = this.errorIdToError.get(errorId);\n if (error === undefined) {\n throw new Error(\n `ErrorRepo: errorId not found: ${errorId}, ${stringifyWithResourceId(quickJSError)}`,\n );\n }\n\n return new PlQuickJSError(quickJSError, error as Error);\n }\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAS,oBAAoB,KAAsC;AACjE,QAAO,eAAe,eAAe,YAAY,OAAO,IAAI;;AAoC9D,IAAa,qBAAb,MAAa,mBAAmB;CAC9B,AAAiB;CACjB,AAAiB;CACjB,AAAiB;CAEjB,AAAgB,YAAY,IAAI,iBAAiB;CAEjD,AAAgB;CAEhB,AAAgB,QAAqB;EACnC,cAAc;EACd,aAAa;EACb,YAAY;EACZ,eAAe;EACf,SAAS;EACT,YAAY;EACZ,YAAY;EACZ,UAAU;EACV,aAAa;EACb,aAAa;EACb,gBAAgB;EAChB,aAAa;EACd;;;;;;;;;;CAWD,YACE,AAAgB,OAChB,AAAgB,IAChB,AAAiB,gBACjB,cACA,eACA;EALgB;EACA;EACC;AAIjB,OAAK,mBAAmB,KAAK,MAAM,OAAO,KAAK,GAAG,WAAW,CAAC;AAE9D,OAAK,kBAAkB,MAAM,OAC3B,GAAG,QAAQ,GAAG,QAAQ,OAAO,CAAC,SAAS,SAAS,GAAG,QAAQ,MAAM,YAAY,CAAC,CAC/E;AACD,MAAI,GAAG,OAAO,KAAK,gBAAgB,KAAK,WACtC,OAAM,IAAI,MAAM,8BAA8B;AAEhD,OAAK,cAAc,MAAM,OACvB,GAAG,QAAQ,GAAG,QAAQ,OAAO,CAAC,SAAS,SAAS,GAAG,QAAQ,MAAM,QAAQ,CAAC,CAC3E;AACD,MAAI,GAAG,OAAO,KAAK,YAAY,KAAK,WAAY,OAAM,IAAI,MAAM,0BAA0B;AAE1F,MAAI,kBAAkB,OACpB,MAAK,mBAAmB,IAAI,wBAC1B,MACA,cAAc,UACd,cAAc,OACd,cACA,cAAc,cACf;AAEH,OAAK,WAAW;;CAGlB,AAAO,qBAAqB;AAC1B,WACE,KAAK,kBACL,+CACD,CAAC,oBAAoB;;CAGxB,OAAe,kBAAkB,OAAsB;AACrD,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa,MAAO,QAAO,MAAM;;CAatF,AAAO,eAAe,MAAc;EAClC,MAAM,KAAK,YAAY,KAAK;AAC5B,MAAI;AACF,QAAK,eAAe;IAClB,wBAAwB;IACxB,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC;AACF,QAAK,GAAG,aAAa,KAAK,GAAG,SAAS,MAAM,aAAa,EAAE,MAAM,UAAU,CAAC,CAAC,CAAC,SAAS;WAChF,KAAc;AACrB,sBAAmB,kBAAkB,IAAI;AACzC,SAAM;YACE;AACR,QAAK,eAAe,OAAU;AAC9B,QAAK,MAAM,gBAAgB,YAAY,KAAK,GAAG;AAC/C,QAAK,MAAM,eAAe,KAAK;;;CAInC,AAAO,YAAY,QAAgB,GAAG,MAAgC;EACpE,MAAM,KAAK,YAAY,KAAK;AAC5B,MAAI;AACF,QAAK,eAAe;IAAE,wBAAwB;IAAQ,UAAU,KAAK,KAAK,GAAG;IAAO,CAAC;AACrF,UAAO,MAAM,WAAW,eAAe;IACrC,MAAM,iBAAiB,WAAW,OAAO,KAAK,GAAG,QAAQ,KAAK,kBAAkB,OAAO,CAAC;AAExF,QAAI,KAAK,GAAG,OAAO,eAAe,KAAK,WACrC,OAAM,IAAI,MAAM,qBAAqB,SAAS;AAEhD,WAAO,KAAK,MAAM,OAChB,KAAK,GAAG,aACN,KAAK,GAAG,aACN,gBACA,KAAK,GAAG,WACR,GAAG,KAAK,KAAK,QAAQ,KAAK,sBAAsB,KAAK,WAAW,CAAC,CAClE,CACF,CACF;KACD;WACK,KAAc;AACrB,sBAAmB,kBAAkB,IAAI;AAEzC,SADiB,KAAK,UAAU,YAAY,IAAI;YAExC;AACR,QAAK,eAAe,OAAU;AAC9B,QAAK,MAAM,cAAc,YAAY,KAAK,GAAG;AAC7C,QAAK,MAAM;;;CAQf,AAAO,kBACL,KACA,OACe;EACf,MAAM,SAAS,KAAK,qBAAqB,KAAK,MAAM;AACpD,MAAI,WAAW,OACb,OAAM,IAAI,MACR,uBAAuB,QAAQ,SAAY,cAAc,KAAK,UAAU,IAAI,GAC7E;AAEH,SAAO;;CAGT,AAAO,qBAAqB,KAAc,OAAqD;EAC7F,IAAI;EACJ,IAAI,SAAS;AACb,UAAQ,OAAO,KAAf;GACE,KAAK;AACH,aAAS,KAAK,GAAG,UAAU,IAAI;AAC/B,aAAS;AACT;GACF,KAAK;AACH,aAAS,KAAK,GAAG,UAAU,IAAI;AAC/B,aAAS;AACT;GACF,KAAK;AACH,aAAS,KAAK,GAAG;AACjB;GACF,KAAK;AACH,aAAS,MAAM,KAAK,GAAG,OAAO,KAAK,GAAG;AACtC;GACF;AACE,QAAI,QAAQ,MAAM;AAChB,cAAS,KAAK,GAAG;AACjB;;AAEF,QAAI,oBAAoB,IAAI,EAAE;AAC5B,cAAS,KAAK,GAAG,eAAe,IAAI;AACpC,cAAS;AACT;;AAEF;;AAEJ,SAAO,UAAU,SAAS,SAAY,MAAM,OAAO,OAAO,GAAG;;CAG/D,AAAO,sBAAsB,KAAc,OAAyC;EAClF,MAAM,eAAe,KAAK,qBAAqB,KAAK,MAAM;AAC1D,MAAI,iBAAiB,OAAW,QAAO;AACvC,SAAO,KAAK,oBAAoB,KAAK,MAAM;;CAG7C,AAAO,oBAAoB,KAAc,OAAyC;EAChF,MAAM,KAAK,YAAY,KAAK;EAC5B,MAAM,OAAO,KAAK,UAAU,IAAI;AAChC,OAAK,MAAM,cAAc,KAAK;AAC9B,OAAK,MAAM;EACX,MAAM,SAAS,KAAK,GACjB,UAAU,KAAK,CACf,SAAS,eACR,KAAK,GAAG,aAAa,KAAK,GAAG,aAAa,KAAK,aAAa,KAAK,GAAG,WAAW,WAAW,CAAC,CAC5F;AACH,OAAK,MAAM,WAAW,YAAY,KAAK,GAAG;AAC1C,SAAO,UAAU,SAAY,MAAM,OAAO,OAAO,GAAG;;CAGtD,AAAO,sBAAsB,QAA4C;AACvE,MAAI,WAAW,OAAW,QAAO;AACjC,UAAQ,KAAK,GAAG,OAAO,OAAO,EAA9B;GACE,KAAK,YACH;GACF,KAAK;GACL,KAAK;GACL,KAAK,SACH,QAAO,KAAK,GAAG,KAAK,OAAO;GAC7B,QACE,QAAO,KAAK,oBAAoB,OAAO;;;CAI7C,AAAO,oBAAoB,QAAgC;EACzD,MAAM,KAAK,YAAY,KAAK;EAC5B,MAAM,OAAO,KAAK,GACf,aAAa,KAAK,GAAG,aAAa,KAAK,iBAAiB,KAAK,GAAG,WAAW,OAAO,CAAC,CACnF,SAAS,cAAc,KAAK,GAAG,UAAU,UAAU,CAAC;AACvD,OAAK,MAAM,eAAe,KAAK;AAC/B,OAAK,MAAM;AACX,MAAI,SAAS,aAAa;AAExB,QAAK,MAAM,YAAY,YAAY,KAAK,GAAG;AAC3C;;EAEF,MAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,OAAK,MAAM,YAAY,YAAY,KAAK,GAAG;AAC3C,SAAO;;CAGT,AAAQ,YAAY;AAClB,QAAM,WAAW,eAAe;GAC9B,MAAM,YAAY,WAAW,OAAO,KAAK,GAAG,WAAW,CAAC;AAMxD,QAAK,GAAG,QAAQ,WAAW,oBAAoB,KAAK,iBAAiB;AACrE,QAAK,GAAG,QACN,WACA,gBACA,KAAK,sBAAsB,iBAAiB,gCAAgC,WAAW,CACxF;AAGD,OAAI,KAAK,qBAAqB,OAC5B,MAAK,iBAAiB,UAAU,UAAU;AAO5C,QAAK,GAAG,QAAQ,KAAK,GAAG,QAAQ,gBAAgB,UAAU;IAC1D;;;;;;AAON,IAAa,kBAAb,MAA6B;CAC3B,AAAiB,iCAAiB,IAAI,KAAsB;;CAG5D,AAAO,yBAAyB,OAG9B;EACA,MAAM,UAAU,YAAY;AAC5B,OAAK,eAAe,IAAI,SAAS,MAAM;AAEvC,MAAI,iBAAiB,MACnB,QAAO;GACL,MAAM,GAAG,MAAM,KAAK,QAAQ;GAC5B,SAAS,MAAM;GAChB;AAGH,SAAO;GACL,MAAM,4BAA4B;GAClC,SAAS,GAAG;GACb;;;CAIH,AAAO,YAAY,cAAgC;AACjD,MAAI,EAAE,wBAAwB,OAAO,qBAAqB;AACxD,WAAQ,KACN,uDACA,wBAAwB,aAAa,CACtC;AACD,UAAO;;EAGT,MAAM,QAAQ,aAAa;AAC3B,MACE,EACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAO,MAAM,SAAS,WAExB;AACA,WAAQ,KACN,+EACA,wBAAwB,aAAa,CACtC;AACD,UAAO;;EAGT,MAAM,YAAY,MAAM;EACxB,MAAM,UAAU,UAAU,MAAM,UAAU,QAAQ,SAAS,GAAG,EAAgB;AAC9E,MAAI,CAAC,QACH,OAAM,IAAI,MACR,gEAAgE,UAAU,IAAI,wBAAwB,aAAa,GACpH;EAGH,MAAM,QAAQ,KAAK,eAAe,IAAI,QAAQ;AAC9C,MAAI,UAAU,OACZ,OAAM,IAAI,MACR,iCAAiC,QAAQ,IAAI,wBAAwB,aAAa,GACnF;AAGH,SAAO,IAAI,eAAe,cAAc,MAAe"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/js_render/context.ts"],"sourcesContent":["import type { ComputableCtx } from \"@milaboratories/computable\";\nimport type { BlockCodeKnownFeatureFlags } from \"@platforma-sdk/model\";\nimport { JsRenderInternal } from \"@platforma-sdk/model\";\nimport { notEmpty } from \"@milaboratories/ts-helpers\";\nimport { randomUUID } from \"node:crypto\";\nimport type { QuickJSContext, QuickJSHandle } from \"quickjs-emscripten\";\nimport { Scope, errors } from \"quickjs-emscripten\";\nimport type { BlockContextAny } from \"../middle_layer/block_ctx\";\nimport type { MiddleLayerEnvironment } from \"../middle_layer/middle_layer\";\nimport { stringifyWithResourceId } from \"@milaboratories/pl-client\";\nimport { PlQuickJSError } from \"@milaboratories/pl-errors\";\nimport { ComputableContextHelper } from \"./computable_context\";\n\nexport type DeadlineSettings = {\n currentExecutionTarget: string;\n deadline: number;\n};\n\n/**\n * Communicates a deadline to the quickjs runtime, that if passed, will interrupt the execution.\n * Undefined can be used to reset the deadline.\n * */\nexport type DeadlineSetter = (settings: DeadlineSettings | undefined) => void;\n\nfunction isArrayBufferOrView(obj: unknown): obj is ArrayBufferLike {\n return obj instanceof ArrayBuffer || ArrayBuffer.isView(obj);\n}\n\n/**\n * Contains references to objects needed to execute lambda within computable,\n * providing access to:\n * - block context\n * - computable context\n * - middle layer environment\n * */\nexport type ComputableEnv = {\n readonly blockCtx: BlockContextAny;\n readonly mlEnv: MiddleLayerEnvironment;\n computableCtx: ComputableCtx;\n};\n\n/** Execution stats accumulated during the lifetime of a JsExecutionContext. */\nexport type JsExecStats = {\n bundleEvalMs: number;\n bundleBytes: number;\n\n callbackMs: number;\n callbackCount: number;\n\n serInMs: number;\n serInBytes: number;\n serInCalls: number;\n\n serOutMs: number;\n serOutBytes: number;\n serOutCalls: number;\n\n ctxMethodCalls: number;\n ctxMethodMs: number;\n};\n\nexport class JsExecutionContext {\n private readonly callbackRegistry: QuickJSHandle;\n private readonly fnJSONStringify: QuickJSHandle;\n private readonly fnJSONParse: QuickJSHandle;\n\n public readonly errorRepo = new ErrorRepository();\n\n public readonly computableHelper: ComputableContextHelper | undefined;\n\n public readonly stats: JsExecStats = {\n bundleEvalMs: 0,\n bundleBytes: 0,\n callbackMs: 0,\n callbackCount: 0,\n serInMs: 0,\n serInBytes: 0,\n serInCalls: 0,\n serOutMs: 0,\n serOutBytes: 0,\n serOutCalls: 0,\n ctxMethodCalls: 0,\n ctxMethodMs: 0,\n };\n\n /**\n * Creates a new JS execution context.\n *\n * @param scope - QuickJS scope for memory management\n * @param vm - QuickJS VM context\n * @param deadlineSetter - Function to set execution deadline\n * @param featureFlags - Block feature flags\n * @param computableEnv - Optional reactive computable environment (for outputs, inputsValid, etc.)\n */\n constructor(\n public readonly scope: Scope,\n public readonly vm: QuickJSContext,\n private readonly deadlineSetter: DeadlineSetter,\n featureFlags: BlockCodeKnownFeatureFlags | undefined,\n computableEnv?: ComputableEnv,\n ) {\n this.callbackRegistry = this.scope.manage(this.vm.newObject());\n\n this.fnJSONStringify = scope.manage(\n vm.getProp(vm.global, \"JSON\").consume((json) => vm.getProp(json, \"stringify\")),\n );\n if (vm.typeof(this.fnJSONStringify) !== \"function\")\n throw new Error(`JSON.stringify() not found.`);\n\n this.fnJSONParse = scope.manage(\n vm.getProp(vm.global, \"JSON\").consume((json) => vm.getProp(json, \"parse\")),\n );\n if (vm.typeof(this.fnJSONParse) !== \"function\") throw new Error(`JSON.parse() not found.`);\n\n if (computableEnv !== undefined)\n this.computableHelper = new ComputableContextHelper(\n this,\n computableEnv.blockCtx,\n computableEnv.mlEnv,\n featureFlags,\n computableEnv.computableCtx,\n );\n\n this.injectCtx();\n }\n\n public resetComputableCtx() {\n notEmpty(\n this.computableHelper,\n \"Computable context helper is not initialized\",\n ).resetComputableCtx();\n }\n\n private static cleanErrorContext(error: unknown): void {\n if (typeof error === \"object\" && error !== null && \"context\" in error) delete error[\"context\"];\n }\n\n // private static cleanError(error: unknown): unknown {\n // if (error instanceof errors.QuickJSUnwrapError) {\n // const { cause, context: _, name, message, stack, ...rest } = error;\n // const clean = new errors.QuickJSUnwrapError(cause);\n // Object.assign(clean, { ...rest, name, message, stack });\n // return clean;\n // }\n // return error;\n // }\n\n public evaluateBundle(code: string) {\n const t0 = performance.now();\n try {\n this.deadlineSetter({\n currentExecutionTarget: \"evaluateBundle\",\n deadline: Date.now() + 10000,\n });\n this.vm.unwrapResult(this.vm.evalCode(code, \"bundle.js\", { type: \"global\" })).dispose();\n } catch (err: unknown) {\n JsExecutionContext.cleanErrorContext(err);\n throw err;\n } finally {\n this.deadlineSetter(undefined);\n this.stats.bundleEvalMs += performance.now() - t0;\n this.stats.bundleBytes += code.length;\n }\n }\n\n public runCallback(cbName: string, ...args: unknown[]): QuickJSHandle {\n const t0 = performance.now();\n try {\n this.deadlineSetter({ currentExecutionTarget: cbName, deadline: Date.now() + 10000 });\n return Scope.withScope((localScope) => {\n const targetCallback = localScope.manage(this.vm.getProp(this.callbackRegistry, cbName));\n\n if (this.vm.typeof(targetCallback) !== \"function\")\n throw new Error(`No such callback: ${cbName}`);\n\n return this.scope.manage(\n this.vm.unwrapResult(\n this.vm.callFunction(\n targetCallback,\n this.vm.undefined,\n ...args.map((arg) => this.exportObjectUniversal(arg, localScope)),\n ),\n ),\n );\n });\n } catch (err: unknown) {\n JsExecutionContext.cleanErrorContext(err);\n const original = this.errorRepo.getOriginal(err);\n throw original;\n } finally {\n this.deadlineSetter(undefined);\n this.stats.callbackMs += performance.now() - t0;\n this.stats.callbackCount++;\n }\n }\n\n //\n // QuickJS Helpers\n //\n\n public exportSingleValue(\n obj: boolean | number | string | null | ArrayBuffer | undefined,\n scope?: Scope,\n ): QuickJSHandle {\n const result = this.tryExportSingleValue(obj, scope);\n if (result === undefined) {\n throw new Error(\n `Can't export value: ${obj === undefined ? \"undefined\" : JSON.stringify(obj)}`,\n );\n }\n return result;\n }\n\n public tryExportSingleValue(obj: unknown, scope?: Scope): QuickJSHandle | undefined {\n let handle: QuickJSHandle;\n let manage = false;\n switch (typeof obj) {\n case \"string\":\n handle = this.vm.newString(obj);\n manage = true;\n break;\n case \"number\":\n handle = this.vm.newNumber(obj);\n manage = true;\n break;\n case \"undefined\":\n handle = this.vm.undefined;\n break;\n case \"boolean\":\n handle = obj ? this.vm.true : this.vm.false;\n break;\n default:\n if (obj === null) {\n handle = this.vm.null;\n break;\n }\n if (isArrayBufferOrView(obj)) {\n handle = this.vm.newArrayBuffer(obj);\n manage = true;\n break;\n }\n return undefined;\n }\n return manage && scope != undefined ? scope.manage(handle) : handle;\n }\n\n public exportObjectUniversal(obj: unknown, scope?: Scope): QuickJSHandle {\n const simpleHandle = this.tryExportSingleValue(obj, scope);\n if (simpleHandle !== undefined) return simpleHandle;\n return this.exportObjectViaJson(obj, scope);\n }\n\n public exportObjectViaJson(obj: unknown, scope?: Scope): QuickJSHandle {\n const t0 = performance.now();\n const json = JSON.stringify(obj);\n this.stats.serInBytes += json.length;\n this.stats.serInCalls++;\n const result = this.vm\n .newString(json)\n .consume((jsonHandle) =>\n this.vm.unwrapResult(this.vm.callFunction(this.fnJSONParse, this.vm.undefined, jsonHandle)),\n );\n this.stats.serInMs += performance.now() - t0;\n return scope !== undefined ? scope.manage(result) : result;\n }\n\n public importObjectUniversal(handle: QuickJSHandle | undefined): unknown {\n if (handle === undefined) return undefined;\n switch (this.vm.typeof(handle)) {\n case \"undefined\":\n return undefined;\n case \"boolean\":\n case \"number\":\n case \"string\":\n return this.vm.dump(handle);\n default:\n return this.importObjectViaJson(handle);\n }\n }\n\n public importObjectViaJson(handle: QuickJSHandle): unknown {\n const t0 = performance.now();\n const text = this.vm\n .unwrapResult(this.vm.callFunction(this.fnJSONStringify, this.vm.undefined, handle))\n .consume((strHandle) => this.vm.getString(strHandle));\n this.stats.serOutBytes += text.length;\n this.stats.serOutCalls++;\n if (text === \"undefined\") {\n // special case with futures\n this.stats.serOutMs += performance.now() - t0;\n return undefined;\n }\n const result = JSON.parse(text);\n this.stats.serOutMs += performance.now() - t0;\n return result;\n }\n\n private injectCtx() {\n Scope.withScope((localScope) => {\n const configCtx = localScope.manage(this.vm.newObject());\n\n //\n // Core props\n //\n\n this.vm.setProp(configCtx, \"callbackRegistry\", this.callbackRegistry);\n this.vm.setProp(\n configCtx,\n \"featureFlags\",\n this.exportObjectUniversal(JsRenderInternal.GlobalCfgRenderCtxFeatureFlags, localScope),\n );\n\n // Inject context values from computableHelper (reactive context for outputs, inputsValid, etc.)\n if (this.computableHelper !== undefined) {\n this.computableHelper.injectCtx(configCtx);\n }\n\n //\n // Creating global variable inside the vm\n //\n\n this.vm.setProp(this.vm.global, \"cfgRenderCtx\", configCtx);\n });\n }\n}\n\n/** Holds errors that happened in the host code (like in middle-layer's drivers)\n * and then throws it where the error from quick JS is needed.\n * QuickJS couldn't throw custom errors, so we store them here, and rethrow them when we exit QuickJS side. */\nexport class ErrorRepository {\n private readonly errorIdToError = new Map<string, unknown>();\n\n /** Sets the error to the repository and returns a mimicrated error that also has uuid key of the original error. */\n public setAndRecreateForQuickJS(error: unknown): {\n name: string;\n message: string;\n } {\n const errorId = randomUUID();\n this.errorIdToError.set(errorId, error);\n\n if (error instanceof Error) {\n return {\n name: `${error.name}/uuid:${errorId}`,\n message: error.message,\n };\n }\n\n return {\n name: `UnknownErrorQuickJS/uuid:${errorId}`,\n message: `${error as any}`,\n };\n }\n\n /** Returns the original error that was stored by parsing uuid of mimicrated error. */\n public getOriginal(quickJSError: unknown): unknown {\n if (!(quickJSError instanceof errors.QuickJSUnwrapError)) {\n console.warn(\n \"ErrorRepo: quickJSError is not a QuickJSUnwrapError\",\n stringifyWithResourceId(quickJSError),\n );\n return quickJSError;\n }\n\n const cause = quickJSError.cause;\n if (\n !(\n typeof cause === \"object\" &&\n cause !== null &&\n \"name\" in cause &&\n typeof cause.name === \"string\"\n )\n ) {\n console.warn(\n \"ErrorRepo: quickJSError.cause is not an Error (can be stack limit exceeded)\",\n stringifyWithResourceId(quickJSError),\n );\n return quickJSError;\n }\n\n const causeName = cause.name;\n const errorId = causeName.slice(causeName.indexOf(\"/uuid:\") + \"/uuid:\".length);\n if (!errorId) {\n throw new Error(\n `ErrorRepo: quickJSError.cause.name does not contain errorId: ${causeName}, ${stringifyWithResourceId(quickJSError)}`,\n );\n }\n\n const error = this.errorIdToError.get(errorId);\n if (error === undefined) {\n throw new Error(\n `ErrorRepo: errorId not found: ${errorId}, ${stringifyWithResourceId(quickJSError)}`,\n );\n }\n\n return new PlQuickJSError(quickJSError, error as Error);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ const require_runtime = require('../_virtual/_rolldown/runtime.cjs');
2
+ const require_usingCtx = require('../_virtual/_@oxc-project_runtime@0.114.0/helpers/usingCtx.cjs');
3
+ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
4
+
5
+ //#region src/js_render/service_injectors.ts
6
+ function getServiceInjectors() {
7
+ return {
8
+ PFrameSpec: ({ host, vm }) => {
9
+ const driver = host.serviceRegistry.get(_milaboratories_pl_model_common.Services.PFrameSpec);
10
+ if (!driver) throw new _milaboratories_pl_model_common.ServiceNotRegisteredError(`Service "${_milaboratories_pl_model_common.Services.PFrameSpec}" has no factory in ModelServiceRegistry. Provide a non-null factory.`);
11
+ return {
12
+ createSpecFrame: (specs) => {
13
+ try {
14
+ var _usingCtx$1 = require_usingCtx._usingCtx();
15
+ const guard = _usingCtx$1.u(new _milaboratories_pl_model_common.PoolEntryGuard(driver.createSpecFrame(vm.importObjectViaJson(specs))));
16
+ host.addOnDestroy(guard.entry.unref);
17
+ const entry = guard.keep();
18
+ const obj = vm.vm.newObject();
19
+ vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, "key", k));
20
+ vm.vm.newFunction("unref", () => {
21
+ entry.unref();
22
+ }).consume((fn) => vm.vm.setProp(obj, "unref", fn));
23
+ return obj;
24
+ } catch (_) {
25
+ _usingCtx$1.e = _;
26
+ } finally {
27
+ _usingCtx$1.d();
28
+ }
29
+ },
30
+ discoverColumns: (handle, request) => vm.exportObjectViaJson(driver.discoverColumns(vm.vm.getString(handle), vm.importObjectViaJson(request))),
31
+ deleteColumn: (handle, request) => vm.exportObjectViaJson(driver.deleteColumn(vm.vm.getString(handle), vm.importObjectViaJson(request))),
32
+ evaluateQuery: (handle, request) => vm.exportObjectViaJson(driver.evaluateQuery(vm.vm.getString(handle), vm.importObjectViaJson(request))),
33
+ expandAxes: (spec) => vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec))),
34
+ collapseAxes: (ids) => vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids))),
35
+ findAxis: (spec, selector) => vm.exportSingleValue(driver.findAxis(vm.importObjectViaJson(spec), vm.importObjectViaJson(selector))),
36
+ findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector)))
37
+ };
38
+ },
39
+ PFrame: ({ host, vm }) => ({
40
+ createPFrame: (def) => vm.exportSingleValue(host.createPFrame(vm.importObjectViaJson(def))),
41
+ createPTable: (def) => vm.exportSingleValue(host.createPTable(vm.importObjectViaJson(def))),
42
+ createPTableV2: (def) => vm.exportSingleValue(host.createPTableV2(vm.importObjectViaJson(def)))
43
+ })
44
+ };
45
+ }
46
+
47
+ //#endregion
48
+ exports.getServiceInjectors = getServiceInjectors;
49
+ //# sourceMappingURL=service_injectors.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service_injectors.cjs","names":["Services","ServiceNotRegisteredError","PoolEntryGuard"],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n };\n },\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;;;AAgDA,SAAgB,sBAA0C;AACxD,QAAO;EACL,aAAa,EAAE,MAAM,SAAiC;GACpD,MAAM,SAAS,KAAK,gBAAgB,IAAIA,yCAAS,WAAW;AAC5D,OAAI,CAAC,OACH,OAAM,IAAIC,0DACR,YAAYD,yCAAS,WAAW,uEACjC;AAEH,UAAO;IACL,kBAAkB,UAAyB;;;MACzC,MAAM,sBAAQ,IAAIE,+CAChB,OAAO,gBAAgB,GAAG,oBAAoB,MAAM,CAAgC,CACrF;AACD,WAAK,aAAa,MAAM,MAAM,MAAM;MACpC,MAAM,QAAQ,MAAM,MAAM;MAE1B,MAAM,MAAM,GAAG,GAAG,WAAW;AAC7B,SAAG,GAAG,UAAU,MAAM,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,EAAE,CAAC;AACvE,SAAG,GACA,YAAY,eAAe;AAC1B,aAAM,OAAO;QACb,CACD,SAAS,OAAO,GAAG,GAAG,QAAQ,KAAK,SAAS,GAAG,CAAC;AACnD,aAAO;;;;;;;IAGT,kBAAkB,QAAuB,YACvC,GAAG,oBACD,OAAO,gBACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,eAAe,QAAuB,YACpC,GAAG,oBACD,OAAO,aACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,gBAAgB,QAAuB,YACrC,GAAG,oBACD,OAAO,cACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,SACX,GAAG,oBAAoB,OAAO,WAAW,GAAG,oBAAoB,KAAK,CAAa,CAAC;IAErF,eAAe,QACb,GAAG,oBAAoB,OAAO,aAAa,GAAG,oBAAoB,IAAI,CAAW,CAAC;IAEpF,WAAW,MAAqB,aAC9B,GAAG,kBACD,OAAO,SACL,GAAG,oBAAoB,KAAK,EAC5B,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,kBAAkB,WAA0B,aAC1C,GAAG,kBACD,OAAO,gBACL,GAAG,oBAAoB,UAAU,EACjC,GAAG,oBAAoB,SAAS,CACjC,CACF;IACJ;;EAGH,SAAS,EAAE,MAAM,UAAkC;GACjD,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,iBAAiB,QACf,GAAG,kBACD,KAAK,eACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GACJ;EACF"}
@@ -0,0 +1,48 @@
1
+ import { _usingCtx } from "../_virtual/_@oxc-project_runtime@0.114.0/helpers/usingCtx.js";
2
+ import { PoolEntryGuard, ServiceNotRegisteredError, Services } from "@milaboratories/pl-model-common";
3
+
4
+ //#region src/js_render/service_injectors.ts
5
+ function getServiceInjectors() {
6
+ return {
7
+ PFrameSpec: ({ host, vm }) => {
8
+ const driver = host.serviceRegistry.get(Services.PFrameSpec);
9
+ if (!driver) throw new ServiceNotRegisteredError(`Service "${Services.PFrameSpec}" has no factory in ModelServiceRegistry. Provide a non-null factory.`);
10
+ return {
11
+ createSpecFrame: (specs) => {
12
+ try {
13
+ var _usingCtx$1 = _usingCtx();
14
+ const guard = _usingCtx$1.u(new PoolEntryGuard(driver.createSpecFrame(vm.importObjectViaJson(specs))));
15
+ host.addOnDestroy(guard.entry.unref);
16
+ const entry = guard.keep();
17
+ const obj = vm.vm.newObject();
18
+ vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, "key", k));
19
+ vm.vm.newFunction("unref", () => {
20
+ entry.unref();
21
+ }).consume((fn) => vm.vm.setProp(obj, "unref", fn));
22
+ return obj;
23
+ } catch (_) {
24
+ _usingCtx$1.e = _;
25
+ } finally {
26
+ _usingCtx$1.d();
27
+ }
28
+ },
29
+ discoverColumns: (handle, request) => vm.exportObjectViaJson(driver.discoverColumns(vm.vm.getString(handle), vm.importObjectViaJson(request))),
30
+ deleteColumn: (handle, request) => vm.exportObjectViaJson(driver.deleteColumn(vm.vm.getString(handle), vm.importObjectViaJson(request))),
31
+ evaluateQuery: (handle, request) => vm.exportObjectViaJson(driver.evaluateQuery(vm.vm.getString(handle), vm.importObjectViaJson(request))),
32
+ expandAxes: (spec) => vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec))),
33
+ collapseAxes: (ids) => vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids))),
34
+ findAxis: (spec, selector) => vm.exportSingleValue(driver.findAxis(vm.importObjectViaJson(spec), vm.importObjectViaJson(selector))),
35
+ findTableColumn: (tableSpec, selector) => vm.exportSingleValue(driver.findTableColumn(vm.importObjectViaJson(tableSpec), vm.importObjectViaJson(selector)))
36
+ };
37
+ },
38
+ PFrame: ({ host, vm }) => ({
39
+ createPFrame: (def) => vm.exportSingleValue(host.createPFrame(vm.importObjectViaJson(def))),
40
+ createPTable: (def) => vm.exportSingleValue(host.createPTable(vm.importObjectViaJson(def))),
41
+ createPTableV2: (def) => vm.exportSingleValue(host.createPTableV2(vm.importObjectViaJson(def)))
42
+ })
43
+ };
44
+ }
45
+
46
+ //#endregion
47
+ export { getServiceInjectors };
48
+ //# sourceMappingURL=service_injectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service_injectors.js","names":[],"sources":["../../src/js_render/service_injectors.ts"],"sourcesContent":["import type { QuickJSHandle, VmFunctionImplementation } from \"quickjs-emscripten\";\nimport type { InferServiceModel, ServiceBrand } from \"@milaboratories/pl-model-common\";\nimport { Services, ServiceNotRegisteredError } from \"@milaboratories/pl-model-common\";\nimport type {\n AxesId,\n AxesSpec,\n DataInfo,\n PColumn,\n PColumnSpec,\n PColumnValues,\n PTableColumnId,\n PTableColumnSpec,\n SingleAxisSelector,\n DeleteColumnRequest,\n DiscoverColumnsRequest,\n PFrameDef,\n SpecQuery,\n PTableDef,\n PTableDefV2,\n SpecFrameHandle,\n} from \"@milaboratories/pl-model-common\";\nimport { PoolEntryGuard } from \"@milaboratories/pl-model-common\";\nimport type { JsExecutionContext } from \"./context\";\nimport type { ComputableContextHelper } from \"./computable_context\";\n\ntype VmMethod = VmFunctionImplementation<QuickJSHandle>;\n\nexport type ServiceInjectorContext = {\n host: ComputableContextHelper;\n vm: JsExecutionContext;\n};\n\n// Each injector returns a record of method name -> VM function implementation.\n// The framework automatically registers them with serviceFnKey(serviceId, methodName).\nexport type ServiceInjector<Methods extends string = string> = (\n ctx: ServiceInjectorContext,\n) => Record<Methods, VmMethod>;\n\n// Type-safe injector for a specific service — must return all methods from the model interface.\ntype ServiceInjectorFor<S extends keyof typeof Services> = ServiceInjector<\n string & keyof InferServiceModel<ServiceBrand<(typeof Services)[S]>>\n>;\n\n// Complete, type-checked injector map.\n// Adding a service to Services without an entry here is a compile-time error.\n// Missing a method from the interface is also a compile-time error.\ntype ServiceInjectorMap = { [K in keyof typeof Services]: ServiceInjectorFor<K> };\n\nexport function getServiceInjectors(): ServiceInjectorMap {\n return {\n PFrameSpec: ({ host, vm }: ServiceInjectorContext) => {\n const driver = host.serviceRegistry.get(Services.PFrameSpec);\n if (!driver)\n throw new ServiceNotRegisteredError(\n `Service \"${Services.PFrameSpec}\" has no factory in ModelServiceRegistry. Provide a non-null factory.`,\n );\n\n return {\n createSpecFrame: (specs: QuickJSHandle) => {\n using guard = new PoolEntryGuard(\n driver.createSpecFrame(vm.importObjectViaJson(specs) as Record<string, PColumnSpec>),\n );\n host.addOnDestroy(guard.entry.unref);\n const entry = guard.keep();\n // TODO: add [Symbol.dispose] once QuickJS supports ES2024 explicit resource management\n const obj = vm.vm.newObject();\n vm.vm.newString(entry.key).consume((k) => vm.vm.setProp(obj, \"key\", k));\n vm.vm\n .newFunction(\"unref\", () => {\n entry.unref();\n })\n .consume((fn) => vm.vm.setProp(obj, \"unref\", fn));\n return obj;\n },\n\n discoverColumns: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.discoverColumns(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DiscoverColumnsRequest,\n ),\n ),\n\n deleteColumn: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.deleteColumn(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as DeleteColumnRequest,\n ),\n ),\n\n evaluateQuery: (handle: QuickJSHandle, request: QuickJSHandle) =>\n vm.exportObjectViaJson(\n driver.evaluateQuery(\n vm.vm.getString(handle) as SpecFrameHandle,\n vm.importObjectViaJson(request) as SpecQuery,\n ),\n ),\n\n expandAxes: (spec: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.expandAxes(vm.importObjectViaJson(spec) as AxesSpec)),\n\n collapseAxes: (ids: QuickJSHandle) =>\n vm.exportObjectViaJson(driver.collapseAxes(vm.importObjectViaJson(ids) as AxesId)),\n\n findAxis: (spec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findAxis(\n vm.importObjectViaJson(spec) as AxesSpec,\n vm.importObjectViaJson(selector) as SingleAxisSelector,\n ),\n ),\n\n findTableColumn: (tableSpec: QuickJSHandle, selector: QuickJSHandle) =>\n vm.exportSingleValue(\n driver.findTableColumn(\n vm.importObjectViaJson(tableSpec) as PTableColumnSpec[],\n vm.importObjectViaJson(selector) as PTableColumnId,\n ),\n ),\n };\n },\n\n PFrame: ({ host, vm }: ServiceInjectorContext) => ({\n createPFrame: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPFrame(\n vm.importObjectViaJson(def) as PFrameDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTable: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTable(\n vm.importObjectViaJson(def) as PTableDef<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n\n createPTableV2: (def: QuickJSHandle) =>\n vm.exportSingleValue(\n host.createPTableV2(\n vm.importObjectViaJson(def) as PTableDefV2<\n PColumn<string | PColumnValues | DataInfo<string>>\n >,\n ),\n ),\n }),\n };\n}\n"],"mappings":";;;;AAgDA,SAAgB,sBAA0C;AACxD,QAAO;EACL,aAAa,EAAE,MAAM,SAAiC;GACpD,MAAM,SAAS,KAAK,gBAAgB,IAAI,SAAS,WAAW;AAC5D,OAAI,CAAC,OACH,OAAM,IAAI,0BACR,YAAY,SAAS,WAAW,uEACjC;AAEH,UAAO;IACL,kBAAkB,UAAyB;;;MACzC,MAAM,sBAAQ,IAAI,eAChB,OAAO,gBAAgB,GAAG,oBAAoB,MAAM,CAAgC,CACrF;AACD,WAAK,aAAa,MAAM,MAAM,MAAM;MACpC,MAAM,QAAQ,MAAM,MAAM;MAE1B,MAAM,MAAM,GAAG,GAAG,WAAW;AAC7B,SAAG,GAAG,UAAU,MAAM,IAAI,CAAC,SAAS,MAAM,GAAG,GAAG,QAAQ,KAAK,OAAO,EAAE,CAAC;AACvE,SAAG,GACA,YAAY,eAAe;AAC1B,aAAM,OAAO;QACb,CACD,SAAS,OAAO,GAAG,GAAG,QAAQ,KAAK,SAAS,GAAG,CAAC;AACnD,aAAO;;;;;;;IAGT,kBAAkB,QAAuB,YACvC,GAAG,oBACD,OAAO,gBACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,eAAe,QAAuB,YACpC,GAAG,oBACD,OAAO,aACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,gBAAgB,QAAuB,YACrC,GAAG,oBACD,OAAO,cACL,GAAG,GAAG,UAAU,OAAO,EACvB,GAAG,oBAAoB,QAAQ,CAChC,CACF;IAEH,aAAa,SACX,GAAG,oBAAoB,OAAO,WAAW,GAAG,oBAAoB,KAAK,CAAa,CAAC;IAErF,eAAe,QACb,GAAG,oBAAoB,OAAO,aAAa,GAAG,oBAAoB,IAAI,CAAW,CAAC;IAEpF,WAAW,MAAqB,aAC9B,GAAG,kBACD,OAAO,SACL,GAAG,oBAAoB,KAAK,EAC5B,GAAG,oBAAoB,SAAS,CACjC,CACF;IAEH,kBAAkB,WAA0B,aAC1C,GAAG,kBACD,OAAO,gBACL,GAAG,oBAAoB,UAAU,EACjC,GAAG,oBAAoB,SAAS,CACjC,CACF;IACJ;;EAGH,SAAS,EAAE,MAAM,UAAkC;GACjD,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,eAAe,QACb,GAAG,kBACD,KAAK,aACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GAEH,iBAAiB,QACf,GAAG,kBACD,KAAK,eACH,GAAG,oBAAoB,IAAI,CAG5B,CACF;GACJ;EACF"}
@@ -10,6 +10,7 @@ const require_project$1 = require('./project.cjs');
10
10
  const require_ops = require('./ops.cjs');
11
11
  const require_watcher = require('../block_registry/watcher.cjs');
12
12
  const require_driver_kit = require('./driver_kit.cjs');
13
+ const require_service_factories = require('../service_factories.cjs');
13
14
  const require_project_helper = require('../model/project_helper.cjs');
14
15
  let _platforma_sdk_model = require("@platforma-sdk/model");
15
16
  let undici = require("undici");
@@ -18,6 +19,7 @@ let _milaboratories_pl_client = require("@milaboratories/pl-client");
18
19
  let _milaboratories_computable = require("@milaboratories/computable");
19
20
  let node_crypto = require("node:crypto");
20
21
  let quickjs_emscripten = require("quickjs-emscripten");
22
+ let _milaboratories_pl_model_common = require("@milaboratories/pl-model-common");
21
23
 
22
24
  //#region src/middle_layer/middle_layer.ts
23
25
  /**
@@ -66,6 +68,10 @@ var MiddleLayer = class MiddleLayer {
66
68
  get internalDriverKit() {
67
69
  return this.env.driverKit;
68
70
  }
71
+ /** Returns the service registry for service introspection. */
72
+ get serviceRegistry() {
73
+ return this.env.serviceRegistry;
74
+ }
69
75
  /** Creates a project with initial state and adds it to project list. */
70
76
  async createProject(meta, id = (0, node_crypto.randomUUID)()) {
71
77
  const resource = await this.pl.withWriteTx("MLCreateProject", async (tx) => {
@@ -207,6 +213,8 @@ var MiddleLayer = class MiddleLayer {
207
213
  runtimeCapabilities.addSupportedRequirement("requiresModelAPIVersion", 1);
208
214
  runtimeCapabilities.addSupportedRequirement("requiresModelAPIVersion", 2);
209
215
  runtimeCapabilities.addSupportedRequirement("requiresCreatePTable", 2);
216
+ (0, _milaboratories_pl_model_common.registerServiceCapabilities)((flag, value) => runtimeCapabilities.addSupportedRequirement(flag, value));
217
+ const serviceRegistry = require_service_factories.createModelServiceRegistry({ logger });
210
218
  const env = {
211
219
  pl,
212
220
  blockEventDispatcher: new _milaboratories_ts_helpers.BlockEventDispatcher(),
@@ -224,9 +232,11 @@ var MiddleLayer = class MiddleLayer {
224
232
  preferredUpdateChannel: ops.preferredUpdateChannel
225
233
  }),
226
234
  runtimeCapabilities,
235
+ serviceRegistry,
227
236
  quickJs,
228
237
  projectHelper: new require_project_helper.ProjectHelper(quickJs, logger),
229
238
  dispose: async () => {
239
+ await serviceRegistry.dispose();
230
240
  await retryHttpDispatcher.destroy();
231
241
  await driverKit.dispose();
232
242
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middle_layer.cjs","names":["createProject","withProjectAuthored","ProjectMetaKey","isNotNullResourceId","duplicateProject","Project","HmacSha256Signer","DefaultMiddleLayerOpsSettings","DefaultMiddleLayerOpsPaths","getDebugFlags","ProjectsField","ProjectsResourceType","initDriverKit","RetryAgent","V2RegistryProvider","BlockPackPreparer","RuntimeCapabilities","BlockEventDispatcher","BlockUpdateWatcher","ProjectHelper","WatchableValue","createProjectList"],"sources":["../../src/middle_layer/middle_layer.ts"],"sourcesContent":["import type { PlClient, ResourceId } from \"@milaboratories/pl-client\";\nimport {\n field,\n isNotNullResourceId,\n isNullResourceId,\n toGlobalResourceId,\n} from \"@milaboratories/pl-client\";\nimport { createProjectList, ProjectsField, ProjectsResourceType } from \"./project_list\";\nimport { createProject, duplicateProject, withProjectAuthored } from \"../mutator/project\";\nimport { ProjectMetaKey } from \"../model/project_model\";\nimport type { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport { BlockPackPreparer } from \"../mutator/block-pack/block_pack\";\nimport type { MiLogger, Signer } from \"@milaboratories/ts-helpers\";\nimport { BlockEventDispatcher } from \"@milaboratories/ts-helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { WatchableValue } from \"@milaboratories/computable\";\nimport { Project } from \"./project\";\nimport type { MiddleLayerOps, MiddleLayerOpsConstructor } from \"./ops\";\nimport { DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings } from \"./ops\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ProjectListEntry } from \"../model\";\nimport type {\n AuthorMarker,\n ProjectMeta,\n BlockPlatform,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { BlockUpdateWatcher } from \"../block_registry/watcher\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { getQuickJS } from \"quickjs-emscripten\";\nimport type { MiddleLayerDriverKit } from \"./driver_kit\";\nimport { initDriverKit } from \"./driver_kit\";\nimport type { BlockCodeFeatureFlags, DriverKit, SupportedRequirement } from \"@platforma-sdk/model\";\nimport { RuntimeCapabilities } from \"@platforma-sdk/model\";\nimport type { DownloadUrlDriver } from \"@milaboratories/pl-drivers\";\nimport { V2RegistryProvider } from \"../block_registry\";\nimport type { Dispatcher } from \"undici\";\nimport { RetryAgent } from \"undici\";\nimport { getDebugFlags } from \"../debug\";\nimport { ProjectHelper } from \"../model/project_helper\";\n\nexport interface MiddleLayerEnvironment {\n dispose(): Promise<void>;\n readonly pl: PlClient;\n readonly runtimeCapabilities: RuntimeCapabilities;\n readonly logger: MiLogger;\n readonly blockEventDispatcher: BlockEventDispatcher;\n readonly httpDispatcher: Dispatcher;\n readonly retryHttpDispatcher: Dispatcher;\n readonly signer: Signer;\n readonly ops: MiddleLayerOps;\n readonly bpPreparer: BlockPackPreparer;\n readonly frontendDownloadDriver: DownloadUrlDriver;\n readonly blockUpdateWatcher: BlockUpdateWatcher;\n readonly quickJs: QuickJSWASMModule;\n readonly driverKit: MiddleLayerDriverKit;\n readonly projectHelper: ProjectHelper;\n}\n\n/**\n * Main access object to work with pl from UI.\n *\n * It implements an abstraction layer of projects and blocks.\n *\n * As a main entry point inside the pl, this object uses a resource attached\n * via the {@link ProjectsField} to the pl client's root, this resource\n * contains project list.\n *\n * Read about alternative roots, if isolated project lists (working environments)\n * are required.\n * */\nexport class MiddleLayer {\n public readonly pl: PlClient;\n\n /** Contains a reactive list of projects along with their meta information. */\n public readonly projectList: ComputableStableDefined<ProjectListEntry[]>;\n\n private constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly driverKit: DriverKit,\n public readonly signer: Signer,\n private readonly projectListResourceId: ResourceId,\n private readonly openedProjectsList: WatchableValue<ResourceId[]>,\n private readonly projectListTree: SynchronizedTreeState,\n public readonly blockRegistryProvider: V2RegistryProvider,\n projectList: ComputableStableDefined<ProjectListEntry[]>,\n ) {\n this.projectList = projectList;\n this.pl = this.env.pl;\n }\n\n /**\n * Get the OS where backend is running.\n * For old backend versions returns undefined.\n */\n public get serverPlatform(): BlockPlatform | undefined {\n return this.pl.serverInfo.platform as BlockPlatform | undefined;\n }\n\n /** Adds a runtime capability to the middle layer. */\n public addRuntimeCapability(\n requirement: SupportedRequirement,\n value: number | boolean = true,\n ): void {\n this.env.runtimeCapabilities.addSupportedRequirement(requirement, value);\n }\n\n /** Checks if the given block feature flags are compatible with the runtime capabilities. */\n public checkBlockCompatibility(featureFlags: BlockCodeFeatureFlags | undefined): boolean {\n return this.env.runtimeCapabilities.checkCompatibility(featureFlags);\n }\n\n /** Returns extended API driver kit used internally by middle layer. */\n public get internalDriverKit(): MiddleLayerDriverKit {\n return this.env.driverKit;\n }\n\n //\n // Project List Manipulation\n //\n\n /** Creates a project with initial state and adds it to project list. */\n public async createProject(meta: ProjectMeta, id: string = randomUUID()): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLCreateProject\", async (tx) => {\n const prj = await createProject(tx, meta);\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", prj);\n await tx.commit();\n return await toGlobalResourceId(prj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n /** Updates project metadata */\n public async setProjectMeta(\n rid: ResourceId,\n meta: ProjectMeta,\n author?: AuthorMarker,\n ): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.pl,\n rid,\n author,\n (prj) => {\n prj.setMeta(meta);\n },\n { name: \"setProjectMeta\" },\n );\n await this.projectListTree.refreshState();\n }\n\n /** Permanently deletes project from the project list, this will result in\n * destruction of all attached objects, like files, analysis results etc. */\n public async deleteProject(id: string): Promise<void> {\n await this.pl.withWriteTx(\"MLRemoveProject\", async (tx) => {\n tx.removeField(field(this.projectListResourceId, id));\n await tx.commit();\n });\n await this.projectListTree.refreshState();\n }\n\n /**\n * Duplicates an existing project and adds the copy to this user's project list.\n *\n * @param sourceRid - resource id of the project to duplicate\n * @param rename - optional function that receives the source label and all existing\n * project labels (read within the same transaction), and returns the label for the copy\n * @param id - optional id for the new project list entry (defaults to random UUID)\n */\n public async duplicateProject(\n sourceRid: ResourceId,\n rename?: (previousLabel: string, existingLabels: string[]) => string,\n id: string = randomUUID(),\n ): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLDuplicateProject\", async (tx) => {\n // Read source project meta\n const sourceMeta = await tx.getKValueJson<ProjectMeta>(sourceRid, ProjectMetaKey);\n\n // Read all existing project labels from the project list (parallel reads)\n const projectListData = await tx.getResourceData(this.projectListResourceId, true);\n const projectRids = projectListData.fields.map((f) => f.value).filter(isNotNullResourceId);\n const existingLabels = (\n await Promise.all(\n projectRids.map((rid) => tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey)),\n )\n ).map((m) => m.label);\n\n // Compute new label\n const newLabel = rename ? rename(sourceMeta.label, existingLabels) : sourceMeta.label;\n\n // Create the duplicate\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n\n // Attach to project list\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", newPrj);\n await tx.commit();\n return await toGlobalResourceId(newPrj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n //\n // Projects\n //\n\n private readonly openedProjectsByRid = new Map<ResourceId, Project>();\n\n private async projectIdToResourceId(id: string): Promise<ResourceId> {\n return await this.pl.withReadTx(\"Project id to resource id\", async (tx) => {\n const rid = (await tx.getField(field(this.projectListResourceId, id))).value;\n if (isNullResourceId(rid)) throw new Error(\"Unexpected project list structure.\");\n return rid;\n });\n }\n\n private async ensureProjectRid(id: ResourceId | string): Promise<ResourceId> {\n if (typeof id === \"string\") return await this.projectIdToResourceId(id);\n else return id;\n }\n\n /** Opens a project, and starts corresponding project maintenance loop. */\n public async openProject(id: ResourceId | string) {\n const rid = await this.ensureProjectRid(id);\n if (this.openedProjectsByRid.has(rid)) throw new Error(`Project ${rid} already opened`);\n this.openedProjectsByRid.set(rid, await Project.init(this.env, rid));\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Closes the project, and deallocate all corresponding resources. */\n public async closeProject(rid: ResourceId): Promise<void> {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n this.openedProjectsByRid.delete(rid);\n await prj.destroy();\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Returns a project access object for opened project, for the given project\n * resource id. */\n public getOpenedProject(rid: ResourceId): Project {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n return prj;\n }\n\n /** Returns true if project with given resource id is currently opened. */\n public isProjectOpened(rid: ResourceId): boolean {\n return this.openedProjectsByRid.has(rid);\n }\n\n /**\n * Deallocates all runtime resources consumed by this object and awaits\n * actual termination of event loops and other processes associated with\n * them.\n */\n public async close() {\n await Promise.all([...this.openedProjectsByRid.values()].map((prj) => prj.destroy()));\n // this.env.quickJs;\n await this.projectListTree.terminate();\n await this.env.dispose();\n await this.pl.close();\n }\n\n /** @deprecated */\n public async closeAndAwaitTermination() {\n await this.close();\n }\n\n /** Generates sufficiently random string to be used as local secret for the\n * middle layer */\n public static generateLocalSecret(): string {\n return HmacSha256Signer.generateSecret();\n }\n\n /** Returns a block event dispatcher, which can be used to listen to block events. */\n public get blockEventDispatcher(): BlockEventDispatcher {\n return this.env.blockEventDispatcher;\n }\n\n /** Initialize middle layer */\n public static async init(\n pl: PlClient,\n workdir: string,\n _ops: MiddleLayerOpsConstructor,\n ): Promise<MiddleLayer> {\n const ops: MiddleLayerOps = {\n ...DefaultMiddleLayerOpsSettings,\n ...DefaultMiddleLayerOpsPaths(workdir),\n ..._ops,\n };\n\n // overriding debug options from environment variables\n ops.defaultTreeOptions.logStat = getDebugFlags().logTreeStats;\n ops.debugOps.dumpInitialTreeState = getDebugFlags().dumpInitialTreeState;\n\n const projects = await pl.withWriteTx(\"MLInitialization\", async (tx) => {\n const projectsField = field(tx.clientRoot, ProjectsField);\n tx.createField(projectsField, \"Dynamic\");\n const projectsFieldData = await tx.getField(projectsField);\n if (isNullResourceId(projectsFieldData.value)) {\n const projects = tx.createEphemeral(ProjectsResourceType);\n tx.lock(projects);\n\n tx.setField(projectsField, projects);\n\n await tx.commit();\n\n return await projects.globalId;\n } else {\n return projectsFieldData.value;\n }\n });\n\n const logger = ops.logger;\n\n const driverKit = await initDriverKit(pl, workdir, ops.frontendDownloadPath, ops);\n\n // passed to components having no own retry logic\n const retryHttpDispatcher = new RetryAgent(pl.httpDispatcher);\n\n const v2RegistryProvider = new V2RegistryProvider(retryHttpDispatcher);\n\n const bpPreparer = new BlockPackPreparer(\n v2RegistryProvider,\n driverKit.signer,\n retryHttpDispatcher,\n );\n\n const quickJs = await getQuickJS();\n\n const runtimeCapabilities = new RuntimeCapabilities();\n // add runtime capabilities of model here\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 1);\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 2);\n runtimeCapabilities.addSupportedRequirement(\"requiresCreatePTable\", 2);\n // runtime capabilities of the desktop are to be added by the desktop app / test framework\n\n const env: MiddleLayerEnvironment = {\n pl,\n blockEventDispatcher: new BlockEventDispatcher(),\n signer: driverKit.signer,\n logger,\n httpDispatcher: pl.httpDispatcher,\n retryHttpDispatcher,\n ops,\n bpPreparer,\n frontendDownloadDriver: driverKit.frontendDriver,\n driverKit,\n blockUpdateWatcher: new BlockUpdateWatcher(v2RegistryProvider, logger, {\n minDelay: ops.devBlockUpdateRecheckInterval,\n http: retryHttpDispatcher,\n preferredUpdateChannel: ops.preferredUpdateChannel,\n }),\n runtimeCapabilities,\n quickJs,\n projectHelper: new ProjectHelper(quickJs, logger),\n dispose: async () => {\n await retryHttpDispatcher.destroy();\n await driverKit.dispose();\n },\n };\n\n const openedProjects = new WatchableValue<ResourceId[]>([]);\n const projectListTC = await createProjectList(pl, projects, openedProjects, env);\n\n return new MiddleLayer(\n env,\n driverKit,\n driverKit.signer,\n projects,\n openedProjects,\n projectListTC.tree,\n v2RegistryProvider,\n projectListTC.computable,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"middle_layer.cjs","names":["createProject","withProjectAuthored","ProjectMetaKey","isNotNullResourceId","duplicateProject","Project","HmacSha256Signer","DefaultMiddleLayerOpsSettings","DefaultMiddleLayerOpsPaths","getDebugFlags","ProjectsField","ProjectsResourceType","initDriverKit","RetryAgent","V2RegistryProvider","BlockPackPreparer","RuntimeCapabilities","createModelServiceRegistry","BlockEventDispatcher","BlockUpdateWatcher","ProjectHelper","WatchableValue","createProjectList"],"sources":["../../src/middle_layer/middle_layer.ts"],"sourcesContent":["import type { PlClient, ResourceId } from \"@milaboratories/pl-client\";\nimport {\n field,\n isNotNullResourceId,\n isNullResourceId,\n toGlobalResourceId,\n} from \"@milaboratories/pl-client\";\nimport { createProjectList, ProjectsField, ProjectsResourceType } from \"./project_list\";\nimport { createProject, duplicateProject, withProjectAuthored } from \"../mutator/project\";\nimport { ProjectMetaKey } from \"../model/project_model\";\nimport type { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport { BlockPackPreparer } from \"../mutator/block-pack/block_pack\";\nimport type { MiLogger, Signer } from \"@milaboratories/ts-helpers\";\nimport { BlockEventDispatcher } from \"@milaboratories/ts-helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { WatchableValue } from \"@milaboratories/computable\";\nimport { Project } from \"./project\";\nimport type { MiddleLayerOps, MiddleLayerOpsConstructor } from \"./ops\";\nimport { DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings } from \"./ops\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ProjectListEntry } from \"../model\";\nimport type {\n AuthorMarker,\n ProjectMeta,\n BlockPlatform,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { BlockUpdateWatcher } from \"../block_registry/watcher\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { getQuickJS } from \"quickjs-emscripten\";\nimport type { MiddleLayerDriverKit } from \"./driver_kit\";\nimport { initDriverKit } from \"./driver_kit\";\nimport type { BlockCodeFeatureFlags, DriverKit, SupportedRequirement } from \"@platforma-sdk/model\";\nimport { RuntimeCapabilities } from \"@platforma-sdk/model\";\nimport {\n type ModelServiceRegistry,\n registerServiceCapabilities,\n} from \"@milaboratories/pl-model-common\";\nimport { createModelServiceRegistry } from \"../service_factories\";\nimport type { DownloadUrlDriver } from \"@milaboratories/pl-drivers\";\nimport { V2RegistryProvider } from \"../block_registry\";\nimport type { Dispatcher } from \"undici\";\nimport { RetryAgent } from \"undici\";\nimport { getDebugFlags } from \"../debug\";\nimport { ProjectHelper } from \"../model/project_helper\";\n\nexport interface MiddleLayerEnvironment {\n dispose(): Promise<void>;\n readonly pl: PlClient;\n readonly runtimeCapabilities: RuntimeCapabilities;\n readonly logger: MiLogger;\n readonly blockEventDispatcher: BlockEventDispatcher;\n readonly httpDispatcher: Dispatcher;\n readonly retryHttpDispatcher: Dispatcher;\n readonly signer: Signer;\n readonly ops: MiddleLayerOps;\n readonly bpPreparer: BlockPackPreparer;\n readonly frontendDownloadDriver: DownloadUrlDriver;\n readonly blockUpdateWatcher: BlockUpdateWatcher;\n readonly quickJs: QuickJSWASMModule;\n readonly driverKit: MiddleLayerDriverKit;\n readonly serviceRegistry: ModelServiceRegistry;\n readonly projectHelper: ProjectHelper;\n}\n\n/**\n * Main access object to work with pl from UI.\n *\n * It implements an abstraction layer of projects and blocks.\n *\n * As a main entry point inside the pl, this object uses a resource attached\n * via the {@link ProjectsField} to the pl client's root, this resource\n * contains project list.\n *\n * Read about alternative roots, if isolated project lists (working environments)\n * are required.\n * */\nexport class MiddleLayer {\n public readonly pl: PlClient;\n\n /** Contains a reactive list of projects along with their meta information. */\n public readonly projectList: ComputableStableDefined<ProjectListEntry[]>;\n\n private constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly driverKit: DriverKit,\n public readonly signer: Signer,\n private readonly projectListResourceId: ResourceId,\n private readonly openedProjectsList: WatchableValue<ResourceId[]>,\n private readonly projectListTree: SynchronizedTreeState,\n public readonly blockRegistryProvider: V2RegistryProvider,\n projectList: ComputableStableDefined<ProjectListEntry[]>,\n ) {\n this.projectList = projectList;\n this.pl = this.env.pl;\n }\n\n /**\n * Get the OS where backend is running.\n * For old backend versions returns undefined.\n */\n public get serverPlatform(): BlockPlatform | undefined {\n return this.pl.serverInfo.platform as BlockPlatform | undefined;\n }\n\n /** Adds a runtime capability to the middle layer. */\n public addRuntimeCapability(\n requirement: SupportedRequirement,\n value: number | boolean = true,\n ): void {\n this.env.runtimeCapabilities.addSupportedRequirement(requirement, value);\n }\n\n /** Checks if the given block feature flags are compatible with the runtime capabilities. */\n public checkBlockCompatibility(featureFlags: BlockCodeFeatureFlags | undefined): boolean {\n return this.env.runtimeCapabilities.checkCompatibility(featureFlags);\n }\n\n /** Returns extended API driver kit used internally by middle layer. */\n public get internalDriverKit(): MiddleLayerDriverKit {\n return this.env.driverKit;\n }\n\n /** Returns the service registry for service introspection. */\n public get serviceRegistry(): ModelServiceRegistry {\n return this.env.serviceRegistry;\n }\n\n //\n // Project List Manipulation\n //\n\n /** Creates a project with initial state and adds it to project list. */\n public async createProject(meta: ProjectMeta, id: string = randomUUID()): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLCreateProject\", async (tx) => {\n const prj = await createProject(tx, meta);\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", prj);\n await tx.commit();\n return await toGlobalResourceId(prj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n /** Updates project metadata */\n public async setProjectMeta(\n rid: ResourceId,\n meta: ProjectMeta,\n author?: AuthorMarker,\n ): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.pl,\n rid,\n author,\n (prj) => {\n prj.setMeta(meta);\n },\n { name: \"setProjectMeta\" },\n );\n await this.projectListTree.refreshState();\n }\n\n /** Permanently deletes project from the project list, this will result in\n * destruction of all attached objects, like files, analysis results etc. */\n public async deleteProject(id: string): Promise<void> {\n await this.pl.withWriteTx(\"MLRemoveProject\", async (tx) => {\n tx.removeField(field(this.projectListResourceId, id));\n await tx.commit();\n });\n await this.projectListTree.refreshState();\n }\n\n /**\n * Duplicates an existing project and adds the copy to this user's project list.\n *\n * @param sourceRid - resource id of the project to duplicate\n * @param rename - optional function that receives the source label and all existing\n * project labels (read within the same transaction), and returns the label for the copy\n * @param id - optional id for the new project list entry (defaults to random UUID)\n */\n public async duplicateProject(\n sourceRid: ResourceId,\n rename?: (previousLabel: string, existingLabels: string[]) => string,\n id: string = randomUUID(),\n ): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLDuplicateProject\", async (tx) => {\n // Read source project meta\n const sourceMeta = await tx.getKValueJson<ProjectMeta>(sourceRid, ProjectMetaKey);\n\n // Read all existing project labels from the project list (parallel reads)\n const projectListData = await tx.getResourceData(this.projectListResourceId, true);\n const projectRids = projectListData.fields.map((f) => f.value).filter(isNotNullResourceId);\n const existingLabels = (\n await Promise.all(\n projectRids.map((rid) => tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey)),\n )\n ).map((m) => m.label);\n\n // Compute new label\n const newLabel = rename ? rename(sourceMeta.label, existingLabels) : sourceMeta.label;\n\n // Create the duplicate\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n\n // Attach to project list\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", newPrj);\n await tx.commit();\n return await toGlobalResourceId(newPrj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n //\n // Projects\n //\n\n private readonly openedProjectsByRid = new Map<ResourceId, Project>();\n\n private async projectIdToResourceId(id: string): Promise<ResourceId> {\n return await this.pl.withReadTx(\"Project id to resource id\", async (tx) => {\n const rid = (await tx.getField(field(this.projectListResourceId, id))).value;\n if (isNullResourceId(rid)) throw new Error(\"Unexpected project list structure.\");\n return rid;\n });\n }\n\n private async ensureProjectRid(id: ResourceId | string): Promise<ResourceId> {\n if (typeof id === \"string\") return await this.projectIdToResourceId(id);\n else return id;\n }\n\n /** Opens a project, and starts corresponding project maintenance loop. */\n public async openProject(id: ResourceId | string) {\n const rid = await this.ensureProjectRid(id);\n if (this.openedProjectsByRid.has(rid)) throw new Error(`Project ${rid} already opened`);\n this.openedProjectsByRid.set(rid, await Project.init(this.env, rid));\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Closes the project, and deallocate all corresponding resources. */\n public async closeProject(rid: ResourceId): Promise<void> {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n this.openedProjectsByRid.delete(rid);\n await prj.destroy();\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Returns a project access object for opened project, for the given project\n * resource id. */\n public getOpenedProject(rid: ResourceId): Project {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n return prj;\n }\n\n /** Returns true if project with given resource id is currently opened. */\n public isProjectOpened(rid: ResourceId): boolean {\n return this.openedProjectsByRid.has(rid);\n }\n\n /**\n * Deallocates all runtime resources consumed by this object and awaits\n * actual termination of event loops and other processes associated with\n * them.\n */\n public async close() {\n await Promise.all([...this.openedProjectsByRid.values()].map((prj) => prj.destroy()));\n // this.env.quickJs;\n await this.projectListTree.terminate();\n await this.env.dispose();\n await this.pl.close();\n }\n\n /** @deprecated */\n public async closeAndAwaitTermination() {\n await this.close();\n }\n\n /** Generates sufficiently random string to be used as local secret for the\n * middle layer */\n public static generateLocalSecret(): string {\n return HmacSha256Signer.generateSecret();\n }\n\n /** Returns a block event dispatcher, which can be used to listen to block events. */\n public get blockEventDispatcher(): BlockEventDispatcher {\n return this.env.blockEventDispatcher;\n }\n\n /** Initialize middle layer */\n public static async init(\n pl: PlClient,\n workdir: string,\n _ops: MiddleLayerOpsConstructor,\n ): Promise<MiddleLayer> {\n const ops: MiddleLayerOps = {\n ...DefaultMiddleLayerOpsSettings,\n ...DefaultMiddleLayerOpsPaths(workdir),\n ..._ops,\n };\n\n // overriding debug options from environment variables\n ops.defaultTreeOptions.logStat = getDebugFlags().logTreeStats;\n ops.debugOps.dumpInitialTreeState = getDebugFlags().dumpInitialTreeState;\n\n const projects = await pl.withWriteTx(\"MLInitialization\", async (tx) => {\n const projectsField = field(tx.clientRoot, ProjectsField);\n tx.createField(projectsField, \"Dynamic\");\n const projectsFieldData = await tx.getField(projectsField);\n if (isNullResourceId(projectsFieldData.value)) {\n const projects = tx.createEphemeral(ProjectsResourceType);\n tx.lock(projects);\n\n tx.setField(projectsField, projects);\n\n await tx.commit();\n\n return await projects.globalId;\n } else {\n return projectsFieldData.value;\n }\n });\n\n const logger = ops.logger;\n\n const driverKit = await initDriverKit(pl, workdir, ops.frontendDownloadPath, ops);\n\n // passed to components having no own retry logic\n const retryHttpDispatcher = new RetryAgent(pl.httpDispatcher);\n\n const v2RegistryProvider = new V2RegistryProvider(retryHttpDispatcher);\n\n const bpPreparer = new BlockPackPreparer(\n v2RegistryProvider,\n driverKit.signer,\n retryHttpDispatcher,\n );\n\n const quickJs = await getQuickJS();\n\n const runtimeCapabilities = new RuntimeCapabilities();\n // add runtime capabilities of model here\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 1);\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 2);\n runtimeCapabilities.addSupportedRequirement(\"requiresCreatePTable\", 2);\n registerServiceCapabilities((flag, value) =>\n runtimeCapabilities.addSupportedRequirement(flag, value),\n );\n // runtime capabilities of the desktop are to be added by the desktop app / test framework\n\n const serviceRegistry = createModelServiceRegistry({ logger });\n\n const env: MiddleLayerEnvironment = {\n pl,\n blockEventDispatcher: new BlockEventDispatcher(),\n signer: driverKit.signer,\n logger,\n httpDispatcher: pl.httpDispatcher,\n retryHttpDispatcher,\n ops,\n bpPreparer,\n frontendDownloadDriver: driverKit.frontendDriver,\n driverKit,\n blockUpdateWatcher: new BlockUpdateWatcher(v2RegistryProvider, logger, {\n minDelay: ops.devBlockUpdateRecheckInterval,\n http: retryHttpDispatcher,\n preferredUpdateChannel: ops.preferredUpdateChannel,\n }),\n runtimeCapabilities,\n serviceRegistry,\n quickJs,\n projectHelper: new ProjectHelper(quickJs, logger),\n dispose: async () => {\n await serviceRegistry.dispose();\n await retryHttpDispatcher.destroy();\n await driverKit.dispose();\n },\n };\n\n const openedProjects = new WatchableValue<ResourceId[]>([]);\n const projectListTC = await createProjectList(pl, projects, openedProjects, env);\n\n return new MiddleLayer(\n env,\n driverKit,\n driverKit.signer,\n projects,\n openedProjects,\n projectListTC.tree,\n v2RegistryProvider,\n projectListTC.computable,\n );\n }\n}\n"],"mappings":"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"}
@@ -15,6 +15,7 @@ import { BlockEventDispatcher, MiLogger, Signer } from "@milaboratories/ts-helpe
15
15
  import { PlClient, ResourceId } from "@milaboratories/pl-client";
16
16
  import { ComputableStableDefined } from "@milaboratories/computable";
17
17
  import { QuickJSWASMModule } from "quickjs-emscripten";
18
+ import { ModelServiceRegistry } from "@milaboratories/pl-model-common";
18
19
  import { DownloadUrlDriver } from "@milaboratories/pl-drivers";
19
20
 
20
21
  //#region src/middle_layer/middle_layer.d.ts
@@ -33,6 +34,7 @@ interface MiddleLayerEnvironment {
33
34
  readonly blockUpdateWatcher: BlockUpdateWatcher;
34
35
  readonly quickJs: QuickJSWASMModule;
35
36
  readonly driverKit: MiddleLayerDriverKit;
37
+ readonly serviceRegistry: ModelServiceRegistry;
36
38
  readonly projectHelper: ProjectHelper;
37
39
  }
38
40
  /**
@@ -70,6 +72,8 @@ declare class MiddleLayer {
70
72
  checkBlockCompatibility(featureFlags: BlockCodeFeatureFlags | undefined): boolean;
71
73
  /** Returns extended API driver kit used internally by middle layer. */
72
74
  get internalDriverKit(): MiddleLayerDriverKit;
75
+ /** Returns the service registry for service introspection. */
76
+ get serviceRegistry(): ModelServiceRegistry;
73
77
  /** Creates a project with initial state and adds it to project list. */
74
78
  createProject(meta: ProjectMeta, id?: string): Promise<ResourceId>;
75
79
  /** Updates project metadata */
@@ -9,6 +9,7 @@ import { Project } from "./project.js";
9
9
  import { DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings } from "./ops.js";
10
10
  import { BlockUpdateWatcher } from "../block_registry/watcher.js";
11
11
  import { initDriverKit } from "./driver_kit.js";
12
+ import { createModelServiceRegistry } from "../service_factories.js";
12
13
  import { ProjectHelper } from "../model/project_helper.js";
13
14
  import { RuntimeCapabilities } from "@platforma-sdk/model";
14
15
  import { RetryAgent } from "undici";
@@ -17,6 +18,7 @@ import { field, isNotNullResourceId, isNullResourceId, toGlobalResourceId } from
17
18
  import { WatchableValue } from "@milaboratories/computable";
18
19
  import { randomUUID } from "node:crypto";
19
20
  import { getQuickJS } from "quickjs-emscripten";
21
+ import { registerServiceCapabilities } from "@milaboratories/pl-model-common";
20
22
 
21
23
  //#region src/middle_layer/middle_layer.ts
22
24
  /**
@@ -65,6 +67,10 @@ var MiddleLayer = class MiddleLayer {
65
67
  get internalDriverKit() {
66
68
  return this.env.driverKit;
67
69
  }
70
+ /** Returns the service registry for service introspection. */
71
+ get serviceRegistry() {
72
+ return this.env.serviceRegistry;
73
+ }
68
74
  /** Creates a project with initial state and adds it to project list. */
69
75
  async createProject(meta, id = randomUUID()) {
70
76
  const resource = await this.pl.withWriteTx("MLCreateProject", async (tx) => {
@@ -206,6 +212,8 @@ var MiddleLayer = class MiddleLayer {
206
212
  runtimeCapabilities.addSupportedRequirement("requiresModelAPIVersion", 1);
207
213
  runtimeCapabilities.addSupportedRequirement("requiresModelAPIVersion", 2);
208
214
  runtimeCapabilities.addSupportedRequirement("requiresCreatePTable", 2);
215
+ registerServiceCapabilities((flag, value) => runtimeCapabilities.addSupportedRequirement(flag, value));
216
+ const serviceRegistry = createModelServiceRegistry({ logger });
209
217
  const env = {
210
218
  pl,
211
219
  blockEventDispatcher: new BlockEventDispatcher(),
@@ -223,9 +231,11 @@ var MiddleLayer = class MiddleLayer {
223
231
  preferredUpdateChannel: ops.preferredUpdateChannel
224
232
  }),
225
233
  runtimeCapabilities,
234
+ serviceRegistry,
226
235
  quickJs,
227
236
  projectHelper: new ProjectHelper(quickJs, logger),
228
237
  dispose: async () => {
238
+ await serviceRegistry.dispose();
229
239
  await retryHttpDispatcher.destroy();
230
240
  await driverKit.dispose();
231
241
  }
@@ -1 +1 @@
1
- {"version":3,"file":"middle_layer.js","names":[],"sources":["../../src/middle_layer/middle_layer.ts"],"sourcesContent":["import type { PlClient, ResourceId } from \"@milaboratories/pl-client\";\nimport {\n field,\n isNotNullResourceId,\n isNullResourceId,\n toGlobalResourceId,\n} from \"@milaboratories/pl-client\";\nimport { createProjectList, ProjectsField, ProjectsResourceType } from \"./project_list\";\nimport { createProject, duplicateProject, withProjectAuthored } from \"../mutator/project\";\nimport { ProjectMetaKey } from \"../model/project_model\";\nimport type { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport { BlockPackPreparer } from \"../mutator/block-pack/block_pack\";\nimport type { MiLogger, Signer } from \"@milaboratories/ts-helpers\";\nimport { BlockEventDispatcher } from \"@milaboratories/ts-helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { WatchableValue } from \"@milaboratories/computable\";\nimport { Project } from \"./project\";\nimport type { MiddleLayerOps, MiddleLayerOpsConstructor } from \"./ops\";\nimport { DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings } from \"./ops\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ProjectListEntry } from \"../model\";\nimport type {\n AuthorMarker,\n ProjectMeta,\n BlockPlatform,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { BlockUpdateWatcher } from \"../block_registry/watcher\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { getQuickJS } from \"quickjs-emscripten\";\nimport type { MiddleLayerDriverKit } from \"./driver_kit\";\nimport { initDriverKit } from \"./driver_kit\";\nimport type { BlockCodeFeatureFlags, DriverKit, SupportedRequirement } from \"@platforma-sdk/model\";\nimport { RuntimeCapabilities } from \"@platforma-sdk/model\";\nimport type { DownloadUrlDriver } from \"@milaboratories/pl-drivers\";\nimport { V2RegistryProvider } from \"../block_registry\";\nimport type { Dispatcher } from \"undici\";\nimport { RetryAgent } from \"undici\";\nimport { getDebugFlags } from \"../debug\";\nimport { ProjectHelper } from \"../model/project_helper\";\n\nexport interface MiddleLayerEnvironment {\n dispose(): Promise<void>;\n readonly pl: PlClient;\n readonly runtimeCapabilities: RuntimeCapabilities;\n readonly logger: MiLogger;\n readonly blockEventDispatcher: BlockEventDispatcher;\n readonly httpDispatcher: Dispatcher;\n readonly retryHttpDispatcher: Dispatcher;\n readonly signer: Signer;\n readonly ops: MiddleLayerOps;\n readonly bpPreparer: BlockPackPreparer;\n readonly frontendDownloadDriver: DownloadUrlDriver;\n readonly blockUpdateWatcher: BlockUpdateWatcher;\n readonly quickJs: QuickJSWASMModule;\n readonly driverKit: MiddleLayerDriverKit;\n readonly projectHelper: ProjectHelper;\n}\n\n/**\n * Main access object to work with pl from UI.\n *\n * It implements an abstraction layer of projects and blocks.\n *\n * As a main entry point inside the pl, this object uses a resource attached\n * via the {@link ProjectsField} to the pl client's root, this resource\n * contains project list.\n *\n * Read about alternative roots, if isolated project lists (working environments)\n * are required.\n * */\nexport class MiddleLayer {\n public readonly pl: PlClient;\n\n /** Contains a reactive list of projects along with their meta information. */\n public readonly projectList: ComputableStableDefined<ProjectListEntry[]>;\n\n private constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly driverKit: DriverKit,\n public readonly signer: Signer,\n private readonly projectListResourceId: ResourceId,\n private readonly openedProjectsList: WatchableValue<ResourceId[]>,\n private readonly projectListTree: SynchronizedTreeState,\n public readonly blockRegistryProvider: V2RegistryProvider,\n projectList: ComputableStableDefined<ProjectListEntry[]>,\n ) {\n this.projectList = projectList;\n this.pl = this.env.pl;\n }\n\n /**\n * Get the OS where backend is running.\n * For old backend versions returns undefined.\n */\n public get serverPlatform(): BlockPlatform | undefined {\n return this.pl.serverInfo.platform as BlockPlatform | undefined;\n }\n\n /** Adds a runtime capability to the middle layer. */\n public addRuntimeCapability(\n requirement: SupportedRequirement,\n value: number | boolean = true,\n ): void {\n this.env.runtimeCapabilities.addSupportedRequirement(requirement, value);\n }\n\n /** Checks if the given block feature flags are compatible with the runtime capabilities. */\n public checkBlockCompatibility(featureFlags: BlockCodeFeatureFlags | undefined): boolean {\n return this.env.runtimeCapabilities.checkCompatibility(featureFlags);\n }\n\n /** Returns extended API driver kit used internally by middle layer. */\n public get internalDriverKit(): MiddleLayerDriverKit {\n return this.env.driverKit;\n }\n\n //\n // Project List Manipulation\n //\n\n /** Creates a project with initial state and adds it to project list. */\n public async createProject(meta: ProjectMeta, id: string = randomUUID()): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLCreateProject\", async (tx) => {\n const prj = await createProject(tx, meta);\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", prj);\n await tx.commit();\n return await toGlobalResourceId(prj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n /** Updates project metadata */\n public async setProjectMeta(\n rid: ResourceId,\n meta: ProjectMeta,\n author?: AuthorMarker,\n ): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.pl,\n rid,\n author,\n (prj) => {\n prj.setMeta(meta);\n },\n { name: \"setProjectMeta\" },\n );\n await this.projectListTree.refreshState();\n }\n\n /** Permanently deletes project from the project list, this will result in\n * destruction of all attached objects, like files, analysis results etc. */\n public async deleteProject(id: string): Promise<void> {\n await this.pl.withWriteTx(\"MLRemoveProject\", async (tx) => {\n tx.removeField(field(this.projectListResourceId, id));\n await tx.commit();\n });\n await this.projectListTree.refreshState();\n }\n\n /**\n * Duplicates an existing project and adds the copy to this user's project list.\n *\n * @param sourceRid - resource id of the project to duplicate\n * @param rename - optional function that receives the source label and all existing\n * project labels (read within the same transaction), and returns the label for the copy\n * @param id - optional id for the new project list entry (defaults to random UUID)\n */\n public async duplicateProject(\n sourceRid: ResourceId,\n rename?: (previousLabel: string, existingLabels: string[]) => string,\n id: string = randomUUID(),\n ): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLDuplicateProject\", async (tx) => {\n // Read source project meta\n const sourceMeta = await tx.getKValueJson<ProjectMeta>(sourceRid, ProjectMetaKey);\n\n // Read all existing project labels from the project list (parallel reads)\n const projectListData = await tx.getResourceData(this.projectListResourceId, true);\n const projectRids = projectListData.fields.map((f) => f.value).filter(isNotNullResourceId);\n const existingLabels = (\n await Promise.all(\n projectRids.map((rid) => tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey)),\n )\n ).map((m) => m.label);\n\n // Compute new label\n const newLabel = rename ? rename(sourceMeta.label, existingLabels) : sourceMeta.label;\n\n // Create the duplicate\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n\n // Attach to project list\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", newPrj);\n await tx.commit();\n return await toGlobalResourceId(newPrj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n //\n // Projects\n //\n\n private readonly openedProjectsByRid = new Map<ResourceId, Project>();\n\n private async projectIdToResourceId(id: string): Promise<ResourceId> {\n return await this.pl.withReadTx(\"Project id to resource id\", async (tx) => {\n const rid = (await tx.getField(field(this.projectListResourceId, id))).value;\n if (isNullResourceId(rid)) throw new Error(\"Unexpected project list structure.\");\n return rid;\n });\n }\n\n private async ensureProjectRid(id: ResourceId | string): Promise<ResourceId> {\n if (typeof id === \"string\") return await this.projectIdToResourceId(id);\n else return id;\n }\n\n /** Opens a project, and starts corresponding project maintenance loop. */\n public async openProject(id: ResourceId | string) {\n const rid = await this.ensureProjectRid(id);\n if (this.openedProjectsByRid.has(rid)) throw new Error(`Project ${rid} already opened`);\n this.openedProjectsByRid.set(rid, await Project.init(this.env, rid));\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Closes the project, and deallocate all corresponding resources. */\n public async closeProject(rid: ResourceId): Promise<void> {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n this.openedProjectsByRid.delete(rid);\n await prj.destroy();\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Returns a project access object for opened project, for the given project\n * resource id. */\n public getOpenedProject(rid: ResourceId): Project {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n return prj;\n }\n\n /** Returns true if project with given resource id is currently opened. */\n public isProjectOpened(rid: ResourceId): boolean {\n return this.openedProjectsByRid.has(rid);\n }\n\n /**\n * Deallocates all runtime resources consumed by this object and awaits\n * actual termination of event loops and other processes associated with\n * them.\n */\n public async close() {\n await Promise.all([...this.openedProjectsByRid.values()].map((prj) => prj.destroy()));\n // this.env.quickJs;\n await this.projectListTree.terminate();\n await this.env.dispose();\n await this.pl.close();\n }\n\n /** @deprecated */\n public async closeAndAwaitTermination() {\n await this.close();\n }\n\n /** Generates sufficiently random string to be used as local secret for the\n * middle layer */\n public static generateLocalSecret(): string {\n return HmacSha256Signer.generateSecret();\n }\n\n /** Returns a block event dispatcher, which can be used to listen to block events. */\n public get blockEventDispatcher(): BlockEventDispatcher {\n return this.env.blockEventDispatcher;\n }\n\n /** Initialize middle layer */\n public static async init(\n pl: PlClient,\n workdir: string,\n _ops: MiddleLayerOpsConstructor,\n ): Promise<MiddleLayer> {\n const ops: MiddleLayerOps = {\n ...DefaultMiddleLayerOpsSettings,\n ...DefaultMiddleLayerOpsPaths(workdir),\n ..._ops,\n };\n\n // overriding debug options from environment variables\n ops.defaultTreeOptions.logStat = getDebugFlags().logTreeStats;\n ops.debugOps.dumpInitialTreeState = getDebugFlags().dumpInitialTreeState;\n\n const projects = await pl.withWriteTx(\"MLInitialization\", async (tx) => {\n const projectsField = field(tx.clientRoot, ProjectsField);\n tx.createField(projectsField, \"Dynamic\");\n const projectsFieldData = await tx.getField(projectsField);\n if (isNullResourceId(projectsFieldData.value)) {\n const projects = tx.createEphemeral(ProjectsResourceType);\n tx.lock(projects);\n\n tx.setField(projectsField, projects);\n\n await tx.commit();\n\n return await projects.globalId;\n } else {\n return projectsFieldData.value;\n }\n });\n\n const logger = ops.logger;\n\n const driverKit = await initDriverKit(pl, workdir, ops.frontendDownloadPath, ops);\n\n // passed to components having no own retry logic\n const retryHttpDispatcher = new RetryAgent(pl.httpDispatcher);\n\n const v2RegistryProvider = new V2RegistryProvider(retryHttpDispatcher);\n\n const bpPreparer = new BlockPackPreparer(\n v2RegistryProvider,\n driverKit.signer,\n retryHttpDispatcher,\n );\n\n const quickJs = await getQuickJS();\n\n const runtimeCapabilities = new RuntimeCapabilities();\n // add runtime capabilities of model here\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 1);\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 2);\n runtimeCapabilities.addSupportedRequirement(\"requiresCreatePTable\", 2);\n // runtime capabilities of the desktop are to be added by the desktop app / test framework\n\n const env: MiddleLayerEnvironment = {\n pl,\n blockEventDispatcher: new BlockEventDispatcher(),\n signer: driverKit.signer,\n logger,\n httpDispatcher: pl.httpDispatcher,\n retryHttpDispatcher,\n ops,\n bpPreparer,\n frontendDownloadDriver: driverKit.frontendDriver,\n driverKit,\n blockUpdateWatcher: new BlockUpdateWatcher(v2RegistryProvider, logger, {\n minDelay: ops.devBlockUpdateRecheckInterval,\n http: retryHttpDispatcher,\n preferredUpdateChannel: ops.preferredUpdateChannel,\n }),\n runtimeCapabilities,\n quickJs,\n projectHelper: new ProjectHelper(quickJs, logger),\n dispose: async () => {\n await retryHttpDispatcher.destroy();\n await driverKit.dispose();\n },\n };\n\n const openedProjects = new WatchableValue<ResourceId[]>([]);\n const projectListTC = await createProjectList(pl, projects, openedProjects, env);\n\n return new MiddleLayer(\n env,\n driverKit,\n driverKit.signer,\n projects,\n openedProjects,\n projectListTC.tree,\n v2RegistryProvider,\n projectListTC.computable,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"middle_layer.js","names":[],"sources":["../../src/middle_layer/middle_layer.ts"],"sourcesContent":["import type { PlClient, ResourceId } from \"@milaboratories/pl-client\";\nimport {\n field,\n isNotNullResourceId,\n isNullResourceId,\n toGlobalResourceId,\n} from \"@milaboratories/pl-client\";\nimport { createProjectList, ProjectsField, ProjectsResourceType } from \"./project_list\";\nimport { createProject, duplicateProject, withProjectAuthored } from \"../mutator/project\";\nimport { ProjectMetaKey } from \"../model/project_model\";\nimport type { SynchronizedTreeState } from \"@milaboratories/pl-tree\";\nimport { BlockPackPreparer } from \"../mutator/block-pack/block_pack\";\nimport type { MiLogger, Signer } from \"@milaboratories/ts-helpers\";\nimport { BlockEventDispatcher } from \"@milaboratories/ts-helpers\";\nimport { HmacSha256Signer } from \"@milaboratories/ts-helpers\";\nimport type { ComputableStableDefined } from \"@milaboratories/computable\";\nimport { WatchableValue } from \"@milaboratories/computable\";\nimport { Project } from \"./project\";\nimport type { MiddleLayerOps, MiddleLayerOpsConstructor } from \"./ops\";\nimport { DefaultMiddleLayerOpsPaths, DefaultMiddleLayerOpsSettings } from \"./ops\";\nimport { randomUUID } from \"node:crypto\";\nimport type { ProjectListEntry } from \"../model\";\nimport type {\n AuthorMarker,\n ProjectMeta,\n BlockPlatform,\n} from \"@milaboratories/pl-model-middle-layer\";\nimport { BlockUpdateWatcher } from \"../block_registry/watcher\";\nimport type { QuickJSWASMModule } from \"quickjs-emscripten\";\nimport { getQuickJS } from \"quickjs-emscripten\";\nimport type { MiddleLayerDriverKit } from \"./driver_kit\";\nimport { initDriverKit } from \"./driver_kit\";\nimport type { BlockCodeFeatureFlags, DriverKit, SupportedRequirement } from \"@platforma-sdk/model\";\nimport { RuntimeCapabilities } from \"@platforma-sdk/model\";\nimport {\n type ModelServiceRegistry,\n registerServiceCapabilities,\n} from \"@milaboratories/pl-model-common\";\nimport { createModelServiceRegistry } from \"../service_factories\";\nimport type { DownloadUrlDriver } from \"@milaboratories/pl-drivers\";\nimport { V2RegistryProvider } from \"../block_registry\";\nimport type { Dispatcher } from \"undici\";\nimport { RetryAgent } from \"undici\";\nimport { getDebugFlags } from \"../debug\";\nimport { ProjectHelper } from \"../model/project_helper\";\n\nexport interface MiddleLayerEnvironment {\n dispose(): Promise<void>;\n readonly pl: PlClient;\n readonly runtimeCapabilities: RuntimeCapabilities;\n readonly logger: MiLogger;\n readonly blockEventDispatcher: BlockEventDispatcher;\n readonly httpDispatcher: Dispatcher;\n readonly retryHttpDispatcher: Dispatcher;\n readonly signer: Signer;\n readonly ops: MiddleLayerOps;\n readonly bpPreparer: BlockPackPreparer;\n readonly frontendDownloadDriver: DownloadUrlDriver;\n readonly blockUpdateWatcher: BlockUpdateWatcher;\n readonly quickJs: QuickJSWASMModule;\n readonly driverKit: MiddleLayerDriverKit;\n readonly serviceRegistry: ModelServiceRegistry;\n readonly projectHelper: ProjectHelper;\n}\n\n/**\n * Main access object to work with pl from UI.\n *\n * It implements an abstraction layer of projects and blocks.\n *\n * As a main entry point inside the pl, this object uses a resource attached\n * via the {@link ProjectsField} to the pl client's root, this resource\n * contains project list.\n *\n * Read about alternative roots, if isolated project lists (working environments)\n * are required.\n * */\nexport class MiddleLayer {\n public readonly pl: PlClient;\n\n /** Contains a reactive list of projects along with their meta information. */\n public readonly projectList: ComputableStableDefined<ProjectListEntry[]>;\n\n private constructor(\n private readonly env: MiddleLayerEnvironment,\n public readonly driverKit: DriverKit,\n public readonly signer: Signer,\n private readonly projectListResourceId: ResourceId,\n private readonly openedProjectsList: WatchableValue<ResourceId[]>,\n private readonly projectListTree: SynchronizedTreeState,\n public readonly blockRegistryProvider: V2RegistryProvider,\n projectList: ComputableStableDefined<ProjectListEntry[]>,\n ) {\n this.projectList = projectList;\n this.pl = this.env.pl;\n }\n\n /**\n * Get the OS where backend is running.\n * For old backend versions returns undefined.\n */\n public get serverPlatform(): BlockPlatform | undefined {\n return this.pl.serverInfo.platform as BlockPlatform | undefined;\n }\n\n /** Adds a runtime capability to the middle layer. */\n public addRuntimeCapability(\n requirement: SupportedRequirement,\n value: number | boolean = true,\n ): void {\n this.env.runtimeCapabilities.addSupportedRequirement(requirement, value);\n }\n\n /** Checks if the given block feature flags are compatible with the runtime capabilities. */\n public checkBlockCompatibility(featureFlags: BlockCodeFeatureFlags | undefined): boolean {\n return this.env.runtimeCapabilities.checkCompatibility(featureFlags);\n }\n\n /** Returns extended API driver kit used internally by middle layer. */\n public get internalDriverKit(): MiddleLayerDriverKit {\n return this.env.driverKit;\n }\n\n /** Returns the service registry for service introspection. */\n public get serviceRegistry(): ModelServiceRegistry {\n return this.env.serviceRegistry;\n }\n\n //\n // Project List Manipulation\n //\n\n /** Creates a project with initial state and adds it to project list. */\n public async createProject(meta: ProjectMeta, id: string = randomUUID()): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLCreateProject\", async (tx) => {\n const prj = await createProject(tx, meta);\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", prj);\n await tx.commit();\n return await toGlobalResourceId(prj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n /** Updates project metadata */\n public async setProjectMeta(\n rid: ResourceId,\n meta: ProjectMeta,\n author?: AuthorMarker,\n ): Promise<void> {\n await withProjectAuthored(\n this.env.projectHelper,\n this.pl,\n rid,\n author,\n (prj) => {\n prj.setMeta(meta);\n },\n { name: \"setProjectMeta\" },\n );\n await this.projectListTree.refreshState();\n }\n\n /** Permanently deletes project from the project list, this will result in\n * destruction of all attached objects, like files, analysis results etc. */\n public async deleteProject(id: string): Promise<void> {\n await this.pl.withWriteTx(\"MLRemoveProject\", async (tx) => {\n tx.removeField(field(this.projectListResourceId, id));\n await tx.commit();\n });\n await this.projectListTree.refreshState();\n }\n\n /**\n * Duplicates an existing project and adds the copy to this user's project list.\n *\n * @param sourceRid - resource id of the project to duplicate\n * @param rename - optional function that receives the source label and all existing\n * project labels (read within the same transaction), and returns the label for the copy\n * @param id - optional id for the new project list entry (defaults to random UUID)\n */\n public async duplicateProject(\n sourceRid: ResourceId,\n rename?: (previousLabel: string, existingLabels: string[]) => string,\n id: string = randomUUID(),\n ): Promise<ResourceId> {\n const resource = await this.pl.withWriteTx(\"MLDuplicateProject\", async (tx) => {\n // Read source project meta\n const sourceMeta = await tx.getKValueJson<ProjectMeta>(sourceRid, ProjectMetaKey);\n\n // Read all existing project labels from the project list (parallel reads)\n const projectListData = await tx.getResourceData(this.projectListResourceId, true);\n const projectRids = projectListData.fields.map((f) => f.value).filter(isNotNullResourceId);\n const existingLabels = (\n await Promise.all(\n projectRids.map((rid) => tx.getKValueJson<ProjectMeta>(rid, ProjectMetaKey)),\n )\n ).map((m) => m.label);\n\n // Compute new label\n const newLabel = rename ? rename(sourceMeta.label, existingLabels) : sourceMeta.label;\n\n // Create the duplicate\n const newPrj = await duplicateProject(tx, sourceRid, { label: newLabel });\n\n // Attach to project list\n tx.createField(field(this.projectListResourceId, id), \"Dynamic\", newPrj);\n await tx.commit();\n return await toGlobalResourceId(newPrj);\n });\n await this.projectListTree.refreshState();\n return resource;\n }\n\n //\n // Projects\n //\n\n private readonly openedProjectsByRid = new Map<ResourceId, Project>();\n\n private async projectIdToResourceId(id: string): Promise<ResourceId> {\n return await this.pl.withReadTx(\"Project id to resource id\", async (tx) => {\n const rid = (await tx.getField(field(this.projectListResourceId, id))).value;\n if (isNullResourceId(rid)) throw new Error(\"Unexpected project list structure.\");\n return rid;\n });\n }\n\n private async ensureProjectRid(id: ResourceId | string): Promise<ResourceId> {\n if (typeof id === \"string\") return await this.projectIdToResourceId(id);\n else return id;\n }\n\n /** Opens a project, and starts corresponding project maintenance loop. */\n public async openProject(id: ResourceId | string) {\n const rid = await this.ensureProjectRid(id);\n if (this.openedProjectsByRid.has(rid)) throw new Error(`Project ${rid} already opened`);\n this.openedProjectsByRid.set(rid, await Project.init(this.env, rid));\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Closes the project, and deallocate all corresponding resources. */\n public async closeProject(rid: ResourceId): Promise<void> {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n this.openedProjectsByRid.delete(rid);\n await prj.destroy();\n this.openedProjectsList.setValue([...this.openedProjectsByRid.keys()]);\n }\n\n /** Returns a project access object for opened project, for the given project\n * resource id. */\n public getOpenedProject(rid: ResourceId): Project {\n const prj = this.openedProjectsByRid.get(rid);\n if (prj === undefined) throw new Error(`Project ${rid} not found among opened projects`);\n return prj;\n }\n\n /** Returns true if project with given resource id is currently opened. */\n public isProjectOpened(rid: ResourceId): boolean {\n return this.openedProjectsByRid.has(rid);\n }\n\n /**\n * Deallocates all runtime resources consumed by this object and awaits\n * actual termination of event loops and other processes associated with\n * them.\n */\n public async close() {\n await Promise.all([...this.openedProjectsByRid.values()].map((prj) => prj.destroy()));\n // this.env.quickJs;\n await this.projectListTree.terminate();\n await this.env.dispose();\n await this.pl.close();\n }\n\n /** @deprecated */\n public async closeAndAwaitTermination() {\n await this.close();\n }\n\n /** Generates sufficiently random string to be used as local secret for the\n * middle layer */\n public static generateLocalSecret(): string {\n return HmacSha256Signer.generateSecret();\n }\n\n /** Returns a block event dispatcher, which can be used to listen to block events. */\n public get blockEventDispatcher(): BlockEventDispatcher {\n return this.env.blockEventDispatcher;\n }\n\n /** Initialize middle layer */\n public static async init(\n pl: PlClient,\n workdir: string,\n _ops: MiddleLayerOpsConstructor,\n ): Promise<MiddleLayer> {\n const ops: MiddleLayerOps = {\n ...DefaultMiddleLayerOpsSettings,\n ...DefaultMiddleLayerOpsPaths(workdir),\n ..._ops,\n };\n\n // overriding debug options from environment variables\n ops.defaultTreeOptions.logStat = getDebugFlags().logTreeStats;\n ops.debugOps.dumpInitialTreeState = getDebugFlags().dumpInitialTreeState;\n\n const projects = await pl.withWriteTx(\"MLInitialization\", async (tx) => {\n const projectsField = field(tx.clientRoot, ProjectsField);\n tx.createField(projectsField, \"Dynamic\");\n const projectsFieldData = await tx.getField(projectsField);\n if (isNullResourceId(projectsFieldData.value)) {\n const projects = tx.createEphemeral(ProjectsResourceType);\n tx.lock(projects);\n\n tx.setField(projectsField, projects);\n\n await tx.commit();\n\n return await projects.globalId;\n } else {\n return projectsFieldData.value;\n }\n });\n\n const logger = ops.logger;\n\n const driverKit = await initDriverKit(pl, workdir, ops.frontendDownloadPath, ops);\n\n // passed to components having no own retry logic\n const retryHttpDispatcher = new RetryAgent(pl.httpDispatcher);\n\n const v2RegistryProvider = new V2RegistryProvider(retryHttpDispatcher);\n\n const bpPreparer = new BlockPackPreparer(\n v2RegistryProvider,\n driverKit.signer,\n retryHttpDispatcher,\n );\n\n const quickJs = await getQuickJS();\n\n const runtimeCapabilities = new RuntimeCapabilities();\n // add runtime capabilities of model here\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 1);\n runtimeCapabilities.addSupportedRequirement(\"requiresModelAPIVersion\", 2);\n runtimeCapabilities.addSupportedRequirement(\"requiresCreatePTable\", 2);\n registerServiceCapabilities((flag, value) =>\n runtimeCapabilities.addSupportedRequirement(flag, value),\n );\n // runtime capabilities of the desktop are to be added by the desktop app / test framework\n\n const serviceRegistry = createModelServiceRegistry({ logger });\n\n const env: MiddleLayerEnvironment = {\n pl,\n blockEventDispatcher: new BlockEventDispatcher(),\n signer: driverKit.signer,\n logger,\n httpDispatcher: pl.httpDispatcher,\n retryHttpDispatcher,\n ops,\n bpPreparer,\n frontendDownloadDriver: driverKit.frontendDriver,\n driverKit,\n blockUpdateWatcher: new BlockUpdateWatcher(v2RegistryProvider, logger, {\n minDelay: ops.devBlockUpdateRecheckInterval,\n http: retryHttpDispatcher,\n preferredUpdateChannel: ops.preferredUpdateChannel,\n }),\n runtimeCapabilities,\n serviceRegistry,\n quickJs,\n projectHelper: new ProjectHelper(quickJs, logger),\n dispose: async () => {\n await serviceRegistry.dispose();\n await retryHttpDispatcher.destroy();\n await driverKit.dispose();\n },\n };\n\n const openedProjects = new WatchableValue<ResourceId[]>([]);\n const projectListTC = await createProjectList(pl, projects, openedProjects, env);\n\n return new MiddleLayer(\n env,\n driverKit,\n driverKit.signer,\n projects,\n openedProjects,\n projectListTC.tree,\n v2RegistryProvider,\n projectListTC.computable,\n );\n }\n}\n"],"mappings":"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"}
@@ -159,6 +159,7 @@ var RemoteBlobProviderImpl = class RemoteBlobProviderImpl {
159
159
  }
160
160
  async [Symbol.asyncDispose]() {
161
161
  await this.server.stop();
162
+ await this.pool[Symbol.asyncDispose]();
162
163
  }
163
164
  };
164
165
  const PFrameDriverOpsDefaults = {