@milaboratories/pl-middle-layer 1.10.12

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 (179) hide show
  1. package/dist/block_registry/index.d.ts +4 -0
  2. package/dist/block_registry/index.d.ts.map +1 -0
  3. package/dist/block_registry/registry.d.ts +37 -0
  4. package/dist/block_registry/registry.d.ts.map +1 -0
  5. package/dist/block_registry/registry_spec.d.ts +12 -0
  6. package/dist/block_registry/registry_spec.d.ts.map +1 -0
  7. package/dist/block_registry/watcher.d.ts +15 -0
  8. package/dist/block_registry/watcher.d.ts.map +1 -0
  9. package/dist/block_registry/well_known_registries.d.ts +4 -0
  10. package/dist/block_registry/well_known_registries.d.ts.map +1 -0
  11. package/dist/cfg_render/executor.d.ts +8 -0
  12. package/dist/cfg_render/executor.d.ts.map +1 -0
  13. package/dist/cfg_render/operation.d.ts +29 -0
  14. package/dist/cfg_render/operation.d.ts.map +1 -0
  15. package/dist/cfg_render/renderer.d.ts +6 -0
  16. package/dist/cfg_render/renderer.d.ts.map +1 -0
  17. package/dist/cfg_render/traverse.d.ts +3 -0
  18. package/dist/cfg_render/traverse.d.ts.map +1 -0
  19. package/dist/cfg_render/util.d.ts +5 -0
  20. package/dist/cfg_render/util.d.ts.map +1 -0
  21. package/dist/dev/index.d.ts +21 -0
  22. package/dist/dev/index.d.ts.map +1 -0
  23. package/dist/dev/util.d.ts +3 -0
  24. package/dist/dev/util.d.ts.map +1 -0
  25. package/dist/index.d.ts +13 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +2 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/index.mjs +3587 -0
  30. package/dist/index.mjs.map +1 -0
  31. package/dist/js_render/context.d.ts +68 -0
  32. package/dist/js_render/context.d.ts.map +1 -0
  33. package/dist/js_render/index.d.ts +6 -0
  34. package/dist/js_render/index.d.ts.map +1 -0
  35. package/dist/middle_layer/active_cfg.d.ts +6 -0
  36. package/dist/middle_layer/active_cfg.d.ts.map +1 -0
  37. package/dist/middle_layer/block.d.ts +9 -0
  38. package/dist/middle_layer/block.d.ts.map +1 -0
  39. package/dist/middle_layer/block_ctx.d.ts +20 -0
  40. package/dist/middle_layer/block_ctx.d.ts.map +1 -0
  41. package/dist/middle_layer/block_ctx_unsafe.d.ts +16 -0
  42. package/dist/middle_layer/block_ctx_unsafe.d.ts.map +1 -0
  43. package/dist/middle_layer/driver_kit.d.ts +31 -0
  44. package/dist/middle_layer/driver_kit.d.ts.map +1 -0
  45. package/dist/middle_layer/frontend_path.d.ts +6 -0
  46. package/dist/middle_layer/frontend_path.d.ts.map +1 -0
  47. package/dist/middle_layer/index.d.ts +5 -0
  48. package/dist/middle_layer/index.d.ts.map +1 -0
  49. package/dist/middle_layer/middle_layer.d.ts +78 -0
  50. package/dist/middle_layer/middle_layer.d.ts.map +1 -0
  51. package/dist/middle_layer/navigation_states.d.ts +10 -0
  52. package/dist/middle_layer/navigation_states.d.ts.map +1 -0
  53. package/dist/middle_layer/ops.d.ts +64 -0
  54. package/dist/middle_layer/ops.d.ts.map +1 -0
  55. package/dist/middle_layer/project.d.ts +110 -0
  56. package/dist/middle_layer/project.d.ts.map +1 -0
  57. package/dist/middle_layer/project_list.d.ts +11 -0
  58. package/dist/middle_layer/project_list.d.ts.map +1 -0
  59. package/dist/middle_layer/project_overview.d.ts +8 -0
  60. package/dist/middle_layer/project_overview.d.ts.map +1 -0
  61. package/dist/middle_layer/render.d.ts +6 -0
  62. package/dist/middle_layer/render.d.ts.map +1 -0
  63. package/dist/middle_layer/types.d.ts +11 -0
  64. package/dist/middle_layer/types.d.ts.map +1 -0
  65. package/dist/middle_layer/util.d.ts +3 -0
  66. package/dist/middle_layer/util.d.ts.map +1 -0
  67. package/dist/model/args.d.ts +12 -0
  68. package/dist/model/args.d.ts.map +1 -0
  69. package/dist/model/block_pack.d.ts +8 -0
  70. package/dist/model/block_pack.d.ts.map +1 -0
  71. package/dist/model/block_pack_spec.d.ts +40 -0
  72. package/dist/model/block_pack_spec.d.ts.map +1 -0
  73. package/dist/model/frontend.d.ts +10 -0
  74. package/dist/model/frontend.d.ts.map +1 -0
  75. package/dist/model/index.d.ts +3 -0
  76. package/dist/model/index.d.ts.map +1 -0
  77. package/dist/model/project_model.d.ts +67 -0
  78. package/dist/model/project_model.d.ts.map +1 -0
  79. package/dist/model/project_model_util.d.ts +29 -0
  80. package/dist/model/project_model_util.d.ts.map +1 -0
  81. package/dist/model/template_spec.d.ts +16 -0
  82. package/dist/model/template_spec.d.ts.map +1 -0
  83. package/dist/mutator/block-pack/block_pack.d.ts +17 -0
  84. package/dist/mutator/block-pack/block_pack.d.ts.map +1 -0
  85. package/dist/mutator/block-pack/frontend.d.ts +4 -0
  86. package/dist/mutator/block-pack/frontend.d.ts.map +1 -0
  87. package/dist/mutator/context_export.d.ts +9 -0
  88. package/dist/mutator/context_export.d.ts.map +1 -0
  89. package/dist/mutator/project.d.ts +121 -0
  90. package/dist/mutator/project.d.ts.map +1 -0
  91. package/dist/mutator/template/render_block.d.ts +32 -0
  92. package/dist/mutator/template/render_block.d.ts.map +1 -0
  93. package/dist/mutator/template/render_template.d.ts +12 -0
  94. package/dist/mutator/template/render_template.d.ts.map +1 -0
  95. package/dist/mutator/template/template_loading.d.ts +13 -0
  96. package/dist/mutator/template/template_loading.d.ts.map +1 -0
  97. package/dist/pool/data.d.ts +24 -0
  98. package/dist/pool/data.d.ts.map +1 -0
  99. package/dist/pool/driver.d.ts +22 -0
  100. package/dist/pool/driver.d.ts.map +1 -0
  101. package/dist/pool/index.d.ts +3 -0
  102. package/dist/pool/index.d.ts.map +1 -0
  103. package/dist/pool/p_object_collection.d.ts +29 -0
  104. package/dist/pool/p_object_collection.d.ts.map +1 -0
  105. package/dist/pool/ref_count_pool.d.ts +25 -0
  106. package/dist/pool/ref_count_pool.d.ts.map +1 -0
  107. package/dist/pool/result_pool.d.ts +25 -0
  108. package/dist/pool/result_pool.d.ts.map +1 -0
  109. package/dist/test/block_packs.d.ts +6 -0
  110. package/dist/test/block_packs.d.ts.map +1 -0
  111. package/dist/test/explicit_templates.d.ts +3 -0
  112. package/dist/test/explicit_templates.d.ts.map +1 -0
  113. package/dist/test/known_templates.d.ts +6 -0
  114. package/dist/test/known_templates.d.ts.map +1 -0
  115. package/package.json +55 -0
  116. package/src/block_registry/index.ts +3 -0
  117. package/src/block_registry/registry.test.ts +35 -0
  118. package/src/block_registry/registry.ts +180 -0
  119. package/src/block_registry/registry_spec.ts +13 -0
  120. package/src/block_registry/watcher.ts +72 -0
  121. package/src/block_registry/well_known_registries.ts +13 -0
  122. package/src/cfg_render/executor.test.ts +120 -0
  123. package/src/cfg_render/executor.ts +253 -0
  124. package/src/cfg_render/operation.ts +38 -0
  125. package/src/cfg_render/renderer.ts +540 -0
  126. package/src/cfg_render/traverse.ts +58 -0
  127. package/src/cfg_render/util.ts +29 -0
  128. package/src/dev/index.ts +89 -0
  129. package/src/dev/util.ts +13 -0
  130. package/src/index.ts +21 -0
  131. package/src/js_render/context.ts +768 -0
  132. package/src/js_render/index.ts +41 -0
  133. package/src/middle_layer/active_cfg.ts +56 -0
  134. package/src/middle_layer/block.ts +70 -0
  135. package/src/middle_layer/block_ctx.ts +90 -0
  136. package/src/middle_layer/block_ctx_unsafe.ts +29 -0
  137. package/src/middle_layer/driver_kit.ts +107 -0
  138. package/src/middle_layer/frontend_path.ts +83 -0
  139. package/src/middle_layer/index.ts +4 -0
  140. package/src/middle_layer/middle_layer.test.ts +720 -0
  141. package/src/middle_layer/middle_layer.ts +235 -0
  142. package/src/middle_layer/navigation_states.ts +48 -0
  143. package/src/middle_layer/ops.ts +147 -0
  144. package/src/middle_layer/project.ts +380 -0
  145. package/src/middle_layer/project_list.ts +59 -0
  146. package/src/middle_layer/project_overview.ts +220 -0
  147. package/src/middle_layer/render.test.ts +129 -0
  148. package/src/middle_layer/render.ts +19 -0
  149. package/src/middle_layer/types.ts +16 -0
  150. package/src/middle_layer/util.ts +22 -0
  151. package/src/model/args.ts +62 -0
  152. package/src/model/block_pack.ts +8 -0
  153. package/src/model/block_pack_spec.ts +52 -0
  154. package/src/model/frontend.ts +10 -0
  155. package/src/model/index.ts +2 -0
  156. package/src/model/project_model.test.ts +26 -0
  157. package/src/model/project_model.ts +142 -0
  158. package/src/model/project_model_util.test.ts +88 -0
  159. package/src/model/project_model_util.ts +169 -0
  160. package/src/model/template_spec.ts +18 -0
  161. package/src/mutator/block-pack/block_pack.test.ts +53 -0
  162. package/src/mutator/block-pack/block_pack.ts +187 -0
  163. package/src/mutator/block-pack/frontend.ts +29 -0
  164. package/src/mutator/context_export.ts +25 -0
  165. package/src/mutator/project.test.ts +272 -0
  166. package/src/mutator/project.ts +1112 -0
  167. package/src/mutator/template/render_block.ts +91 -0
  168. package/src/mutator/template/render_template.ts +40 -0
  169. package/src/mutator/template/template_loading.ts +77 -0
  170. package/src/mutator/template/template_render.test.ts +272 -0
  171. package/src/pool/data.ts +239 -0
  172. package/src/pool/driver.ts +325 -0
  173. package/src/pool/index.ts +2 -0
  174. package/src/pool/p_object_collection.ts +122 -0
  175. package/src/pool/ref_count_pool.ts +76 -0
  176. package/src/pool/result_pool.ts +284 -0
  177. package/src/test/block_packs.ts +23 -0
  178. package/src/test/explicit_templates.ts +8 -0
  179. package/src/test/known_templates.ts +24 -0
