@milaboratories/pl-middle-layer 1.58.4 → 1.59.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 (85) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/middle_layer/middle_layer.cjs +71 -47
  3. package/dist/middle_layer/middle_layer.cjs.map +1 -1
  4. package/dist/middle_layer/middle_layer.d.ts +18 -18
  5. package/dist/middle_layer/middle_layer.d.ts.map +1 -1
  6. package/dist/middle_layer/middle_layer.js +72 -48
  7. package/dist/middle_layer/middle_layer.js.map +1 -1
  8. package/dist/middle_layer/project.cjs +8 -9
  9. package/dist/middle_layer/project.cjs.map +1 -1
  10. package/dist/middle_layer/project.d.ts +6 -5
  11. package/dist/middle_layer/project.d.ts.map +1 -1
  12. package/dist/middle_layer/project.js +9 -10
  13. package/dist/middle_layer/project.js.map +1 -1
  14. package/dist/middle_layer/project_list.cjs +3 -3
  15. package/dist/middle_layer/project_list.cjs.map +1 -1
  16. package/dist/middle_layer/project_list.d.ts +1 -1
  17. package/dist/middle_layer/project_list.js +4 -4
  18. package/dist/middle_layer/project_list.js.map +1 -1
  19. package/dist/middle_layer/project_overview.cjs.map +1 -1
  20. package/dist/middle_layer/project_overview.js.map +1 -1
  21. package/dist/middle_layer/util.cjs.map +1 -1
  22. package/dist/middle_layer/util.js.map +1 -1
  23. package/dist/model/index.d.ts +2 -2
  24. package/dist/model/project_helper.cjs.map +1 -1
  25. package/dist/model/project_helper.d.ts +3 -3
  26. package/dist/model/project_helper.d.ts.map +1 -1
  27. package/dist/model/project_helper.js.map +1 -1
  28. package/dist/model/project_model.cjs.map +1 -1
  29. package/dist/model/project_model.d.ts +6 -5
  30. package/dist/model/project_model.d.ts.map +1 -1
  31. package/dist/model/project_model.js.map +1 -1
  32. package/dist/model/template_spec.d.ts +2 -2
  33. package/dist/model/template_spec.d.ts.map +1 -1
  34. package/dist/mutator/migration.cjs +1 -1
  35. package/dist/mutator/migration.cjs.map +1 -1
  36. package/dist/mutator/migration.js +2 -2
  37. package/dist/mutator/migration.js.map +1 -1
  38. package/dist/mutator/project.cjs +6 -6
  39. package/dist/mutator/project.cjs.map +1 -1
  40. package/dist/mutator/project.d.ts +3 -3
  41. package/dist/mutator/project.d.ts.map +1 -1
  42. package/dist/mutator/project.js +7 -7
  43. package/dist/mutator/project.js.map +1 -1
  44. package/dist/mutator/template/template_cache.cjs +7 -7
  45. package/dist/mutator/template/template_cache.cjs.map +1 -1
  46. package/dist/mutator/template/template_cache.d.ts +8 -8
  47. package/dist/mutator/template/template_cache.d.ts.map +1 -1
  48. package/dist/mutator/template/template_cache.js +8 -8
  49. package/dist/mutator/template/template_cache.js.map +1 -1
  50. package/dist/network_check/template.cjs +5 -5
  51. package/dist/network_check/template.cjs.map +1 -1
  52. package/dist/network_check/template.js +6 -6
  53. package/dist/network_check/template.js.map +1 -1
  54. package/dist/pool/data.cjs +2 -1
  55. package/dist/pool/data.cjs.map +1 -1
  56. package/dist/pool/data.d.ts +1 -1
  57. package/dist/pool/data.d.ts.map +1 -1
  58. package/dist/pool/data.js +3 -2
  59. package/dist/pool/data.js.map +1 -1
  60. package/dist/pool/driver.cjs +3 -1
  61. package/dist/pool/driver.cjs.map +1 -1
  62. package/dist/pool/driver.d.ts.map +1 -1
  63. package/dist/pool/driver.js +3 -1
  64. package/dist/pool/driver.js.map +1 -1
  65. package/package.json +15 -15
  66. package/src/index.ts +1 -1
  67. package/src/middle_layer/middle_layer.ts +99 -61
  68. package/src/middle_layer/project.ts +14 -13
  69. package/src/middle_layer/project_list.ts +10 -8
  70. package/src/middle_layer/project_overview.ts +2 -2
  71. package/src/middle_layer/render.test.ts +9 -9
  72. package/src/middle_layer/util.ts +2 -2
  73. package/src/model/index.ts +1 -1
  74. package/src/model/project_helper.ts +2 -2
  75. package/src/model/project_model.ts +7 -4
  76. package/src/model/template_spec.ts +2 -2
  77. package/src/mutator/block-pack/block_pack.test.ts +7 -2
  78. package/src/mutator/migration.ts +7 -7
  79. package/src/mutator/project.ts +20 -19
  80. package/src/mutator/template/template_cache.test.ts +6 -6
  81. package/src/mutator/template/template_cache.ts +24 -21
  82. package/src/mutator/template/template_render.test.ts +7 -7
  83. package/src/network_check/template.ts +8 -8
  84. package/src/pool/data.ts +6 -4
  85. package/src/pool/driver.ts +3 -1
