@milaboratories/pl-middle-layer 1.48.28 → 1.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/middle_layer/middle_layer.cjs +22 -0
- package/dist/middle_layer/middle_layer.cjs.map +1 -1
- package/dist/middle_layer/middle_layer.d.ts +9 -0
- package/dist/middle_layer/middle_layer.js +24 -2
- package/dist/middle_layer/middle_layer.js.map +1 -1
- package/dist/model/project_model.cjs +1 -0
- package/dist/model/project_model.js +1 -1
- package/dist/mutator/project.cjs +46 -0
- package/dist/mutator/project.cjs.map +1 -1
- package/dist/mutator/project.js +47 -2
- package/dist/mutator/project.js.map +1 -1
- package/package.json +8 -8
- package/src/middle_layer/middle_layer.ts +49 -2
- package/src/mutator/project.ts +78 -0
package/src/mutator/project.ts
CHANGED
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
ProjectMetaKey,
|
|
39
39
|
InitialBlockMeta,
|
|
40
40
|
blockArgsAuthorKey,
|
|
41
|
+
BlockArgsAuthorKeyPrefix,
|
|
41
42
|
ProjectLastModifiedTimestamp,
|
|
42
43
|
ProjectCreatedTimestamp,
|
|
43
44
|
ProjectStructureAuthorKey,
|
|
@@ -1822,6 +1823,83 @@ export async function createProject(
|
|
|
1822
1823
|
return prj;
|
|
1823
1824
|
}
|
|
1824
1825
|
|
|
1826
|
+
/**
|
|
1827
|
+
* Duplicates an existing project resource within a transaction.
|
|
1828
|
+
* Creates a new project resource with all dynamic fields (block data) copied by reference
|
|
1829
|
+
* and all KV metadata copied with appropriate adjustments.
|
|
1830
|
+
*
|
|
1831
|
+
* The returned resource is NOT attached to any project list — the caller is responsible
|
|
1832
|
+
* for placing it where needed. This enables cross-user duplication.
|
|
1833
|
+
*
|
|
1834
|
+
* @param tx - active write transaction
|
|
1835
|
+
* @param sourceRid - resource id of the project to duplicate
|
|
1836
|
+
* @param options.label - optional label override for the new project; if omitted, copies the source label
|
|
1837
|
+
*/
|
|
1838
|
+
export async function duplicateProject(
|
|
1839
|
+
tx: PlTransaction,
|
|
1840
|
+
sourceRid: ResourceId,
|
|
1841
|
+
options?: { label?: string },
|
|
1842
|
+
): Promise<AnyResourceRef> {
|
|
1843
|
+
// Read source resource data (with fields) and all KV pairs
|
|
1844
|
+
const sourceDataP = tx.getResourceData(sourceRid, true);
|
|
1845
|
+
const sourceKVsP = tx.listKeyValuesString(sourceRid);
|
|
1846
|
+
|
|
1847
|
+
const sourceData = await sourceDataP;
|
|
1848
|
+
const sourceKVs = await sourceKVsP;
|
|
1849
|
+
|
|
1850
|
+
// Validate schema version
|
|
1851
|
+
const schemaKV = sourceKVs.find((kv) => kv.key === SchemaVersionKey);
|
|
1852
|
+
const schema = schemaKV ? JSON.parse(schemaKV.value) : undefined;
|
|
1853
|
+
if (schema !== SchemaVersionCurrent) {
|
|
1854
|
+
throw new UiError(
|
|
1855
|
+
`Cannot duplicate project with schema version ${schema ?? "unknown"}. ` +
|
|
1856
|
+
`Only schema version ${SchemaVersionCurrent} is supported. ` +
|
|
1857
|
+
`Try opening the project first to trigger migration.`,
|
|
1858
|
+
);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
// Create new project resource
|
|
1862
|
+
const newPrj = tx.createEphemeral(ProjectResourceType);
|
|
1863
|
+
tx.lock(newPrj);
|
|
1864
|
+
|
|
1865
|
+
// Copy KV pairs with adjustments
|
|
1866
|
+
const ts = String(Date.now());
|
|
1867
|
+
const kvSkipPrefixes = [BlockArgsAuthorKeyPrefix];
|
|
1868
|
+
const kvSkipKeys = new Set([
|
|
1869
|
+
ProjectCreatedTimestamp,
|
|
1870
|
+
ProjectLastModifiedTimestamp,
|
|
1871
|
+
ProjectStructureAuthorKey,
|
|
1872
|
+
]);
|
|
1873
|
+
|
|
1874
|
+
for (const { key, value } of sourceKVs) {
|
|
1875
|
+
// Skip author markers
|
|
1876
|
+
if (kvSkipKeys.has(key)) continue;
|
|
1877
|
+
if (kvSkipPrefixes.some((prefix) => key.startsWith(prefix))) continue;
|
|
1878
|
+
|
|
1879
|
+
if (key === ProjectMetaKey && options?.label !== undefined) {
|
|
1880
|
+
// Override label
|
|
1881
|
+
const meta: ProjectMeta = JSON.parse(value);
|
|
1882
|
+
tx.setKValue(newPrj, key, JSON.stringify({ ...meta, label: options.label }));
|
|
1883
|
+
} else {
|
|
1884
|
+
// Copy as-is
|
|
1885
|
+
tx.setKValue(newPrj, key, value);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
// Set fresh timestamps
|
|
1890
|
+
tx.setKValue(newPrj, ProjectCreatedTimestamp, ts);
|
|
1891
|
+
tx.setKValue(newPrj, ProjectLastModifiedTimestamp, ts);
|
|
1892
|
+
|
|
1893
|
+
// Copy all dynamic fields by sharing references
|
|
1894
|
+
for (const f of sourceData.fields) {
|
|
1895
|
+
if (isNotNullResourceId(f.value)) {
|
|
1896
|
+
tx.createField(field(newPrj, f.name), "Dynamic", f.value);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
return newPrj;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1825
1903
|
export async function withProject<T>(
|
|
1826
1904
|
projectHelper: ProjectHelper,
|
|
1827
1905
|
txOrPl: PlTransaction | PlClient,
|