@@ -0,0 +1,169 @@
1
+ import { Block, ProjectStructure } from './project_model';
2
+ import { Optional, Writable } from 'utility-types';
3
+ import { inferAllReferencedBlocks } from './args';
4
+
5
+ export function allBlocks(structure: ProjectStructure): Iterable<Block> {
6
+ return {
7
+ *[Symbol.iterator]() {
8
+ for (const g of structure.groups) for (const b of g.blocks) yield b;
9
+ }
10
+ };
11
+ }
12
+
13
+ export interface BlockGraphNode {
14
+ readonly id: string;
15
+ readonly missingReferences: boolean;
16
+ /** Direct upstreams */
17
+ readonly upstream: Set<string>;
18
+ /** Direct downstreams */
19
+ readonly downstream: Set<string>;
20
+ }
21
+
22
+ export class BlockGraph {
23
+ /** Nodes are stored in the map in topological order */
24
+ public readonly nodes: Map<string, BlockGraphNode>;
25
+
26
+ constructor(nodes: Map<string, BlockGraphNode>) {
27
+ this.nodes = nodes;
28
+ }
29
+
30
+ public traverseIds(direction: 'upstream' | 'downstream', ...rootBlockIds: string[]): Set<string> {
31
+ const all = new Set<string>();
32
+ this.traverse(direction, rootBlockIds, (node) => all.add(node.id));
33
+ return all;
34
+ }
35
+
36
+ public traverseIdsExcludingRoots(
37
+ direction: 'upstream' | 'downstream',
38
+ ...rootBlockIds: string[]
39
+ ): Set<string> {
40
+ const result = this.traverseIds(direction, ...rootBlockIds);
41
+ for (const r of rootBlockIds) result.delete(r);
42
+ return result;
43
+ }
44
+
45
+ public traverse(
46
+ direction: 'upstream' | 'downstream',
47
+ rootBlockIds: string[],
48
+ cb: (node: BlockGraphNode) => void
49
+ ): void {
50
+ let unprocessed = [...rootBlockIds];
51
+ // used to deduplicate possible downstream / upstream blocks and process them only once
52
+ const queued = new Set<string>(unprocessed);
53
+ while (unprocessed.length > 0) {
54
+ let nextUnprocessed: string[] = [];
55
+ for (const blockId of unprocessed) {
56
+ const info = this.nodes.get(blockId)!;
57
+ cb(info);
58
+ info[direction]!.forEach((v) => {
59
+ if (!queued.has(v)) {
60
+ queued.add(v);
61
+ nextUnprocessed.push(v);
62
+ }
63
+ });
64
+ }
65
+ unprocessed = nextUnprocessed;
66
+ }
67
+ }
68
+ }
69
+
70
+ export function stagingGraph(structure: ProjectStructure) {
71
+ type WNode = Optional<Writable<BlockGraphNode>, 'upstream' | 'downstream'>;
72
+ const result = new Map<string, WNode>();
73
+
74
+ // Simple dependency graph from previous to next
75
+ //
76
+ // more complicated patterns to be implemented later
77
+ // (i.e. groups with specific behaviours for total outputs and inputs)
78
+ //
79
+ let previous: WNode | undefined = undefined;
80
+ for (const { id } of allBlocks(structure)) {
81
+ const current: WNode = {
82
+ id: id,
83
+ missingReferences: false
84
+ };
85
+ result.set(id, current);
86
+ if (previous === undefined) {
87
+ current.upstream = new Set<string>();
88
+ } else {
89
+ current.upstream = new Set<string>([previous.id]);
90
+ previous.downstream = new Set<string>([current.id]);
91
+ }
92
+
93
+ previous = current;
94
+ }
95
+ if (previous !== undefined) previous.downstream = new Set<string>();
96
+
97
+ return new BlockGraph(result as Map<string, BlockGraphNode>);
98
+ }
99
+
100
+ export function productionGraph(
101
+ structure: ProjectStructure,
102
+ argsProvider: (blockId: string) => any | undefined
103
+ ): BlockGraph {
104
+ const result = new Map<string, BlockGraphNode>();
105
+
106
+ // traversing blocks in topological order defined by the project structure
107
+ // and keeping possibleUpstreams set on each step, to consider only
108
+ // those dependencies that are possible under current topology
109
+ const possibleUpstreams = new Set<string>();
110
+ for (const { id } of allBlocks(structure)) {
111
+ const args = argsProvider(id);
112
+
113
+ // skipping those blocks for which we don't have args
114
+ if (args === undefined) continue;
115
+
116
+ const upstreams = inferAllReferencedBlocks(args, possibleUpstreams);
117
+ const node: BlockGraphNode = {
118
+ id,
119
+ missingReferences: upstreams.missingReferences,
120
+ upstream: upstreams.upstreams,
121
+ downstream: new Set<string>() // will be populated from downstream blocks
122
+ };
123
+ result.set(id, node);
124
+ upstreams.upstreams.forEach((dep) => result.get(dep)!.downstream.add(id));
125
+ possibleUpstreams.add(id);
126
+ }
127
+
128
+ return new BlockGraph(result);
129
+ }
130
+
131
+ function setsEqual<T>(a: Set<T>, b: Set<T>): boolean {
132
+ if (a.size !== b.size) return false;
133
+ for (const e of a) if (!b.has(e)) return false;
134
+ return true;
135
+ }
136
+
137
+ function intersects<T>(a: Set<T>, b: Set<T>): boolean {
138
+ if (a.size > b.size) return intersects(b, a);
139
+ for (const e of a) if (b.has(e)) return true;
140
+ return false;
141
+ }
142
+
143
+ export interface GraphDiff {
144
+ onlyInA: Set<string>;
145
+ /** Nodes that changed the list of their upstreams,
146
+ * and all their downstreams */
147
+ different: Set<string>;
148
+ onlyInB: Set<string>;
149
+ }
150
+
151
+ export function graphDiff(a: BlockGraph, b: BlockGraph): GraphDiff {
152
+ let matched = 0;
153
+ const onlyInA = new Set<string>();
154
+ const onlyInB = new Set<string>();
155
+ const different = new Set<string>();
156
+ a.nodes.forEach((fromA) => {
157
+ const fromB = b.nodes.get(fromA.id);
158
+ if (fromB === undefined) onlyInA.add(fromA.id);
159
+ else if (!setsEqual(fromA.upstream, fromB.upstream) || intersects(fromA.upstream, different))
160
+ different.add(fromA.id);
161
+ });
162
+
163
+ b.nodes.forEach((fromB) => {
164
+ if (!a.nodes.has(fromB.id)) onlyInB.add(fromB.id);
165
+ else if (intersects(fromB.upstream, different)) different.add(fromB.id);
166
+ });
167
+
168
+ return { onlyInA, onlyInB, different };
169
+ }
@@ -0,0 +1,18 @@
1
+ export interface TemplateFromRegistry {
2
+ readonly type: 'from-registry';
3
+ registry: string;
4
+ path: string;
5
+ }
6
+
7
+ export interface ExplicitTemplate {
8
+ readonly type: 'explicit';
9
+ content: Uint8Array;
10
+ }
11
+
12
+ export interface TemplateFromFile {
13
+ readonly type: 'from-file';
14
+ path: string;
15
+ }
16
+
17
+ export type TemplateSpecPrepared = TemplateFromRegistry | ExplicitTemplate;
18
+ export type TemplateSpecAny = TemplateSpecPrepared | TemplateFromFile;
@@ -0,0 +1,53 @@
1
+ import {
2
+ isNullResourceId,
3
+ poll,
4
+ TestHelpers,
5
+ toGlobalResourceId
6
+ } from '@milaboratories/pl-client';
7
+ import { BlockPackPreparer, createBlockPack } from './block_pack';
8
+ import { BlockPackSpecAny } from '../../model';
9
+ import path from 'node:path';
10
+ import { HmacSha256Signer } from '@milaboratories/ts-helpers';
11
+
12
+ const preparation = new BlockPackPreparer(new HmacSha256Signer(HmacSha256Signer.generateSecret()));
13
+
14
+ test.each([
15
+ {
16
+ spec: {
17
+ type: 'from-registry-v1',
18
+ registryUrl: 'https://block.registry.platforma.bio/releases',
19
+ organization: 'milaboratory',
20
+ package: 'enter-numbers',
21
+ version: '0.4.1'
22
+ } as BlockPackSpecAny
23
+ },
24
+ {
25
+ spec: {
26
+ type: 'dev',
27
+ folder: path.resolve('integration', 'block-beta-sum-numbers')
28
+ } as BlockPackSpecAny
29
+ }
30
+ ])('test load template from $spec.type', async ({ spec }) => {
31
+ const config = await preparation.getBlockConfig(spec);
32
+ expect(config).toBeDefined();
33
+ expect(config.renderingMode).toEqual('Heavy');
34
+
35
+ const specPrepared = await preparation.prepare(spec);
36
+
37
+ await TestHelpers.withTempRoot(async (pl) => {
38
+ const f0 = { resourceId: pl.clientRoot, fieldName: 'test0' };
39
+
40
+ const bp = await pl.withWriteTx('test', async (tx) => {
41
+ tx.createField(f0, 'Dynamic');
42
+ const bp = createBlockPack(tx, specPrepared);
43
+ tx.setField(f0, bp);
44
+ await tx.commit();
45
+ return await toGlobalResourceId(bp);
46
+ });
47
+
48
+ await poll(pl, async (a) => {
49
+ const r = await a.get(bp).then((r) => r.final()); // this will await final state
50
+ expect(isNullResourceId(r.data.error)).toBe(true);
51
+ });
52
+ });
53
+ });
@@ -0,0 +1,187 @@
1
+ import { AnyResourceRef, field, PlTransaction, ResourceType } from '@milaboratories/pl-client';
2
+ import { loadTemplate } from '../template/template_loading';
3
+ import { BlockPackExplicit, BlockPackSpecAny, BlockPackSpecPrepared } from '../../model';
4
+ import { assertNever, Signer } from '@milaboratories/ts-helpers';
5
+ import fs from 'node:fs';
6
+ import { Dispatcher, request } from 'undici';
7
+ import { createFrontend } from './frontend';
8
+ import { BlockConfig } from '@platforma-sdk/model';
9
+ import { loadPackDescription, RegistryV1 } from '@platforma-sdk/block-tools';
10
+ import { BlockPackInfo } from '../../model/block_pack';
11
+ import { resolveDevPacket } from '../../dev';
12
+ import { getDevV2PacketMtime } from '../../block_registry';
13
+
14
+ export const BlockPackCustomType: ResourceType = { name: 'BlockPackCustom', version: '1' };
15
+ export const BlockPackTemplateField = 'template';
16
+ export const BlockPackFrontendField = 'frontend';
17
+
18
+ /** Ensure trailing slash */
19
+ function tSlash(str: string): string {
20
+ if (str.endsWith('/')) return str;
21
+ else return `${str}/`;
22
+ }
23
+
24
+ export class BlockPackPreparer {
25
+ constructor(
26
+ private readonly signer: Signer,
27
+ private readonly http?: Dispatcher
28
+ ) {}
29
+
30
+ public async getBlockConfig(spec: BlockPackSpecAny): Promise<BlockConfig> {
31
+ switch (spec.type) {
32
+ case 'explicit':
33
+ return spec.config;
34
+
35
+ case 'dev':
36
+ case 'dev-v1': {
37
+ const devPaths = await resolveDevPacket(spec.folder, false);
38
+ const configContent = await fs.promises.readFile(devPaths.config, { encoding: 'utf-8' });
39
+ return JSON.parse(configContent) as BlockConfig;
40
+ }
41
+
42
+ case 'dev-v2': {
43
+ const description = await loadPackDescription(spec.folder);
44
+ const configContent = await fs.promises.readFile(description.components.model.file, {
45
+ encoding: 'utf-8'
46
+ });
47
+ return JSON.parse(configContent) as BlockConfig;
48
+ }
49
+
50
+ case 'from-registry-v1': {
51
+ const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};
52
+
53
+ const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix(spec)}`;
54
+
55
+ const configResponse = await request(`${urlPrefix}/config.json`, httpOptions);
56
+
57
+ return (await configResponse.body.json()) as BlockConfig;
58
+ }
59
+
60
+ default:
61
+ return assertNever(spec);
62
+ }
63
+ }
64
+
65
+ public async prepare(spec: BlockPackSpecAny): Promise<BlockPackSpecPrepared> {
66
+ switch (spec.type) {
67
+ case 'explicit':
68
+ return spec;
69
+
70
+ case 'dev':
71
+ case 'dev-v1': {
72
+ const devPaths = await resolveDevPacket(spec.folder, false);
73
+
74
+ // template
75
+ const templateContent = await fs.promises.readFile(devPaths.workflow);
76
+
77
+ // config
78
+ const config = JSON.parse(
79
+ await fs.promises.readFile(devPaths.config, 'utf-8')
80
+ ) as BlockConfig;
81
+
82
+ // frontend
83
+ const frontendPath = devPaths.ui;
84
+
85
+ return {
86
+ type: 'explicit',
87
+ template: {
88
+ type: 'explicit',
89
+ content: templateContent
90
+ },
91
+ config,
92
+ frontend: {
93
+ type: 'local',
94
+ path: frontendPath,
95
+ signature: this.signer.sign(frontendPath)
96
+ },
97
+ source: spec
98
+ };
99
+ }
100
+
101
+ case 'dev-v2': {
102
+ const description = await loadPackDescription(spec.folder);
103
+ const config = JSON.parse(
104
+ await fs.promises.readFile(description.components.model.file, {
105
+ encoding: 'utf-8'
106
+ })
107
+ ) as BlockConfig;
108
+ const workflowContent = await fs.promises.readFile(description.components.workflow.file);
109
+ const frontendPath = description.components.ui.folder;
110
+ const source = { ...spec };
111
+ if (spec.mtime === undefined)
112
+ // if absent, calculating the mtime here, so the block will correctly show whether it can be updated
113
+ source.mtime = await getDevV2PacketMtime(description);
114
+ return {
115
+ type: 'explicit',
116
+ template: {
117
+ type: 'explicit',
118
+ content: workflowContent
119
+ },
120
+ config,
121
+ frontend: {
122
+ type: 'local',
123
+ path: frontendPath,
124
+ signature: this.signer.sign(frontendPath)
125
+ },
126
+ source
127
+ };
128
+ }
129
+
130
+ case 'from-registry-v1': {
131
+ const httpOptions = this.http !== undefined ? { dispatcher: this.http } : {};
132
+
133
+ const urlPrefix = `${tSlash(spec.registryUrl)}${RegistryV1.packageContentPrefix(spec)}`;
134
+
135
+ const templateUrl = `${urlPrefix}/template.plj.gz`;
136
+ // template
137
+ const templateResponse = await request(templateUrl, httpOptions);
138
+ if (templateResponse.statusCode !== 200)
139
+ throw new Error(
140
+ `Block not found in registry (url = ${templateUrl} ; code = ${templateResponse.statusCode}): ` +
141
+ JSON.stringify(spec)
142
+ );
143
+ const templateContent = new Uint8Array(await templateResponse.body.arrayBuffer());
144
+
145
+ // config
146
+ const configResponse = await request(`${urlPrefix}/config.json`, httpOptions);
147
+ const config = (await configResponse.body.json()) as BlockConfig;
148
+
149
+ return {
150
+ type: 'explicit',
151
+ template: {
152
+ type: 'explicit',
153
+ content: templateContent
154
+ },
155
+ config,
156
+ frontend: {
157
+ type: 'url',
158
+ url: `${urlPrefix}/frontend.tgz`
159
+ },
160
+ source: spec
161
+ };
162
+ }
163
+
164
+ default:
165
+ return assertNever(spec);
166
+ }
167
+ }
168
+ }
169
+
170
+ function createCustomBlockPack(tx: PlTransaction, spec: BlockPackExplicit): AnyResourceRef {
171
+ const blockPackInfo: BlockPackInfo = { config: spec.config, source: spec.source };
172
+ const bp = tx.createStruct(BlockPackCustomType, JSON.stringify(blockPackInfo));
173
+ tx.createField(field(bp, BlockPackTemplateField), 'Input', loadTemplate(tx, spec.template));
174
+ tx.createField(field(bp, BlockPackFrontendField), 'Input', createFrontend(tx, spec.frontend));
175
+ tx.lock(bp);
176
+
177
+ return bp;
178
+ }
179
+
180
+ export function createBlockPack(tx: PlTransaction, spec: BlockPackSpecPrepared): AnyResourceRef {
181
+ switch (spec.type) {
182
+ case 'explicit':
183
+ return createCustomBlockPack(tx, spec);
184
+ default:
185
+ return assertNever(spec.type);
186
+ }
187
+ }
@@ -0,0 +1,29 @@
1
+ import { AnyResourceRef, PlTransaction } from '@milaboratories/pl-client';
2
+ import {
3
+ FrontendFromFolderData,
4
+ FrontendFromFolderResourceType,
5
+ FrontendFromUrlData,
6
+ FrontendFromUrlResourceType,
7
+ FrontendSpec
8
+ } from '../../model';
9
+ import { assertNever } from '@milaboratories/ts-helpers';
10
+
11
+ export function createFrontend(tx: PlTransaction, spec: FrontendSpec): AnyResourceRef {
12
+ switch (spec.type) {
13
+ case 'url':
14
+ return tx.createValue(
15
+ FrontendFromUrlResourceType,
16
+ JSON.stringify({ url: spec.url } as FrontendFromUrlData)
17
+ );
18
+ case 'local':
19
+ return tx.createValue(
20
+ FrontendFromFolderResourceType,
21
+ JSON.stringify({
22
+ path: spec.path,
23
+ signature: spec.signature
24
+ } as FrontendFromFolderData)
25
+ );
26
+ default:
27
+ return assertNever(spec);
28
+ }
29
+ }
@@ -0,0 +1,25 @@
1
+ import { AnyRef, PlTransaction } from '@milaboratories/pl-client';
2
+ import { Templates as SdkTemplates } from '@platforma-sdk/workflow-tengo';
3
+ import { createRenderTemplate } from './template/render_template';
4
+ import { prepareTemplateSpec } from './template/template_loading';
5
+ import { TemplateSpecPrepared } from '../model/template_spec';
6
+ import { createHash } from 'crypto';
7
+
8
+ export type TemplateEnvelop = { spec: TemplateSpecPrepared; hash: string };
9
+
10
+ let preparedTemplateEnvelop: TemplateEnvelop | undefined;
11
+
12
+ export async function getPreparedExportTemplateEnvelope(): Promise<TemplateEnvelop> {
13
+ if (preparedTemplateEnvelop === undefined) {
14
+ const preparedTemplate = await prepareTemplateSpec(SdkTemplates['pframes.export-pframe']);
15
+ if (preparedTemplate.type !== 'explicit') throw new Error('Unexpected prepared template type.');
16
+ const hash = createHash('sha256').update(preparedTemplate.content).digest('hex');
17
+ preparedTemplateEnvelop = { spec: preparedTemplate, hash };
18
+ }
19
+
20
+ return preparedTemplateEnvelop;
21
+ }
22
+
23
+ export function exportContext(tx: PlTransaction, exportTpl: AnyRef, ctx: AnyRef) {
24
+ return createRenderTemplate(tx, exportTpl, true, { pf: ctx }, ['result']).result;
25
+ }