@@ -1,11 +1,11 @@
1
1
  import type { PruningFunction } from "@milaboratories/pl-tree";
2
2
  import { SynchronizedTreeState } from "@milaboratories/pl-tree";
3
- import type { PlClient, ResourceId, ResourceType } from "@milaboratories/pl-client";
4
- import { resourceTypesEqual } from "@milaboratories/pl-client";
3
+ import type { PlClient, SignedResourceId, ResourceType } from "@milaboratories/pl-client";
4
+ import { resourceIdToString, resourceTypesEqual } from "@milaboratories/pl-client";
5
5
  import type { TreeAndComputableU } from "./types";
6
6
  import type { WatchableValue } from "@milaboratories/computable";
7
7
  import { Computable } from "@milaboratories/computable";
8
- import type { ProjectListEntry } from "../model/project_model";
8
+ import type { ProjectId, ProjectListEntry } from "../model/project_model";
9
9
  import {
10
10
  ProjectCreatedTimestamp,
11
11
  ProjectLastModifiedTimestamp,
@@ -25,8 +25,8 @@ export const ProjectsListTreePruningFunction: PruningFunction = (resource) => {
25
25
 
26
26
  export async function createProjectList(
27
27
  pl: PlClient,
28
- rid: ResourceId,
29
- openedProjects: WatchableValue<ResourceId[]>,
28
+ rid: SignedResourceId,
29
+ openedProjects: WatchableValue<ProjectId[]>,
30
30
  env: MiddleLayerEnvironment,
31
31
  ): Promise<TreeAndComputableU<ProjectListEntry[]>> {
32
32
  const tree = await SynchronizedTreeState.init(
@@ -44,18 +44,20 @@ export async function createProjectList(
44
44
  const oProjects = openedProjects.getValue(ctx);
45
45
  if (node === undefined) return undefined;
46
46
  const result: ProjectListEntry[] = [];
47
+
48
+ // Projects list resource keeps projects assigned to fields. Each field name is project's UUID
47
49
  for (const field of node.listDynamicFields()) {
48
50
  const prj = node.traverse(field);
49
51
  if (prj === undefined) continue;
50
52
  const meta = notEmpty(prj.getKeyValueAsJson<ProjectMeta>(ProjectMetaKey));
51
53
  const created = notEmpty(prj.getKeyValueAsJson<number>(ProjectCreatedTimestamp));
52
54
  const lastModified = notEmpty(prj.getKeyValueAsJson<number>(ProjectLastModifiedTimestamp));
55
+ const projectId = resourceIdToString(prj.id) as ProjectId;
53
56
  result.push({
54
- id: field,
55
- rid: prj.id,
57
+ id: projectId,
56
58
  created: new Date(created),
57
59
  lastModified: new Date(lastModified),
58
- opened: oProjects.indexOf(prj.id) >= 0,
60
+ opened: oProjects.indexOf(projectId) >= 0,
59
61
  meta,
60
62
  });
61
63
  }
@@ -28,12 +28,12 @@ import { extractCodeWithInfo, wrapCallback } from "@platforma-sdk/model";
28
28
  import { computableFromCfgOrRF } from "./render";
29
29
  import type { NavigationStates } from "./navigation_states";
30
30
  import { getBlockPackInfo } from "./util";
31
- import { resourceIdToString, type ResourceId } from "@milaboratories/pl-client";
31
+ import { resourceIdToString, type SignedResourceId } from "@milaboratories/pl-client";
32
32
  import { omitBy, isEqual } from "es-toolkit";
33
33
  import { getDebugFlags } from "../debug";
34
34
 
35
35
  type BlockInfo = {
36
- argsRid?: ResourceId;
36
+ argsRid?: SignedResourceId;
37
37
  currentArguments: unknown;
38
38
  prod?: ProdState;
39
39
  };
@@ -60,9 +60,9 @@ export async function awaitBlockDone(prj: Project, blockId: string, timeout: num
60
60
 
61
61
  test("test JS render enter numbers", async () => {
62
62
  await withMl(async (ml) => {
63
- const pRid1 = await ml.createProject({ label: "Project 1" }, "id1");
64
- await ml.openProject(pRid1);
65
- const prj = ml.getOpenedProject(pRid1);
63
+ const prj1Id = await ml.createProject({ label: "Project 1" });
64
+ await ml.openProject(prj1Id);
65
+ const prj = ml.getOpenedProject(prj1Id);
66
66
 
67
67
  const block1Id = await prj.addBlock("Block 1", {
68
68
  type: "from-registry-v1",
@@ -82,9 +82,9 @@ test("test JS render enter numbers", async () => {
82
82
 
83
83
  test.skip("test JS render options", async () => {
84
84
  await withMl(async (ml) => {
85
- const pRid1 = await ml.createProject({ label: "Project 1" }, "id1");
86
- await ml.openProject(pRid1);
87
- const prj = ml.getOpenedProject(pRid1);
85
+ const prj1Id = await ml.createProject({ label: "Project 1" });
86
+ await ml.openProject(prj1Id);
87
+ const prj = ml.getOpenedProject(prj1Id);
88
88
 
89
89
  const block1Id = await prj.addBlock("Block 1", {
90
90
  type: "from-registry-v1",
@@ -118,9 +118,9 @@ test.skip("test JS render options", async () => {
118
118
 
119
119
  test.skip("test JS render download", async () => {
120
120
  await withMl(async (ml) => {
121
- const pRid1 = await ml.createProject({ label: "Project 1" }, "id1");
122
- await ml.openProject(pRid1);
123
- const prj = ml.getOpenedProject(pRid1);
121
+ const prj1Id = await ml.createProject({ label: "Project 1" });
122
+ await ml.openProject(prj1Id);
123
+ const prj = ml.getOpenedProject(prj1Id);
124
124
 
125
125
  const block1Id = await prj.addBlock("Block 1", {
126
126
  type: "from-registry-v1",
@@ -1,6 +1,6 @@
1
1
  import type { PlTreeNodeAccessor } from "@milaboratories/pl-tree";
2
2
  import { projectFieldName } from "../model/project_model";
3
- import type { ResourceId } from "@milaboratories/pl-client";
3
+ import type { SignedResourceId } from "@milaboratories/pl-client";
4
4
  import { Pl } from "@milaboratories/pl-client";
5
5
  import { ifNotUndef } from "../cfg_render/util";
6
6
  import type { BlockPackInfo } from "../model/block_pack";
@@ -8,7 +8,7 @@ import type { BlockConfig } from "@platforma-sdk/model";
8
8
  import { extractConfig } from "@platforma-sdk/model";
9
9
 
10
10
  export type BlockPackInfoAndId = {
11
- readonly bpResourceId: ResourceId;
11
+ readonly bpResourceId: SignedResourceId;
12
12
  /** To be added to computable keys, to force reload on config change */
13
13
  readonly bpId: string;
14
14
  /** Full block-pack info */
@@ -1,5 +1,5 @@
1
1
  export * from "./block_pack_spec";
2
- export { type ProjectListEntry, type ProjectField } from "./project_model";
2
+ export { type ProjectId, type ProjectListEntry, type ProjectField } from "./project_model";
3
3
 
4
4
  export {
5
5
  ProjectMetaKey,
@@ -9,7 +9,7 @@ import {
9
9
  import { LRUCache } from "lru-cache";
10
10
  import type { QuickJSWASMModule } from "quickjs-emscripten";
11
11
  import { executeSingleLambda } from "../js_render";
12
- import type { ResourceId } from "@milaboratories/pl-client";
12
+ import type { SignedResourceId } from "@milaboratories/pl-client";
13
13
  import { ConsoleLoggerAdapter, type MiLogger } from "@milaboratories/ts-helpers";
14
14
  import type { StorageDebugView } from "@milaboratories/pl-model-middle-layer";
15
15
 
@@ -146,7 +146,7 @@ export class ProjectHelper {
146
146
  public getEnrichmentTargets(
147
147
  blockConfig: () => BlockConfig,
148
148
  args: () => unknown,
149
- key?: { argsRid: ResourceId; blockPackRid: ResourceId },
149
+ key?: { argsRid: SignedResourceId; blockPackRid: SignedResourceId },
150
150
  ): PlRef[] | undefined {
151
151
  const req = { blockConfig, args };
152
152
  if (key === undefined) return this.calculateEnrichmentTargets(req);
@@ -1,13 +1,16 @@
1
- import type { ResourceId, ResourceType } from "@milaboratories/pl-client";
1
+ import type { ResourceType } from "@milaboratories/pl-client";
2
+ import type { ProjectId } from "@milaboratories/pl-model-common";
2
3
  import type {
3
4
  ProjectListEntry as ProjectListEntryFromModel,
4
5
  ProjectMeta,
5
6
  } from "@milaboratories/pl-model-middle-layer";
6
7
  import type { BlockRenderingMode } from "@platforma-sdk/model";
7
8
 
8
- export interface ProjectListEntry extends ProjectListEntryFromModel {
9
- /** Project resource ID. */
10
- rid: ResourceId;
9
+ export type { ProjectId };
10
+
11
+ export interface ProjectListEntry extends Omit<ProjectListEntryFromModel, "id"> {
12
+ /** Unique project identifier in middle layer. Use to operate with given project. */
13
+ id: ProjectId;
11
14
  }
12
15
 
13
16
  /** Entry representing a single block in block structure */
@@ -1,4 +1,4 @@
1
- import type { ResourceId } from "@milaboratories/pl-client";
1
+ import type { SignedResourceId } from "@milaboratories/pl-client";
2
2
  import type { CompiledTemplateV3, TemplateData } from "@milaboratories/pl-model-backend";
3
3
 
4
4
  export interface TemplateFromRegistry {
@@ -19,7 +19,7 @@ export interface PreparedTemplate {
19
19
 
20
20
  export interface CachedTemplate {
21
21
  readonly type: "cached";
22
- readonly resourceId: ResourceId;
22
+ readonly resourceId: SignedResourceId;
23
23
  }
24
24
 
25
25
  export interface TemplateFromFile {
@@ -1,4 +1,9 @@
1
- import { isNullResourceId, poll, TestHelpers, toGlobalResourceId } from "@milaboratories/pl-client";
1
+ import {
2
+ isNullSignedResourceId,
3
+ poll,
4
+ TestHelpers,
5
+ toGlobalResourceId,
6
+ } from "@milaboratories/pl-client";
2
7
  import { defaultHttpDispatcher } from "@milaboratories/pl-http";
3
8
  import { HmacSha256Signer } from "@milaboratories/ts-helpers";
4
9
  import path from "node:path";
@@ -50,7 +55,7 @@ test.each([
50
55
 
51
56
  await poll(pl, async (a) => {
52
57
  const r = await a.get(bp).then((r) => r.final()); // this will await final state
53
- expect(isNullResourceId(r.data.error)).toBe(true);
58
+ expect(isNullSignedResourceId(r.data.error)).toBe(true);
54
59
  });
55
60
  });
56
61
  });
@@ -1,5 +1,5 @@
1
1
  import { UiError } from "@milaboratories/pl-model-common";
2
- import type { PlClient, PlTransaction, ResourceId } from "@milaboratories/pl-client";
2
+ import type { PlClient, PlTransaction, SignedResourceId } from "@milaboratories/pl-client";
3
3
  import type { ProjectField, ProjectStructure } from "../model/project_model";
4
4
  import {
5
5
  projectFieldName,
@@ -10,7 +10,7 @@ import {
10
10
  SchemaVersionV3,
11
11
  } from "../model/project_model";
12
12
  import { BlockFrontendStateKeyPrefixV1, SchemaVersionV1 } from "../model/project_model_v1";
13
- import { field, isNullResourceId } from "@milaboratories/pl-client";
13
+ import { field, isNullSignedResourceId } from "@milaboratories/pl-client";
14
14
  import { cachedDeserialize } from "@milaboratories/ts-helpers";
15
15
  import { allBlocks } from "../model/project_model_util";
16
16
 
@@ -20,7 +20,7 @@ import { allBlocks } from "../model/project_model_util";
20
20
  * @param pl - The client to use.
21
21
  * @param rid - The resource id of the project.
22
22
  */
23
- export async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {
23
+ export async function applyProjectMigrations(pl: PlClient, rid: SignedResourceId) {
24
24
  await pl.withWriteTx("ProjectMigration", async (tx) => {
25
25
  let schemaVersion = await tx.getKValueJson<string>(rid, SchemaVersionKey);
26
26
  if (schemaVersion === SchemaVersionCurrent) return;
@@ -64,7 +64,7 @@ export async function applyProjectMigrations(pl: PlClient, rid: ResourceId) {
64
64
  * @param tx - The transaction to use.
65
65
  * @param rid - The resource id of the project.
66
66
  */
67
- async function migrateV1ToV2(tx: PlTransaction, rid: ResourceId) {
67
+ async function migrateV1ToV2(tx: PlTransaction, rid: SignedResourceId) {
68
68
  const [structure, allKV] = await Promise.all([
69
69
  tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),
70
70
  tx.listKeyValues(rid),
@@ -98,16 +98,16 @@ async function migrateV1ToV2(tx: PlTransaction, rid: ResourceId) {
98
98
  * @param tx - The transaction to use.
99
99
  * @param rid - The resource id of the project.
100
100
  */
101
- async function migrateV2ToV3(tx: PlTransaction, rid: ResourceId) {
101
+ async function migrateV2ToV3(tx: PlTransaction, rid: SignedResourceId) {
102
102
  const [structure, fullResourceState] = await Promise.all([
103
103
  tx.getKValueJson<ProjectStructure>(rid, ProjectStructureKey),
104
104
  tx.getResourceData(rid, true),
105
105
  ]);
106
106
 
107
107
  // Build a map of field name -> resource id for quick lookup
108
- const fieldMap = new Map<string, ResourceId>();
108
+ const fieldMap = new Map<string, SignedResourceId>();
109
109
  for (const f of fullResourceState.fields) {
110
- if (!isNullResourceId(f.value)) {
110
+ if (!isNullSignedResourceId(f.value)) {
111
111
  fieldMap.set(f.name, f.value);
112
112
  }
113
113
  }
@@ -2,16 +2,17 @@ import type {
2
2
  AnyRef,
3
3
  AnyResourceRef,
4
4
  BasicResourceData,
5
+ ResourceRef,
5
6
  PlTransaction,
6
7
  ResourceData,
7
- ResourceId,
8
+ SignedResourceId,
8
9
  TxOps,
9
10
  } from "@milaboratories/pl-client";
10
11
  import {
11
- ensureResourceIdNotNull,
12
+ ensureSignedResourceIdNotNull,
12
13
  field,
13
- isNotNullResourceId,
14
- isNullResourceId,
14
+ isNotNullSignedResourceId,
15
+ isNullSignedResourceId,
15
16
  isResource,
16
17
  isResourceId,
17
18
  isResourceRef,
@@ -341,7 +342,7 @@ export class ProjectMutator {
341
342
  private readonly blocksWithChangedInputs = new Set<string>();
342
343
 
343
344
  constructor(
344
- public readonly rid: ResourceId,
345
+ public readonly rid: SignedResourceId,
345
346
  private readonly tx: PlTransaction,
346
347
  private readonly author: AuthorMarker | undefined,
347
348
  private readonly schema: string,
@@ -359,7 +360,7 @@ export class ProjectMutator {
359
360
  // Fix inconsistent production fields.
360
361
  // All four fields (prodArgs, prodOutput, prodCtx, prodUiCtx) must be present together.
361
362
  // prodUiCtx can be missing after project duplication: prodCtx uses a holder wrapper
362
- // (always non-null), but prodUiCtx is a raw FieldRef that may still be NullResourceId
363
+ // (always non-null), but prodUiCtx is a raw FieldRef that may still be NullSignedResourceId
363
364
  // at snapshot time and thus not copied.
364
365
  this.blockInfos.forEach((blockInfo) => {
365
366
  if (
@@ -1716,7 +1717,7 @@ export class ProjectMutator {
1716
1717
  public static async load(
1717
1718
  projectHelper: ProjectHelper,
1718
1719
  tx: PlTransaction,
1719
- rid: ResourceId,
1720
+ rid: SignedResourceId,
1720
1721
  author?: AuthorMarker,
1721
1722
  ): Promise<ProjectMutator> {
1722
1723
  //
@@ -1749,7 +1750,7 @@ export class ProjectMutator {
1749
1750
  blockInfoStates.set(projectField.blockId, info);
1750
1751
  }
1751
1752
 
1752
- info.fields[projectField.fieldName] = isNullResourceId(f.value)
1753
+ info.fields[projectField.fieldName] = isNullSignedResourceId(f.value)
1753
1754
  ? { modCount: 0 }
1754
1755
  : { modCount: 0, ref: f.value };
1755
1756
  }
@@ -1811,8 +1812,8 @@ export class ProjectMutator {
1811
1812
  for (const [info, fieldName, state, response] of blockFieldRequests) {
1812
1813
  const result = await response;
1813
1814
  state.value = result.data;
1814
- if (isNotNullResourceId(result.error)) state.status = "Error";
1815
- else if (result.resourceReady || isNotNullResourceId(result.originalResourceId))
1815
+ if (isNotNullSignedResourceId(result.error)) state.status = "Error";
1816
+ else if (result.resourceReady || isNotNullSignedResourceId(result.originalResourceId))
1816
1817
  state.status = "Ready";
1817
1818
  else state.status = "NotReady";
1818
1819
 
@@ -1822,7 +1823,7 @@ export class ProjectMutator {
1822
1823
  if (refField === undefined) throw new Error("Block pack ref field is missing");
1823
1824
  blockPackRequests.push([
1824
1825
  info,
1825
- tx.getResourceData(ensureResourceIdNotNull(refField.value), false),
1826
+ tx.getResourceData(ensureSignedResourceIdNotNull(refField.value), false),
1826
1827
  ]);
1827
1828
  }
1828
1829
  }
@@ -1852,7 +1853,7 @@ export class ProjectMutator {
1852
1853
  );
1853
1854
  let ctxExportTplHolder: AnyResourceRef;
1854
1855
  if (ctxExportTplField !== undefined)
1855
- ctxExportTplHolder = ensureResourceIdNotNull(ctxExportTplField.value);
1856
+ ctxExportTplHolder = ensureSignedResourceIdNotNull(ctxExportTplField.value);
1856
1857
  else {
1857
1858
  ctxExportTplHolder = Pl.wrapInHolder(tx, loadTemplate(tx, ctxExportTplEnvelope.spec));
1858
1859
  tx.createField(
@@ -1917,7 +1918,7 @@ export interface ProjectState {
1917
1918
  export async function createProject(
1918
1919
  tx: PlTransaction,
1919
1920
  meta: ProjectMeta = InitialBlockMeta,
1920
- ): Promise<AnyResourceRef> {
1921
+ ): Promise<ResourceRef> {
1921
1922
  const prj = tx.createEphemeral(ProjectResourceType);
1922
1923
  tx.lock(prj);
1923
1924
  const ts = String(Date.now());
@@ -1950,9 +1951,9 @@ export async function createProject(
1950
1951
  */
1951
1952
  export async function duplicateProject(
1952
1953
  tx: PlTransaction,
1953
- sourceRid: ResourceId,
1954
+ sourceRid: SignedResourceId,
1954
1955
  options?: { label?: string },
1955
- ): Promise<AnyResourceRef> {
1956
+ ): Promise<ResourceRef> {
1956
1957
  // Read source resource data (with fields) and all KV pairs
1957
1958
  const sourceDataP = tx.getResourceData(sourceRid, true);
1958
1959
  const sourceKVsP = tx.listKeyValuesString(sourceRid);
@@ -2006,10 +2007,10 @@ export async function duplicateProject(
2006
2007
  // Copy only persistent block fields (FieldsToDuplicate).
2007
2008
  // Transient fields (prodChainCtx, staging*, *Previous) are rebuilt on project open
2008
2009
  // by fixProblemsAndMigrate(). Copying them is both unnecessary and dangerous:
2009
- // some fields use raw FieldRefs (not holder-wrapped) whose values may be NullResourceId
2010
+ // some fields use raw FieldRefs (not holder-wrapped) whose values may be NullSignedResourceId
2010
2011
  // at snapshot time, leading to partially copied field groups and broken project state.
2011
2012
  for (const f of sourceData.fields) {
2012
- if (isNullResourceId(f.value)) continue;
2013
+ if (isNullSignedResourceId(f.value)) continue;
2013
2014
  const parsed = parseProjectField(f.name);
2014
2015
  if (parsed !== undefined && !FieldsToDuplicate.has(parsed.fieldName)) continue;
2015
2016
  tx.createField(field(newPrj, f.name), "Dynamic", f.value);
@@ -2021,7 +2022,7 @@ export async function duplicateProject(
2021
2022
  export async function withProject<T>(
2022
2023
  projectHelper: ProjectHelper,
2023
2024
  txOrPl: PlTransaction | PlClient,
2024
- rid: ResourceId,
2025
+ rid: SignedResourceId,
2025
2026
  cb: (p: ProjectMutator) => T | Promise<T>,
2026
2027
  ops?: Partial<TxOps>,
2027
2028
  ): Promise<T> {
@@ -2031,7 +2032,7 @@ export async function withProject<T>(
2031
2032
  export async function withProjectAuthored<T>(
2032
2033
  projectHelper: ProjectHelper,
2033
2034
  txOrPl: PlTransaction | PlClient,
2034
- rid: ResourceId,
2035
+ rid: SignedResourceId,
2035
2036
  author: AuthorMarker | undefined,
2036
2037
  cb: (p: ProjectMutator) => T | Promise<T>,
2037
2038
  ops: Partial<TxOps> = {},
@@ -1,7 +1,7 @@
1
1
  import {
2
- ensureResourceIdNotNull,
2
+ ensureSignedResourceIdNotNull,
3
3
  field,
4
- isNotNullResourceId,
4
+ isNotNullSignedResourceId,
5
5
  poll,
6
6
  TestHelpers,
7
7
  toGlobalResourceId,
@@ -103,7 +103,7 @@ describe("dropTemplateCache", () => {
103
103
  // ─── loadTemplateCached ──────────────────────────────────────────────────────
104
104
 
105
105
  describe("loadTemplateCached", () => {
106
- test("cache miss then cache hit returns same ResourceId", async () => {
106
+ test("cache miss then cache hit returns same SignedResourceId", async () => {
107
107
  await TestHelpers.withTempRoot(async (pl) => {
108
108
  const testCache = await createTestCacheInTx(pl);
109
109
 
@@ -151,7 +151,7 @@ describe("loadTemplateCached", () => {
151
151
  // Verify the field was set correctly
152
152
  await pl.withReadTx("verify", async (tx) => {
153
153
  const fd = await tx.getField(field(pl.clientRoot, "test_result"));
154
- expect(ensureResourceIdNotNull(fd.value)).toBe(resultId);
154
+ expect(ensureSignedResourceIdNotNull(fd.value)).toBe(resultId);
155
155
  });
156
156
  });
157
157
  }, 15000);
@@ -265,8 +265,8 @@ describe("template cache produces equivalent resources", () => {
265
265
 
266
266
  // After dedup, both should resolve to the same canonical resource.
267
267
  // Either one points to the other, or both point to a common original.
268
- const resolvedCached = isNotNullResourceId(cachedOriginal) ? cachedOriginal : cachedId;
269
- const resolvedLegacy = isNotNullResourceId(legacyOriginal) ? legacyOriginal : legacyId;
268
+ const resolvedCached = isNotNullSignedResourceId(cachedOriginal) ? cachedOriginal : cachedId;
269
+ const resolvedLegacy = isNotNullSignedResourceId(legacyOriginal) ? legacyOriginal : legacyId;
270
270
  expect(resolvedCached).toBe(resolvedLegacy);
271
271
  });
272
272
  }, 30000);
@@ -3,11 +3,11 @@ import type {
3
3
  AnyResourceRef,
4
4
  PlClient,
5
5
  PlTransaction,
6
- ResourceId,
6
+ SignedResourceId,
7
7
  ResourceRef,
8
8
  } from "@milaboratories/pl-client";
9
9
  import {
10
- ensureResourceIdNotNull,
10
+ ensureSignedResourceIdNotNull,
11
11
  field,
12
12
  resourceType,
13
13
  toGlobalResourceId,
@@ -86,7 +86,7 @@ interface CacheableNode {
86
86
  /** SHA-256 content hash (includes all descendant content) */
87
87
  hash: string;
88
88
  /** Creates this node's resource in a transaction.
89
- * childRefs maps child hash → already-resolved ResourceRef or ResourceId */
89
+ * childRefs maps child hash → already-resolved ResourceRef or SignedResourceId */
90
90
  create: (tx: PlTransaction, childRefs: ReadonlyMap<string, AnyResourceRef>) => ResourceRef;
91
91
  /** Hashes of direct child nodes this node depends on */
92
92
  childHashes: string[];
@@ -406,8 +406,8 @@ export function flattenTemplateTree(data: TemplateData | CompiledTemplateV3): Ca
406
406
 
407
407
  // ─── Cache operations ────────────────────────────────────────────────────────
408
408
 
409
- /** In-memory cache for the TemplateCache ResourceId per PlClient instance. */
410
- const cacheRidMap = new WeakMap<PlClient, ResourceId>();
409
+ /** In-memory cache for the TemplateCache SignedResourceId per PlClient instance. */
410
+ const cacheRidMap = new WeakMap<PlClient, SignedResourceId>();
411
411
 
412
412
  /** Clear the in-memory cacheRid entry (call on errors referencing the cache resource). */
413
413
  export function invalidateTemplateCacheId(pl: PlClient): void {
@@ -415,7 +415,7 @@ export function invalidateTemplateCacheId(pl: PlClient): void {
415
415
  }
416
416
 
417
417
  /** Find or create the TemplateCache/1 resource on user root. */
418
- export async function getOrCreateTemplateCache(pl: PlClient): Promise<ResourceId> {
418
+ export async function getOrCreateTemplateCache(pl: PlClient): Promise<SignedResourceId> {
419
419
  // Check in-memory cache first (0ms after first call)
420
420
  const cached = cacheRidMap.get(pl);
421
421
  if (cached !== undefined) return cached;
@@ -423,7 +423,7 @@ export async function getOrCreateTemplateCache(pl: PlClient): Promise<ResourceId
423
423
  // Try read-only check
424
424
  const existing = await pl.withReadTx("templateCache:check", async (tx) => {
425
425
  const fd = await tx.getFieldIfExists(field(pl.clientRoot, TemplateCacheFieldName));
426
- return fd ? ensureResourceIdNotNull(fd.value) : undefined;
426
+ return fd ? ensureSignedResourceIdNotNull(fd.value) : undefined;
427
427
  });
428
428
  if (existing) {
429
429
  cacheRidMap.set(pl, existing);
@@ -433,7 +433,7 @@ export async function getOrCreateTemplateCache(pl: PlClient): Promise<ResourceId
433
433
  const result = await pl.withWriteTx("templateCache:init", async (tx) => {
434
434
  // Double-check inside write tx (another instance may have created it)
435
435
  const fd = await tx.getFieldIfExists(field(pl.clientRoot, TemplateCacheFieldName));
436
- if (fd) return ensureResourceIdNotNull(fd.value);
436
+ if (fd) return ensureSignedResourceIdNotNull(fd.value);
437
437
 
438
438
  const cache = tx.createStruct(TemplateCacheType);
439
439
  tx.createField(field(pl.clientRoot, TemplateCacheFieldName), "Dynamic", cache);
@@ -470,7 +470,7 @@ export async function dropTemplateCache(pl: PlClient): Promise<void> {
470
470
  */
471
471
  export async function runGc(
472
472
  pl: PlClient,
473
- cacheRid: ResourceId,
473
+ cacheRid: SignedResourceId,
474
474
  maxEntries: number = GC_MAX_ENTRIES,
475
475
  ): Promise<boolean> {
476
476
  return await pl.withWriteTx("templateCache:gc", async (tx) => {
@@ -510,9 +510,9 @@ export async function runGc(
510
510
  /** Create a batch of cache nodes in the current transaction. */
511
511
  function createBatchNodes(
512
512
  tx: PlTransaction,
513
- cacheRid: ResourceId,
513
+ cacheRid: SignedResourceId,
514
514
  batch: CacheableNode[],
515
- resolvedIds: ReadonlyMap<string, ResourceId>,
515
+ resolvedIds: ReadonlyMap<string, SignedResourceId>,
516
516
  newRefs: Map<string, ResourceRef>,
517
517
  now: string,
518
518
  ): void {
@@ -543,17 +543,17 @@ function createBatchNodes(
543
543
  * Phase 2..N (one write tx per batch):
544
544
  * - Create remaining missing nodes in BATCH_SIZE chunks
545
545
  *
546
- * @returns root ResourceId and current access count (for GC decision)
546
+ * @returns root SignedResourceId and current access count (for GC decision)
547
547
  */
548
548
  async function materialize(
549
549
  pl: PlClient,
550
- cacheRid: ResourceId,
550
+ cacheRid: SignedResourceId,
551
551
  rootHash: string,
552
552
  nodes: CacheableNode[],
553
553
  stat: TemplateCacheStat,
554
- ): Promise<{ rootId: ResourceId; accessCount: number }> {
554
+ ): Promise<{ rootId: SignedResourceId; accessCount: number }> {
555
555
  const allHashes = nodes.map((n) => n.hash);
556
- const resolvedIds = new Map<string, ResourceId>();
556
+ const resolvedIds = new Map<string, SignedResourceId>();
557
557
 
558
558
  // Phase 1: probe all + first batch
559
559
  const phase1 = await pl.withWriteTx("templateCache:materialize", async (tx) => {
@@ -571,7 +571,7 @@ async function materialize(
571
571
  // Happy path: root already cached
572
572
  if (exists[rootIdx]) {
573
573
  const rootFd = await tx.getField(field(cacheRid, rootHash));
574
- const rootRid = ensureResourceIdNotNull(rootFd.value);
574
+ const rootRid = ensureSignedResourceIdNotNull(rootFd.value);
575
575
  tx.setKValue(cacheRid, ACCESS_KEY_PREFIX + rootHash, now);
576
576
  tx.setKValue(cacheRid, ACCESS_COUNT_KEY, newCount.toString());
577
577
  await tx.commit();
@@ -592,7 +592,10 @@ async function materialize(
592
592
  hitIndices.map((i) => tx.getField(field(cacheRid, allHashes[i]))),
593
593
  );
594
594
  for (let j = 0; j < hitIndices.length; j++) {
595
- resolvedIds.set(allHashes[hitIndices[j]], ensureResourceIdNotNull(hitFields[j].value));
595
+ resolvedIds.set(
596
+ allHashes[hitIndices[j]],
597
+ ensureSignedResourceIdNotNull(hitFields[j].value),
598
+ );
596
599
  }
597
600
  }
598
601
  stat.cacheHits = hitIndices.length;
@@ -659,13 +662,13 @@ async function materialize(
659
662
  * Materialize a template tree via the cache.
660
663
  * Manages its own transactions internally — do NOT call inside an existing tx.
661
664
  *
662
- * @returns concrete ResourceId of the root template
665
+ * @returns concrete SignedResourceId of the root template
663
666
  */
664
667
  export async function loadTemplateCached(
665
668
  pl: PlClient,
666
669
  spec: TemplateSpecPrepared,
667
- options?: { cacheResourceId?: ResourceId },
668
- ): Promise<ResourceId> {
670
+ options?: { cacheResourceId?: SignedResourceId },
671
+ ): Promise<SignedResourceId> {
669
672
  const stat = initialStat();
670
673
  const t0 = performance.now();
671
674
 
@@ -751,7 +754,7 @@ export async function loadTemplateCached(
751
754
  export async function cacheBlockPackTemplate(
752
755
  pl: PlClient,
753
756
  spec: BlockPackSpecPrepared,
754
- options?: { cacheResourceId?: ResourceId },
757
+ options?: { cacheResourceId?: SignedResourceId },
755
758
  ): Promise<BlockPackSpecPrepared> {
756
759
  if (spec.template.type === "cached") return spec;
757
760
 
@@ -3,13 +3,13 @@ import {
3
3
  AnyResourceRef,
4
4
  field,
5
5
  getField,
6
- isNotNullResourceId,
7
- isNullResourceId,
6
+ isNotNullSignedResourceId,
7
+ isNullSignedResourceId,
8
8
  Pl,
9
9
  PlClient,
10
10
  PlTransaction,
11
11
  ResourceData,
12
- ResourceId,
12
+ SignedResourceId,
13
13
  TestHelpers,
14
14
  valErr,
15
15
  } from "@milaboratories/pl-client";
@@ -235,7 +235,7 @@ async function expectResultAndContext(
235
235
  ok: boolean;
236
236
  }> {
237
237
  const fieldData = await tx.getResourceData(root, true);
238
- expect(isNullResourceId(fieldData.error)).toBe(true);
238
+ expect(isNullSignedResourceId(fieldData.error)).toBe(true);
239
239
  expectFields(fieldData, ["context", "result"]);
240
240
 
241
241
  const ctxField = await valErr(tx, getField(fieldData, "context"));
@@ -246,7 +246,7 @@ async function expectResultAndContext(
246
246
  const ctxId = ctxField.valueId;
247
247
  const resultId = resultField.valueId;
248
248
 
249
- if (isNullResourceId(ctxId) || isNullResourceId(resultId)) return { ok: false };
249
+ if (isNullSignedResourceId(ctxId) || isNullSignedResourceId(resultId)) return { ok: false };
250
250
 
251
251
  const result = await tx.getResourceData(resultId, true);
252
252
  const ctx = await tx.getResourceData(ctxId, true);
@@ -260,8 +260,8 @@ async function expectResource(tx: PlTransaction, res: ResourceData, fieldName: s
260
260
  const f = getField(res, fieldName);
261
261
  const ve = await valErr(tx, f);
262
262
  expect(ve.error).toHaveLength(0);
263
- expect(isNotNullResourceId(ve.valueId)).toBeTruthy();
264
- return await tx.getResourceData(ve.valueId as ResourceId, true);
263
+ expect(isNotNullSignedResourceId(ve.valueId)).toBeTruthy();
264
+ return await tx.getResourceData(ve.valueId as SignedResourceId, true);
265
265
  }
266
266
 
267
267
  async function expectData(tx: PlTransaction, result: ResourceData, fieldName: string) {